自定义控件之水波纹的实现--手势识别器SimpleOnGestureListener

缺陷:每次只能显示一个圆环的效果,当点击第二次的时候就会把第一次的效果中断掉

模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明)
1、自定义类继承View
2、重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心。
3、发送handler信息,对数据进行修改,刷新页面。
4、重写onDraw方法,绘制一个圆环。
5、如果可以执行动画,重复上面第3步。

代码如下:

MainActivity.java

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
}

布局文件:activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.ripple.MyRound
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

自定义控件类:MyRound.java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/*
模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明)
1、自定义类继承View
2、重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心。
3、发送handler信息,对数据进行修改,刷新页面。
4、重写onDraw方法,绘制一个圆环。
5、如果可以执行动画,重复上面第3步。
 */
public class MyRound extends View{

    private int roundX;//圆心X轴坐标
    private int roundY;//圆心Y轴坐标
    private Paint paint;//画圆的画笔
    private float rwidth;//圆的线条的宽度
    private int radius;//圆的半径
    private int ranNum;//随机数
    private int[] randomColor={Color.BLACK,Color.BLUE,Color.CYAN,Color.DKGRAY,Color.GRAY,
            Color.GREEN,Color.LTGRAY,Color.MAGENTA,Color.RED,Color.YELLOW};
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            invalidate();//刷新界面,会执行onDraw方法
        }
    };
    

    public MyRound(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    /**
     * 初始化数据,每次点击一次都要初始化一次
     */
    private void initData() {
        paint=new Paint();//因为点击一次需要画出不同半径的圆
        paint.setAntiAlias(true);//打开抗锯齿
        ranNum=(int) (Math.random()*10);//[0,9]的随机数
        paint.setColor(randomColor[ranNum]);//设置画笔的颜色
        paint.setStyle(Style.STROKE);//画出空心圆
        paint.setStrokeWidth(rwidth);//设置空心圆的外面线条宽度
        paint.setAlpha(255);//透明度的设置(0-255),0为完全透明
        radius=0;//初始化,也是每次的清零
        rwidth=0;
    }

    @Override
    /**
     * 绘制显示的内容,一运行程序就会执行一次onDraw方法
     * 调用invalidate(刷新界面)方法的后也会调用此方法
     */
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        if(paint!=null){//避免程序一运行就执行drawRound方法
            drawRound(canvas);
        }
    }
    
    /**
     * 一次点击圆环的绘制
     */
    private void drawRound(Canvas canvas){
        //绘制圆环(圆心坐标,半径,画笔)
        canvas.drawCircle(roundX, roundY, radius, paint);
        radius=radius+5;
        int alpha = paint.getAlpha();//获取透明度
        if(alpha!=0){
            if(alpha<=20){
                alpha=0;
            }else{
                alpha=alpha-5;
            }
            paint.setStrokeWidth(radius/10);//设置空心圆的外面线条宽度
            paint.setAlpha(alpha);//设置透明度
            handler.sendEmptyMessageDelayed(1, 100);//延时100ms发送
        }
    }
    
    @Override
    /**
     * 获取触摸的坐标,以确定圆心
     */
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://获取按下的坐标
            roundX = (int) event.getX();
            roundY=(int) event.getY();
            initData();//每次点击后要初始化数据
            invalidate();//刷新界面,会调用onDraw方法
            break;
        }
        return true;
    }
    
    /**
     * 不需要重写,因为没有在该控件上添加控件
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

效果图:

=================================================

自定义控件之水波纹的实现-2

功能:与上一个相比,这次可以实现多次点击,每次的圆环动画效果都是单独的,但是没有拖动功能

主活动与布局文件不变,其他代码如下:

每个圆环的实体类 UnitRound.java

 

import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
/**
 *使用不同的画笔,然后一次刷新出多个画笔所绘制的图像就可以了
 *该类为每个圆环的属性
 */
public class UnitRound {
    public int roundX;//圆心X轴坐标
    public int roundY;//圆心Y轴坐标
    public Paint paint;//画圆的画笔
    public float rwidth;//圆的线条的宽度
    public int radius;//圆的半径
    public int ranNum;//随机数
    public int[] randomColor={Color.BLACK,Color.BLUE,Color.CYAN,Color.DKGRAY,Color.GRAY,
            Color.GREEN,Color.LTGRAY,Color.MAGENTA,Color.RED,Color.YELLOW};
    
    public UnitRound(int roundX, int roundY) {
        this.roundX=roundX;
        this.roundY=roundY;
        initData();
    }

    /**
     * 初始化数据,每次点击一次都要初始化一次
     */
    private void initData() {
        paint=new Paint();//因为点击一次需要画出不同半径的圆
        paint.setAntiAlias(true);//打开抗锯齿
        ranNum=(int) (Math.random()*10);//[0,9]的随机数
        paint.setColor(randomColor[ranNum]);//设置画笔的颜色
        paint.setStyle(Style.STROKE);//画出空心圆
        paint.setStrokeWidth(rwidth);//设置空心圆的外面线条宽度
        paint.setAlpha(255);//透明度的设置(0-255),0为完全透明
        radius=0;//初始化
        rwidth=0;
    }
    
}

自定义控件类:MyRound.java 

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/*
模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明)
1、自定义类继承View
2、重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心。
3、发送handler信息,对数据进行修改,刷新页面。
4、重写onDraw方法,绘制一个圆环。
5、如果可以执行动画,重复上面第3步。
 */
public class MyRound extends View{
    /**
     * 存放每一个圆环
     */
    private ArrayList<UnitRound> list;
    
