自定义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是两个很强大的类,有很多有趣的功能等着我们探索,加油吧。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章