先上效果圖 灑豆子的效果,突發奇想,覺得這個動畫挺有意思的,就抽空寫了一個玩玩 繪製流程: 定義6個‘’豆子‘’,每個豆子有各自的屬性,大小,拋出的速度等,然後控制每個的方向和狀態,回彈效果使用差值器 BounceInterpolator package com.fragmentapp.view.b ...
先上效果圖
灑豆子的效果,突發奇想,覺得這個動畫挺有意思的,就抽空寫了一個玩玩
繪製流程:
定義6個‘’豆子‘’,每個豆子有各自的屬性,大小,拋出的速度等,然後控制每個的方向和狀態,回彈效果使用差值器 BounceInterpolator
package com.fragmentapp.view.beans; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.animation.BounceInterpolator; import com.fragmentapp.R; import com.fragmentapp.helper.RandomUtil; /** * Created by liuzhen on 2017/1/17. */ public class BeansView extends View { private Paint paint; private int mWidth; private int mHeight; private int top; private ValueAnimator va; private Beans beans1,beans2,beans3,beans4,beans5,beans6; public BeansView(Context context) { this(context, null); } public BeansView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BeansView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { Log.e("tag","init"); setWillNotDraw(false); paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); paint.setColor(getResources().getColor(R.color.color_ff9c19)); //隨機生成球體的大小、 beans1 = new Beans(RandomUtil.random(5,15)); beans2 = new Beans(RandomUtil.random(5,15)); beans3 = new Beans(RandomUtil.random(5,15)); beans4 = new Beans(RandomUtil.random(5,15)); beans5 = new Beans(RandomUtil.random(5,15)); beans6 = new Beans(RandomUtil.random(5,15)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { mWidth = getWidth(); mHeight = getHeight(); this.top = top; startAnim(); } } @Override protected void onDraw(Canvas canvas) { //正常向右掉落,這裡也可以利用隨機生成方向,這裡就固定左邊三個右邊三個 canvas.drawCircle(beans1.getCx(), beans1.getCy(), beans1.getRadius(), paint); canvas.drawCircle(beans2.getCx(), beans2.getCy(), beans2.getRadius(), paint); canvas.drawCircle(beans3.getCx(), beans3.getCy(), beans3.getRadius(), paint); //讓球往左邊掉落 canvas.drawCircle(-beans4.getCx()+mWidth, beans4.getCy(), beans4.getRadius(), paint); canvas.drawCircle(-beans5.getCx()+mWidth, beans5.getCy(), beans5.getRadius(), paint); canvas.drawCircle(-beans6.getCx()+mWidth, beans6.getCy(), beans6.getRadius(), paint); } public void startAnim() { if (mWidth == 0) return; beans1.setState(0); beans1.setOff(0); beans1.setRand(RandomUtil.random(20));//隨機生成拋出的速度值 beans2.setState(0); beans2.setOff(0); beans2.setRand(RandomUtil.random(20)); beans3.setState(0); beans3.setOff(0); beans3.setRand(RandomUtil.random(20)); beans4.setState(0); beans4.setOff(0); beans4.setRand(RandomUtil.random(20)); beans5.setState(0); beans5.setOff(0); beans5.setRand(RandomUtil.random(20)); beans6.setState(0); beans6.setOff(0); beans6.setRand(RandomUtil.random(20)); va = ValueAnimator.ofFloat(top, mHeight - top); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float val = (float)animation.getAnimatedValue(); beans1.setCy(val); beans1.move(mWidth);//先移動坐標,實際上是改變了off偏移量的值 beans1.setCx(mWidth / 2 + beans1.getOff());//刷新X軸坐標 beans2.setCy(val); beans2.move(mWidth); beans2.setCx(mWidth / 2 + beans2.getOff()); beans3.setCy(val); beans3.move(mWidth); beans3.setCx(mWidth / 2 + beans3.getOff()); beans4.setCy(val); beans4.move(mWidth); beans4.setCx(mWidth / 2 + beans4.getOff()); beans5.setCy(val); beans5.move(mWidth); beans5.setCx(mWidth / 2 + beans5.getOff()); beans6.setCy(val); beans6.move(mWidth); beans6.setCx(mWidth / 2 + beans6.getOff()); invalidate(); } }); va.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { //防止停止後球體因為半徑的不一樣而降落到地面的水平不一樣,統一水平線 beans1.setCy(mHeight - beans1.getRadius()); beans2.setCy(mHeight - beans2.getRadius()); beans3.setCy(mHeight - beans3.getRadius()); beans4.setCy(mHeight - beans4.getRadius()); beans5.setCy(mHeight - beans5.getRadius()); beans6.setCy(mHeight - beans6.getRadius()); invalidate(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); va.setInterpolator(new BounceInterpolator());//重力差值器 va.setDuration(3000); va.setRepeatMode(ValueAnimator.RESTART); va.start(); } public void stopAnim() { va.cancel(); va = null; } }View Code
這裡主要把邏輯封裝到單獨的對象裡面去了,所以view類看起來很清爽
下麵是豆子類
package com.fragmentapp.view.beans; import android.util.Log; /** * Created by liuzhen on 2018/1/18. */ public class Beans { public Beans(){ } public Beans(int radius){ this.radius = radius; } /**X坐標*/ private float cx; /**Y坐標*/ private float cy; /**偏移量*/ private float off; /**隨機生成的速度值*/ private float rand; /**是否碰到邊緣*/ private int state; /**圓球的大小*/ private float radius; /**移動 X 坐標,並且碰到邊界後回彈*/ public void move(int width){ if (cx < 0 || state == 1) {//碰到左邊的邊緣 state = 1; off += rand; } else if (cx >= width || state == 2) {//碰到右邊的邊緣 state = 2; off -= rand; }else if(state == 0) { state = 0; off += rand; } // Log.e("tag","-- cx "+(int)cx + " width "+width + " state "+state); } public float getCx() { return cx; } public void setCx(float cx) { this.cx = cx; } public float getOff() { return off; } public void setOff(float off) { this.off = off; } public float getRand() { return rand; } public void setRand(float rand) { this.rand = rand; } public int getState() { return state; } public void setState(int state) { this.state = state; } public float getCy() { return cy; } public void setCy(float cy) { this.cy = cy; } public float getRadius() { return radius; } public void setRadius(float radius) { this.radius = radius; } }View Code
主要邏輯集中在move方法中
預設是正常拋出,然後碰到邊緣後改變狀態往回彈
使用上只關註兩個方法就行了
這裡是把控制項放在了一個dialog裡面,這個看個人喜歡,顯然dialog不是很適合,或者可以加到下拉庫的頭部上去,效果應該不錯
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/shape_dialog_bg" android:padding="@dimen/d20.0" android:orientation="vertical" android:id="@+id/root"> <com.fragmentapp.view.beans.BeansView android:id="@+id/beans" android:layout_width="@dimen/d350.0" android:layout_height="@dimen/d300.0" android:layout_gravity="center_horizontal" /> <!--<View--> <!--android:layout_width="match_parent"--> <!--android:layout_height="@dimen/d1.0"--> <!--android:background="@color/white"/>--> <TextView android:id="@+id/tv_val" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="@dimen/d20.0" android:text="載入中..." android:textColor="@color/color_cccccc" android:textSize="@dimen/d43.0" /> </LinearLayout>View Code
GitHub:https://github.com/1024477951/FragmentApp