    /**
     * 发送延时执行界面的刷新,实现动画的效果
     */
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            invalidate();//刷新界面,会执行onDraw方法
        }
    };
    

    public MyRound(Context context, AttributeSet attrs) {
        super(context, attrs);
        list=new ArrayList<UnitRound>();
    }
    

    @Override
    /**
     * 绘制显示的内容,一运行程序就会执行一次onDraw方法
     * 调用invalidate(刷新界面)方法的后也会调用此方法
     */
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        if(list.size()!=0){//避免程序一运行就执行drawRound方法
            drawRound(canvas);
        }
    }
    
    /**
     * 删除透明度为0的对象,不然list的对象过多
     */
    private void deleteItem(){
        for (int i = 0; i < list.size(); i++) {
            if(list.get(i).paint.getAlpha()==0){
                list.remove(i);
            }
        }
    }
    
    /**
     * 一次点击圆环的绘制
     */
    private void drawRound(Canvas canvas){
        for(UnitRound unit : list){
            //绘制圆环(圆心坐标,半径,画笔)
            canvas.drawCircle(unit.roundX, unit.roundY, unit.radius, unit.paint);
            unit.radius+=5;
            int alpha = unit.paint.getAlpha();//获取透明度
            if(alpha!=0){
                if(alpha<=20){
                    alpha=0;
                }else{
                    alpha=alpha-5;
                }
                unit.paint.setStrokeWidth(unit.radius/10);//设置空心圆的外面线条宽度
                unit.paint.setAlpha(alpha);//设置透明度
                handler.sendEmptyMessageDelayed(1, 100);//延时100ms发送
            }
        }
        System.out.println("list的个数:"+list.size());
    }
    
    @Override
    /**
     * 获取触摸的坐标,以确定圆心
     */
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://获取按下的坐标
            UnitRound unit=new UnitRound((int) event.getX(),(int) event.getY());
            deleteItem();//删除透明度为0的圆环,不写这里容易出现并发异常
            list.add(unit);//将这个对象添加到集合
            invalidate();//刷新界面,会调用onDraw方法
            break;
        }
        return true;
    }
    
    /**
     * 不需要重写,因为没有在该控件上添加控件
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

效果图:

 自定义控件之水波纹的实现-3

可以拖动的出现圆环,其他类不变,手势识别器的使用

MyRound.java:

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.GestureDetectorCompat;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
/*
实现滚动:通过手势解析器创建对应的圆环就行
知识点:手势识别器的使用:SimpleOnGestureListener
 */
public class MyRound extends View{
    /**
     * 存放每一个圆环
     */
    private ArrayList<UnitRound> list;
    
    /**
     * 手势识别器
     */
    private GestureDetector detector;   
    
    /**
     * 发送延时执行界面的刷新,实现动画的效果
     */
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            invalidate();//刷新界面,会执行onDraw方法
        }
    };
    

    public MyRound(Context context, AttributeSet attrs) {
        super(context, attrs);
        list=new ArrayList<UnitRound>();
        detector=new GestureDetector(context,new MySimpleGesture());//初始化解析器
    }
    

    @Override
    /**
     * 绘制显示的内容,一运行程序就会执行一次onDraw方法
     * 调用invalidate(刷新界面)方法的后也会调用此方法
     */
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        if(list.size()!=0){//避免程序一运行就执行drawRound方法
            drawRound(canvas);
        }
    }
    
    /**
     * 删除透明度为0的对象,不然list的对象过多
     */
    private void deleteItem(){
        for (int i = 0; i < list.size(); i++) {
            if(list.get(i).paint.getAlpha()==0){
                list.remove(i);
            }
        }
    }
    
    /**
     * 一次点击圆环的绘制
     */
    private void drawRound(Canvas canvas){
        for(UnitRound unit : list){
            //绘制圆环(圆心坐标,半径,画笔)
            canvas.drawCircle(unit.roundX, unit.roundY, unit.radius, unit.paint);
            unit.radius+=5;
            int alpha = unit.paint.getAlpha();//获取透明度
            if(alpha!=0){
                if(alpha<=20){
                    alpha=0;
                }else{
                    alpha=alpha-5;
                }
                unit.paint.setStrokeWidth(unit.radius/10);//设置空心圆的外面线条宽度
                unit.paint.setAlpha(alpha);//设置透明度
                handler.sendEmptyMessageDelayed(1, 100);//延时100ms发送
            }
        }
    }
    
    @Override
    /**
     * 获取触摸的坐标,以确定圆心
     */
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        detector.onTouchEvent(event);//复制一份事件给解析器处理
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://获取按下的坐标
            UnitRound unit=new UnitRound((int) event.getX(),(int) event.getY());
            deleteItem();//删除透明度为0的圆环,不写这里容易出现并发异常
            list.add(unit);//将这个对象添加到集合
            invalidate();//刷新界面,会调用onDraw方法
            break;
        }
        return true;
    }
    
    /**
     * 手势识别器
     */
    private class MySimpleGesture extends SimpleOnGestureListener{
        /**
         *     e1  第一运动事件开始滚动。
            e2  此举运动事件,引发了当前onScroll。
            distanceX沿着X轴的距离,自从上次叫onScroll滚动。这不是e1和e2之间的距离。
            distanceY沿着Y轴的距离,自从上次叫onScroll滚动。这不是e1和e2之间的距离。
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            //System.out.println("滑动了");
            UnitRound unit=new UnitRound((int) e2.getX(),(int) e2.getY());
            deleteItem();//删除透明度为0的圆环,不写这里容易出现并发异常
            list.add(unit);//将这个对象添加到集合
            invalidate();//刷新界面,会调用onDraw方法
            return true;
        }
        
    }
    
    /**
     * 不需要重写,因为没有在该控件上添加控件
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

效果图:

 

posted @ 2016-08-02 19:36  ts-android  阅读(652)  评论(0编辑  收藏  举报