自定义 View 之完全自定义

3,450 阅读4分钟

文章来自:Android程序员日记

作者:贤榆的鱼

测试阅读时间:5min30s

前言

前面我给大家分享过"自定义控件之扩展式"“自定义控件之复合式”,现在终于到了完全自定义阶段,其实完全自定义控件就是通过重写View来实现的全新控件!
先来看看效果图:


正文

[ 0 ] 这或许才是第一步
看上图分析一下就可以得出它是由一个黑色的圆弧和一个白色的圆弧再加上中间的文字组合而成的自定view!下面我们就来看一下,是怎样具体实现它的!

[ 1 ] 创建一个类继承View

public class ScoreView extends View{
    //实现构造方法时传入要显示的数字
    public ScoreView(Context context,int score){
        super(context);
        init(score);
    }

[ 2 ] 初始化所有的备用条件

private void init(int score) {
    this.score=score;
    Resources res = getResources();
    //以10dp作为单位量
    unitage = res.getDimension(R.dimen.unitage);

    //初始黑色笔
    mPaint_black = new Paint();
    //设置抗锯齿,优化绘制效果的精细度
    mPaint_black.setAntiAlias(true);
    //设置图像抖动处理,也是用于优化图像的显示效果
    mPaint_black.setDither(true);
    //设置画笔的颜色
    mPaint_black.setColor(Color.BLACK);
    //设置画笔的风格为空心
    mPaint_black.setStyle(Paint.Style.STROKE);
    //设置“空心”的外框宽度为2dp
    mPaint_black.setStrokeWidth(unitage*0.2f);

    //初始白色笔
    mPaint_while = new Paint();
    mPaint_while.setAntiAlias(true);
    mPaint_while.setStyle(Paint.Style.STROKE);
    mPaint_while.setStrokeWidth(unitage*0.2f);
    mPaint_while.setDither(true);
    //设置文本的字号大小
    mPaint_while.setTextSize(unitage*6);
    //设置文本的对其方式为水平居中
    mPaint_while.setTextAlign(Paint.Align.CENTER);
    mPaint_while.setColor(Color.WHITE);

    //初始化圆弧所需条件(及设置圆弧的外接矩形的四边)
    mRectf = new RectF();
    mRectf.set(unitage*0.5f,unitage*0.5f,unitage*18.5f,unitage*18.5f);
    //设置整个控件的宽高配置参数
    setLayoutParams(new ViewGroup.LayoutParams((int)(unitage*19.5f),(int)(unitage*19.5f)));

    //获取该view的视图树观察者并添加绘制变化监听者
    //实现有绘制变化时的回调方法
    this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            //2.开启子线程对绘制用到的数据进行修改
            new DrawThread();
            getViewTreeObserver().removeOnPreDrawListener(this);
            return false;
        }
    });
}

注1:如果大家对Paint类还不太熟悉可以看一下我这里的一个摘抄笔记:
note.youdao.com/yws/public/…

注2:ViewTreeObserver——注册监听视图树的观察者,关于它的介绍,我这里也有一篇摘抄笔记可以帮助大家更好的理解这个例子:
note.youdao.com/yws/public/…

注3:这里使用unitage=10dp作为单位量进行计算就可以很好的保证我们的自定义View在不同分辨率的手机上保持不变形

[ 3 ] 开启子线程并在绘制监听的回调方法中实现实时更新绘制数据

 public class DrawThread implements Runnable {
    //2.开启子线程,并通过绘制监听实时更新绘制数据
    private final Thread mDrawThread;
    private int statek;
    int count;

    public DrawThread() {
        mDrawThread = new Thread(this);
        mDrawThread.start();
    }

    @Override
    public void run() {
        while (true) {
            switch (statek) {
                case 0://给一点点缓冲的时间
                    try {
                        Thread.sleep(200);
                        statek = 1;
                    } catch (InterruptedException e) {

                    }
                    break;
                case 1:
                    try {//更新显示的数据
                        Thread.sleep(20);
                        arc_y += 3.6f;
                        score_text++;
                        count++;
                        postInvalidate();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
            }
            if (count >= score)//满足该条件就结束循环
                break;
        }

    }
}

[ 4 ] 重写onDraw方法绘制自定义View

 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //绘制弧形
    //黑笔画的是一个整圆所有从哪里开始都一样
    canvas.drawArc(mRectf,0,360,false,mPaint_black);
    //白笔之所以从-90度开始,是因为0度其实使我们的3点钟的位置,所以-90才是我们的0点的位置
    canvas.drawArc(mRectf,-90,arc_y,false,mPaint_while);
    //绘制文本
    canvas.drawText(score_text+"",unitage*9.7f,unitage*11.0f,mPaint_while);

    //到此整个自定义View就已经写完了
}

[ 5 ] 将自定义控件添加到创建的ScoreActivity中

public class ScoreActivity extends Activity {

    private LinearLayout scoreView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_score);
        scoreView = (LinearLayout) findViewById(R.id.score_View);
        scoreView.addView(new ScoreView(this,80));
    }
}

附 该项目gitHub地址:
github.com/luorenyu/Co…

动态图效果图:


后记

上面这自定view虽然简单,但是自定义控件就是这么一步一步描绘出来的,如果你还想直接可以在xml布局中使用,那么就可以使用在“自定义控件之复合式”中使用过的——在attr中配置自定义属性。并且通过引入自定义属性,还可以极大的丰富我们控件的可定制性!

最后我想说我并不是一个Android技术特别特别好或是特别厉害的Android开发者。但我还是喜欢分享,也喜欢尽可能的做到让更多的人更容易理解我的分享!如果有一些东西你还是不能理解的,那就去敲一遍代码然后把你不理解的地方的值改掉然后看看有什么变化,你就很容易得出答案了!

学习的过程也像构建自定义View的过程,需要一步一步来,无论是多么复杂的控件都是从基础的绘制开始,慢慢的迭代添加效果和功能!仅以此废话与君共勉。

我的所有文章将在微信公众号第一时间更新,还不关注!


欢迎关注我的微信公众号:Android程序员日记