自定义控件之水波纹的实现--手势识别器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); } }
效果图: