首先是效果图:
然后分析一下我写的代码:
通过阅读郭神的博客了解到自定义view大体包含3种:自绘控件,组合控件,和继承控件。
我用的是第一种,自绘控件。自绘控件继承自view,重写ondraw方法,绘制自己需要的视图。
上图的实现,用了两个自绘的view,那个圆环是一个,那个圆球是一个。
那个圆环的实现比较简单,来看一下代码:
/** * Created by J on 2016/3/25. */ public class CircleView extends View { Paint mPaint1, mPaint2; int r ; int r0 = 5; public void setR(int r) { this.r = r; } public CircleView(Context context) { super(context); } public CircleView(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); } private void initPaint() { mPaint1 = new Paint(); mPaint1.setColor(getResources().getColor(R.color.color_6c6c6c)); mPaint1.setAntiAlias(true); mPaint2 = new Paint(); mPaint2.setColor(getResources().getColor(R.color.color_2ea9ff)); mPaint2.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(getWidth() / 2, getHeight() / 2, r + r0, mPaint2); canvas.drawCircle(getWidth() / 2, getHeight() / 2, r, mPaint1); } public void changSize(int w) { r = w; invalidate(); } }
我取了个名字叫CircleView,继承自View,需要重写一下他的构造方法,有四个构造方法,一般重写两个就够了,其中第一个构造方法
public CircleView(Context context) { super(context); }
这个构造方法,是用来new的,比如CircleView circle = new CircleView(this),就会调用这个构造方法,而第二个:
public CircleView(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); }
这个构造方法是在加载xml布局文件时调用的,你定义的属性也在这里调用,当然我没有定义,只是单纯的在xml里用了这个控件:
<com.xzj.TouchCircle android:id="@+id/TouchCircle" android:layout_width="wrap_content" android:layout_height="wrap_content" />
在加载控件的时候可以看到构造方法里实例化了paint,画笔,看一下方法:
private void initPaint() { mPaint1 = new Paint(); mPaint1.setColor(getResources().getColor(R.color.color_6c6c6c)); mPaint1.setAntiAlias(true); mPaint2 = new Paint(); mPaint2.setColor(getResources().getColor(R.color.color_2ea9ff)); mPaint2.setAntiAlias(true); }
在这里边实例化了两个不同的画笔,当然在ondraw方法里也画了两个圆:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(getWidth() / 2, getHeight() / 2, r + r0, mPaint2); canvas.drawCircle(getWidth() / 2, getHeight() / 2, r, mPaint1); }
圆环其实是这样实现的:一个大圆套一个小圆,小圆与背景色一样,这样就形成了圆环。它为什么会变大变小的,因为我写了一个方法:
public void changSize(int w) { r = w; invalidate(); }
给方法传参,改变半径,并且调用invalid()方法重绘视图。圆环讲完了,再来看一下移动的圆:
/** * Created by J on 2016/3/24. */ public class TouchCircle extends View { private Paint mPaint; private CircleView Circle; int tmpcy = 0; int tmpcx = 0; int r; int type = 0; int cy; int cx; int cr; public void setCr(int cr) { this.cr = cr; } public void setR(int r) { this.r = r; } public void setListener(TouchCircleListener listener) { this.listener = listener; } TouchCircleListener listener; public TouchCircle(Context context) { super(context); } public TouchCircle(Context context, AttributeSet attrs) { super(context, attrs); iniPaint(); } private void iniPaint() { mPaint = new Paint(); mPaint.setColor(getResources().getColor(R.color.color_cb6854)); mPaint.setAntiAlias(true); } public void setView(CircleView circle) { this.Circle = circle; } public void setCy(int cy) { this.cy = cy; } public void setCx(int cx) { this.cx = cx; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(cx, cy, r, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: tmpcx = (int) event.getX(); tmpcy = (int) event.getY(); int Lx = tmpcx - cx; int Ly = tmpcy - cy; if ((Lx > -r && Lx < r) && (Ly > -r && Ly < r)) { return true; } return false; case MotionEvent.ACTION_MOVE: cx = (int) event.getX(); cy = (int) event.getY(); break; case MotionEvent.ACTION_UP: //抬起 if (inCircle()) { r = 0; type++; listener.onTouchCircle(type); } break; } if (inCircle() && r != 0) { Circle.changSize(cr+30); } else { Circle.changSize(cr); } invalidate(); return super.onTouchEvent(event); } private boolean inCircle() { int R = 80; int r1 = getWidth() / 2 > cx ? getWidth() / 2 - cx : cx - getWidth() / 2; int r2 = getHeight() / 2 > cy ? getHeight() / 2 - cy : cy - getHeight() / 2; if (r1 * r1 < R * R && r2 * r2 < R * R && r1 < R - 50 / 2 && r2 < R - 50 / 2) { return true; } return false; } }
实例化了一个画笔,画了一个圆,之所以能够移动是因为重写了onTouch方法:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: tmpcx = (int) event.getX(); tmpcy = (int) event.getY(); int Lx = tmpcx - cx; int Ly = tmpcy - cy; if ((Lx > -r && Lx < r) && (Ly > -r && Ly < r)) { return true; } return false; case MotionEvent.ACTION_MOVE: cx = (int) event.getX(); cy = (int) event.getY(); break; case MotionEvent.ACTION_UP: //抬起 if (inCircle()) { r = 0; type++; listener.onTouchCircle(type); } break; } if (inCircle() && r != 0) { Circle.changSize(cr+30); } else { Circle.changSize(cr); } invalidate(); return super.onTouchEvent(event); }
把触摸的坐标当作圆心的坐标,重绘视图,看起来就像是在移动,
case MotionEvent.ACTION_DOWN: tmpcx = (int) event.getX(); tmpcy = (int) event.getY(); int Lx = tmpcx - cx; int Ly = tmpcy - cy; if ((Lx > -50 && Lx < 50) && (Ly > -50 && Ly < 50)) { return true; } return false;
这一部分很重要,限定了点下的位置,只有点到圆的时候才可以移动
private boolean inCircle() { int R = 80; int r1 = getWidth() / 2 > cx ? getWidth() / 2 - cx : cx - getWidth() / 2; int r2 = getHeight() / 2 > cy ? getHeight() / 2 - cy : cy - getHeight() / 2; if (r1 * r1 < R * R && r2 * r2 < R * R && r1 < R - 50 / 2 && r2 < R - 50 / 2) { return true; } return false; }
这个方法判断了是否在圆环范围之内,当圆球在圆环的范围内,不抬起时,圆环变大,抬起时,圆环变为原来的大小,圆球的半径变为0,看起来圆环把圆球吞了。
圆环吞圆球的时候还包含了activity的跳转,在View里边是不能直接跳的,所以定义了一个监听:
/** * Created by J on 2016/3/29. */ public interface TouchCircleListener { void onTouchCircle(int touch); }
在Activity里给View设置监听:
touchCircle.setListener(new TouchCircleListener() { @Override public void onTouchCircle(int touch) { if (touch == 1) { startActivity(new Intent(MainActivity.this, SecondActivity.class)); finish(); } } });
满足条件就跳转,两个圆的时候怎么监听呢? 给两个圆球都设置监听:
touchCircle1.setListener(new TouchCircleListener() { @Override public void onTouchCircle(int touch) { if (touch == 1) { type++; jump(); } } }); touchCircle2.setListener(new TouchCircleListener() { @Override public void onTouchCircle(int touch) { if (touch == 1) { type++; jump(); } } }); } private void jump() { if (type == 2) { startActivity(new Intent(SecondActivity.this, ThirdActivity.class)); finish(); } }
这样当两个球都被吞的时候就会跳第三个Activity。
Over