自定义控件(倒计时)

最终效果:

/**
 * 自定义计时控件
 */
public class TimeView extends View {
    private TextPaint mTextPaint;
    private Paint mCricPaint;
    private Paint mArcPaint;

    /**
     * 测量的文字(通过文字测量宽度)
     */
    String mContent = "跳过";

    /**
     * 文字的宽度
     */
    private int mTextLong;

    /**
     *内圆的半径
     */
    private int mInRadius;

    /**
     * 外圆的半径
     */
    private int mOutRadius;

    /**
     * 文字的边距
     */
    private int mTextPadding = 5;

    /**
     * 内外圆之间的间隔
     */
    private int mCriclePadding = 5;

    /**
     * 外圆到画布的距离
     */
    private int mCanvasPadding = 10;

    private RectF mRectf;

    private int mDegree = 0;

    public TimeView(Context context) {
        super(context);
    }

    public TimeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
//      获取属性数组
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TimeView);
        int inCircleColor = typedArray.getColor(R.styleable.TimeView_inCircleColor, Color.GRAY);
        int outCircleColor = typedArray.getColor(R.styleable.TimeView_outCircleColor, Color.RED);
        int textColor = typedArray.getColor(R.styleable.TimeView_textColor, Color.WHITE);
        int textSize = typedArray.getInteger(R.styleable.TimeView_size, 50);

        mTextPaint = new TextPaint();
        mTextPaint.setTextSize(textSize);
        mTextPaint.setColor(textColor);

        mCricPaint = new Paint();
        mCricPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mCricPaint.setColor(inCircleColor);
        mCricPaint.setAlpha(100);

        mArcPaint = new Paint();
        mArcPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mArcPaint.setColor(outCircleColor);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setStrokeWidth(10);



        mTextLong = (int) mTextPaint.measureText(mContent);
        mInRadius = (2*mTextPadding + mTextLong)/2;
        mOutRadius = mInRadius + mCriclePadding;

//      内圆到画布的距离
        int i = mOutRadius + mCanvasPadding - mInRadius;

        mRectf = new RectF(i-5, i-5, mInRadius*2+i+5, mInRadius*2+i+5 );

//      typedArray对象使用完要进行回收
        typedArray.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        setMeasuredDimension((mOutRadius+mCanvasPadding)*2,(mOutRadius+mCanvasPadding)*2);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawCircle(mOutRadius+mCanvasPadding,mOutRadius+mCanvasPadding,mInRadius,mCricPaint);
//      旋转canvas的坐标系
        canvas.save();
        canvas.rotate(-90,mOutRadius+mCanvasPadding,mOutRadius+mCanvasPadding);

        canvas.drawArc(mRectf,0,mDegree,false,mArcPaint);
//      恢复坐标系
        canvas.restore();

//       文字底部到baseline的距离(正数)
        float descent = mTextPaint.descent();
//       文字顶部到baseline的距离 (负数)
        float ascent = mTextPaint.ascent();

        int height = canvas.getHeight();
        int width = canvas.getWidth();

//        Log.i("520","descent:" + descent+"");
//        Log.i("520","ascent:" + ascent+"");

        canvas.drawText(mContent,(width/2-mTextLong/2)*1.0f,height/2+(descent-ascent)/2-descent,mTextPaint);

    }

    public void setDegree(int degree){
        this.mDegree = degree;
        invalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction()){
            case  MotionEvent.ACTION_DOWN:
                setAlpha(0.3f);
                break;
            case  MotionEvent.ACTION_UP:
                setAlpha(1.0f);
                break;
            default:
                break;
        }

        return true;
    }
}

attrs文件的配置

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TimeView" >
        <attr name="inCircleColor" format="color" />
        <attr name="outCircleColor" format="color" />
        <attr name="textColor" format="color" />
        <attr name="size" format="integer" />
    </declare-styleable>
</resources>

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TimeView mTimeView;
    private Handler mHandler;

    private int mDegree = 0;


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

        findViewById(R.id.net_bt).setOnClickListener(this);

        mTimeView = findViewById(R.id.custom_tv);

        mHandler = new MyHandler(this);

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mDegree += 30;
//              使用message保存数据
                Message message = mHandler.obtainMessage(0);
                message.arg1 = mDegree;
//              发送消息
                mHandler.sendMessage(message);
//              递归
                if(mDegree>=360){
//                  移除这个任务
                    mHandler.removeCallbacks(this);
                }
                mHandler.postDelayed(this,100);

            }
        });
    }


//      使用static切断对MainActivity的引用,将Mainactivity设置为弱引用来取值,防止内存的泄露
    static class MyHandler extends Handler{
        private WeakReference<MainActivity> main;

        public MyHandler(MainActivity main){
            this.main = new WeakReference<MainActivity>(main);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(main == null){
                return;
            }
            MainActivity mainActivity = main.get();
            switch(msg.what){
                case  0:
                    mainActivity.mTimeView.setDegree(msg.arg1);
                    break;
                default:
                    break;
            }
        }
    }

}

 

posted @ 2018-03-25 10:02  Kliver  阅读(151)  评论(0编辑  收藏  举报