模仿一个投票,学习一下View的事件分发和拦截

最近看了一个叫投票的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中学习了一些事件的处理,对于事件的种类,触发的实际,事件的拦截也加深了了解。

点此下载源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值