自定義View實現雨點灑落效果

自定義View實現雨點灑落效果

最近事情不多,想着寫點東西,又不知道寫什麼好,實現個小效果,娛樂一下,順帶自己也再熟練下自定義view的繪製的相關知識,不說廢話,先上圖:

自定義view

一、前期分析

很明顯,上面場景是又一個居中的TextView以及一個個小紅點和散開的圓圈構成。在點擊上面文本框的時候文本框出現抖動併產生一個小紅點,下紅點沿預定路徑下落,在下落到指定高度時顯示散開的波浪效果,同時伴有透明度的變化。好了,效果分析完,咱開始代碼實現吧。

二、文本框抖動的實現

文本框抖動很簡單,一個平移效果的動畫,加上循環差值器,xml如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="#fff">
    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:background="#f60"
        android:clickable="true"
        android:textColor="#fff"
        android:gravity="center"
        android:text="hahaha" />

    <com.example.test.CustomView
        android:id="@+id/v"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        />
    </LinearLayout>
    private TextView tv;

    tv=(TextView) findViewById(R.id.tv);
    final TranslateAnimation animation = (TranslateAnimation)AnimationUtils.loadAnimation(this, R.anim.animation);
    tv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.startAnimation(animation);
            }
        });

animation.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="500"
        android:fromXDelta="0"
        android:interpolator="@anim/cycle"
        android:toXDelta="10" 
        >
    </translate>

cycle.xml:

    <cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
        android:cycles="5" />

這個實現很簡單,大家看一下應該都能明白,我們繼續。

三、圓點生成以及散開效果

ok,我們的圓點生成器已經完成,我們要製作圓點了,動手之前,我們再次觀察一下,我**每點擊一次**就**生成一個**小圓點,而且小圓點是按照**自己的軌跡**掉落下來,最後自己散開。
聰明的小夥伴應該已經猜到了,每個小圓點應該都是獨立的,按照面向對象的思想,每個小圓點應該都做爲一個獨立的對象存在,那我們就先來創建小圓點的對象吧。
    class Circle{

        //x軸的 的座標
        int x;
        //y軸的座標
        int y;
        //畫筆的透明度值
        int alpha;
        //掉落後圓環的寬度
        float width;
        //圓環的半徑
        float radius;
        //繪製散開圓環的畫筆
        Paint paint;
    }
在產生小圓點以及小圓點散開的過程中,我們就是要不斷的繪製我們的界面,這裏呢,我們自定義一個View來實現這個效果。
public class CustomView extends View {

    //畫小圓點的畫筆
    private Paint paint;
    private List<Circle> list = new ArrayList<CustomView.Circle>();
    //x初始值
    //圓環的畫筆
    private Paint Circlepaint;
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);

        Circlepaint = new Paint(paint);
        Circlepaint.setStyle(Paint.Style.STROKE);
    }
    @Override
    protected void onDraw(Canvas canvas) {      
        for(Circle circle:list){
            if(circle.alpha<15){
                circle.alpha = 0;
            }
            circle.paint.setAlpha(circle.alpha);
            if(circle.y >= dp2px(300)){
                circle.paint.setStrokeWidth(circle.width);
                canvas.drawCircle(circle.x, dp2px(300), circle.radius, circle.paint);
            }else{
                canvas.drawCircle(circle.x, circle.y, circle.radiusSamll, paint);
            }
        }

    }
    //外部刷新view
    public void refresh(int y){
        int x = dp2px(150);
        int cishu = new Random().nextInt(4);
        switch (cishu) {
        case 0:
            x-=dp2px(30);
            break;
        case 1:
            x+=dp2px(30);
            break;
        case 2:
            x-=dp2px(10);
            break;
        case 3:
            x+=dp2px(10);
            break;
        }
        Circle circle = new Circle();
        circle.x = x;
        circle.y = y;
        circle.radius = dp2px(60f);
        circle.alpha = 255;
        circle.radiusSamll = dp2px(10);
        circle.width = dp2px(60f);
        circle.paint = Circlepaint;//畫圓的paint
        list.add(circle);
        invalidate();
    }
    private List<Circle> tempList = new ArrayList<CustomView.Circle>();
    @Override
    public void computeScroll() {
        for(Circle circle:list){
            if(circle.y <dp2px(300)){
                circle.y+=dp2px(8);
                invalidate();
            }else{
                if(circle.alpha >= 0){
                    circle.radius+=dp2px(28);
                    circle.alpha-=10;
                    circle.width-=dp2px(15);
                    if(circle.width<0){
                        circle.width = 0;
                        circle.radius = 0;
                    }
                    invalidate();
                }else{
                    //將alpha值小於0的對象保存在臨時集合中
                    tempList.add(circle);
                }
            }
        }
        //從集合中去除看不見的對象
        list.removeAll(tempList);
    }
    class Circle{
        //x軸的座標
        int x;
        //y軸的座標
        int y;
        //畫筆的透明度值
        int alpha;
        //掉落後圓環的寬度
        float width;
        //散落下圓環的半徑
        float radius;
        //小圓點的半徑
        float radiusSamll;
        //繪製散開圓環的畫筆
        Paint paint;
    }
    public int dp2px(float value){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
    }
}

    private TextView tv;
    private CustomView cv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        cv = (CustomView) findViewById(R.id.v);
        tv=(TextView) findViewById(R.id.tv);
    final TranslateAnimation animation = (TranslateAnimation)AnimationUtils.loadAnimation(this, R.anim.animation);
    tv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.startAnimation(animation);
                // 刷新  界面
                cv.refresh(0);
            }
        });
    }

其中核心就是每點擊一次就創建一個圓點對象,並存儲在集合中,在每次onDraw調用時,遍歷集合中每一個對象繪製在界面上,invalidate方法會觸發computeScroll方法,在computeScroll方法調用時,遍歷判斷每個對象的透明值是否小於0,即是否可見,如果不可見,我們就將其從集合中移除出去,注意集合在遍歷時不允許進行增刪操作,所以這裏我們先放進一個臨時集合中,在遍歷結束之後統一移除。

四、總結

自定義view最主要的就是根據狀態賦予不同的變量值,從而不斷的顯示不同的效果,Paint,Canvas是兩個很強大的類,有很多有趣的功能等着我們探索,加油吧。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章