最近看了一个叫投票的App,发现有点意思的。就是当我长按的时候会开始画一个圈圈,然后当这个圈圈画成一个整圆的时候就会投票成功,然后显示出数据。当然,当这个圈没有画成一个圆的时候,我们松手就会将这个圆圈画回去。效果如下:
自己也写的玩玩。先想想看怎么去实现。
1.需要自定义一个手指放上去就画圈,但是手指拿下来就销毁圈圈的View,并且画满一个圆的时候还会处理其他事情(颜色、宽度、圆圈大小)
2.需要自定义一个画圆圈的View(颜色、宽度、圆圈大小)。
3.将手指放在View上的时候就会触发画圈操作,离开的时候就会取消画圈的操作,这就需要处理View的Touch事件。这个的操作其实也是在第一个圆圈中。
第一步:实现投票的View,可以看到当去点击该View的时候就会开始去画圈,当松开的时候就会慢慢销毁这个圆圈。而对应的点击就是ACTION_DOWN的事件,那么取消呢?最开始我做的时候仅仅考虑的是ACTION_UP,但是后来发现如果是在ListView,ViewPager等滑动的时候不会执行ACTION_UP的事件。所以还需要在onTouchEvent()中加上ACTION_CANCEL。同时为了保证该View能获取到相应的事件,需要在onTouchEvent()返回true。
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 投票的View
*/
public class VoteProgress extends View
{
// 当前的进度
private int progress;
// 画笔的颜色
private int color;
// 圆圈的半径(实际上会根据View的高度和宽度来计算出一个合适的radius)
private int radius;
// 画笔的宽度
private int progressStrokeWidth;
private static final int PROGRESS = 0;
private static final int COLOR = 0xff969696;
private static final int RADIUS = 0;
private static final int PROGRESS_STROKE_WIDTH = 0;
private Paint progressPaint;
private RectF progressRect = new RectF();
private ClickProgressCallBack clickProgressCallBack;
public VoteProgress(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VoteProgress,
defStyleAttr, 0);
progress = attributes.getInt(R.styleable.VoteProgress_progress_progress, PROGRESS);
color = attributes.getColor(R.styleable.VoteProgress_progress_color, COLOR);
radius = attributes.getDimensionPixelSize(R.styleable.VoteProgress_progress_radius, RADIUS);
progressStrokeWidth = attributes.getDimensionPixelSize(R.styleable.VoteProgress_progress_stroke_width,
PROGRESS_STROKE_WIDTH);
attributes.recycle();
initPainter();
}
public VoteProgress(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public VoteProgress(Context context)
{
this(context, null);
}
// 初始化画笔
private void initPainter()
{
progressPaint = new Paint();
progressPaint.setColor(color);
progressPaint.setStrokeWidth(progressStrokeWidth);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setAntiAlias(true);
}
// 用来画圆
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int delta = getProgressStrokeWidth();
int width = getWidth();
int height = getHeight();
int size = width > height ? height : width;
radius = (size / 2 - delta) * 3 / 4;
// 设置圆弧内边所在的区域
progressRect.set(width / 2 - radius, height / 2 - radius, width / 2 + radius, height / 2 + radius);
canvas.drawArc(progressRect, 180, getProgress(), false, progressPaint);
}
private boolean isDown = false;
/**
* 监听onTouch事件
*/
@Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
isDown = true;
final View view = this;
this.post(new Runnable()
{
@Override
public void run()
{
if (progress >= 360)
{
if (clickProgressCallBack != null)
{
clickProgressCallBack.onProgressOk(view);
}
return;
}
if (progress < 360 && isDown == true)
{
progress += 15;
setProgress(progress);
postDelayed(this, 10);
}
}
});
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isDown = false;
break;
}
post(new Runnable()
{
@Override
public void run()
{
if (progress >= 1 && isDown == false)
{
progress -= 15;
setProgress(progress);
postDelayed(this, 10);
}
}
});
return true;
}
public int getProgress()
{
return progress;
}
public void setProgress(int progress)
{
this.progress = progress;
this.invalidate();
}
public int getColor()
{
return color;
}
public void setColor(int color)
{
this.color = color;
}
public int getRadius()
{
return radius;
}
public void setRadius(int radius)
{
this.radius = radius;
}
public int getProgressStrokeWidth()
{
return progressStrokeWidth;
}
public void setProgressStrokeWidth(int progressStrokeWidth)
{
this.progressStrokeWidth = progressStrokeWidth;
}
public void setClickProgressCallBack(ClickProgressCallBack listener)
{
this.clickProgressCallBack = listener;
}
/**
* 用于回调View处理完成以后的操作
*/
public static interface ClickProgressCallBack
{
public void onProgressOk(View view);
}
}
第二步:实现结果的展示。这个只需要根据数据得到响应的项对应的progress是多少。
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
/**
* 投票结果的View
*/
public class VoteResultProgress extends View
{
// 当前的进度
private int progress;
// 画过的颜色
private int finishColor;
// 没有画过的颜色
private int unfinishColor;
// 圆圈的半径(实际上会根据View的高度和宽度来计算出一个合适的radius)
private int radius;
// 画笔的宽度
private int strokeWidth;
private static final int PROGRESS = 0;
private static final int FINISH_COLOR = 0xff969696;
private static final int UNFINISH_COLOR = 0xff969696;
private static final int RADIUS = 0;
private static final int PROGRESS_STROKE_WIDTH = 0;
private Paint finishPaint;
private Paint unfinishPaint;
private RectF finishProgressRect = new RectF();
private RectF unfinishProgressRect = new RectF();
public VoteResultProgress(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VoteResultProgress,
defStyleAttr, 0);
progress = attributes.getInt(R.styleable.VoteResultProgress_progress, PROGRESS);
finishColor = attributes.getColor(R.styleable.VoteResultProgress_finish_color, FINISH_COLOR);
unfinishColor = attributes.getColor(R.styleable.VoteResultProgress_unfinish_color, FINISH_COLOR);
radius = attributes.getInt(R.styleable.VoteResultProgress_radius, RADIUS);
strokeWidth = attributes.getDimensionPixelSize(R.styleable.VoteResultProgress_stroke_width,
PROGRESS_STROKE_WIDTH);
attributes.recycle();
initPainter();
}
public VoteResultProgress(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public VoteResultProgress(Context context)
{
this(context, null);
}
private void initPainter()
{
finishPaint = new Paint();
finishPaint.setColor(finishColor);
finishPaint.setStrokeWidth(strokeWidth);
finishPaint.setStyle(Paint.Style.STROKE);
finishPaint.setAntiAlias(true);
unfinishPaint = new Paint();
unfinishPaint.setColor(unfinishColor);
unfinishPaint.setStrokeWidth(strokeWidth);
unfinishPaint.setStyle(Paint.Style.STROKE);
unfinishPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int delta = getStrokeWidth();
int width = getWidth();
int height = getHeight();
int size = width > height ? height : width;
radius = (size / 2 - delta) * 3 / 4;
finishProgressRect.set(width / 2 - radius, height / 2 - radius, width / 2 + radius, height / 2 + radius);
canvas.drawArc(finishProgressRect, 270, getProgress() % 360, false, finishPaint);
unfinishProgressRect.set(width / 2 - radius, height / 2 - radius, width / 2 + radius, height / 2 + radius);
canvas.drawArc(unfinishProgressRect, 270 + getProgress() % 360, 360 - getProgress() % 360, false,
unfinishPaint);
}
public int getProgress()
{
return progress;
}
public void setProgress(int progress)
{
this.progress = progress;
this.invalidate();
}
public int getFinishColor()
{
return finishColor;
}
public void setFinishColor(int finishColor)
{
this.finishColor = finishColor;
}
public int getUnfinishColor()
{
return unfinishColor;
}
public void setUnfinishColor(int unfinishColor)
{
this.unfinishColor = unfinishColor;
}
public int getRadius()
{
return radius;
}
public void setRadius(int radius)
{
this.radius = radius;
}
public int getStrokeWidth()
{
return strokeWidth;
}
public void setStrokeWidth(int strokeWidth)
{
this.strokeWidth = strokeWidth;
}
public void startIncreaseAnima(int duration)
{
ObjectAnimator anima = ObjectAnimator.ofInt(this, "progress", 0, progress);
anima.setDuration(duration);
anima.setInterpolator(new AccelerateInterpolator());
anima.start();
}
}
然后,最后做的效果就是这样了。
自己从这个Demo中学习了一些事件的处理,对于事件的种类,触发的实际,事件的拦截也加深了了解。