笔记 Androd 自定义控件学习(三)

自定义View

Android 给我们提供了丰富的组件来创建不同的UI效果,同时也提供了非常方便的扩展方法。通过继承Android的系统组件,我们可以非常方便的扩展现有的功能,在系统组件的基础上创建新的功能,甚至可以直接自定义一个控件,实现Android系统控件所没有的功能。
在自定义View时,我们通常会去重写一些Android的方法来绘制View的显示内容,另外通过自定义attrs属性,还可以设置新的属性配置值。在View中通常有以下一些比较重要的回调方法:

  • onFinishInflate() :从XML加载组件后回调
  • onDraw() : 重新绘图时回调
  • onSizeChanged() :组件大小改变时回调
  • onMeasure() :回调该方法来进行测量
  • onLayout() :回调该方法来确定显示的位置
  • onTouchEvent() :监听到触摸事件时回调

在创建自定义View的时候,并不需要重写所有的方法,只需要重写特定条件的回调方法即可。
通常情况下,有三种方法来实现自定义的控件:

  • 对现有控件进行扩展
  • 通过组合来实现新的控件
  • 重写View来实现全新的控件

对现有控件进行扩展

这是一个比较重要的自定义View的方法,他可以在原生控件的基础上进行扩展,增加新的功能,修改显示的UI,一般来说我们可以在onDraw()方法中对原生控件行为进行扩展。
下面以一个TextView为例:来介绍如何使用扩展原生控件的方法创建新的控件:

    @Override
    protected void onDraw(Canvas canvas) {
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容前
        super.onDraw(canvas);
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容后
        }
    }

程序调用super.onDraw(canvas)方法来实现原生控件的功能,但是在调用super.onDraw(canvas)方法之前和之后,我们可以实现自己的逻辑,分别在系统绘制文字前后,完成自己的操作。

我们在构造方法中完成必要对象的初始化工作:

mPaint1 = new Paint();
mPaint1.setColor(getResources().getColor(R.color.colorAccent));
mPaint1.setStyle(Paint.Style.FILL);

mPaint2 = new Paint();
mPaint2.setColor(Color.YELLOW);
mPaint2.setStyle(Paint.Style.FILL);

为了改变原生的绘制行为,在系统调用super.onDraw(canvas)方法前,也就是在绘制文字之前,绘制两个不同大小的矩形,形成一个重叠效果,在让系统调用super.onDraw(canvas)方法,执行绘制文字的工作,这样,我们就通过改变控件绘制行为,创建一个新的控件,代码如下:

canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint2);
//绘制文字前平移10像素
canvas.translate(10,0);

完成代码如下:

    @Override
    protected void onDraw(Canvas canvas) {
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容前
        initPaint(canvas);
        super.onDraw(canvas);
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容后

        //用来恢复Canvas旋转、缩放等之后的状态,
        //当和canvas.save( )一起使用时,恢复到canvas.save( )保存时的状态
        canvas.restore();

    }

    private void initPaint(Canvas canvas){
        mPaint1 = new Paint();
        mPaint1.setColor(getResources().getColor(R.color.colorAccent));
        mPaint1.setStyle(Paint.Style.FILL);

        mPaint2 = new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.FILL);

        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint2);
        //绘制文字前平移10像素
        canvas.translate(10,0);
    }

接下来我们利用 LinearGradient ShaderMatrix来实现一个动态的文字闪现效果,要想实现这一个效果,可以充分利用Android 中Paint 对象的Shader 渲染器,通过设置不断变化的LinearGradient,并使用带有该属性的Paint对象来绘制显示要显示的文字。在onSizeChanged()方法中进行一些对象的初始化工作,并根据View的Paint设置一个LinearGradient渐变渲染器。

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mViewWidth == 0){
            mViewWidth = getMeasuredWidth();
            if(mViewWidth > 0){
                mPaint = getPaint();
                mLinearGradient = new LinearGradient(0,0,mViewWidth,0,
                        new int[]{Color.BLUE,Color.RED,Color.GREEN},
                        null, Shader.TileMode.CLAMP);//渲染器
                mPaint.setShader(mLinearGradient);
                mGradientMatriX = new Matrix();
            }
        }

    }

其中最关键的就是使用getPaint()方法获取当前绘制TextView的Paint对象,并给这个Paint对象设置原生TextView没有的LinearGradient属性,最后,在onDraw()方法中,通过矩阵的方式来不断平移渐变效果,从而在绘制文字时,产生动态的闪动效果,代码如下:

    @Override
    protected void onDraw(Canvas canvas) {
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容前
        initPaint(canvas);
        super.onDraw(canvas);
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容后

        //用来恢复Canvas旋转、缩放等之后的状态,
        //当和canvas.save( )一起使用时,恢复到canvas.save( )保存时的状态
        canvas.restore();

        if (mGradientMatriX !=null){
            mTranslate += mViewWidth/5;
            if (mTranslate > 2*mViewWidth){
                mTranslate = -mViewWidth;
            }
            mGradientMatriX.setTranslate(mTranslate,0);
            mLinearGradient.setLocalMatrix(mGradientMatriX);
            postInvalidateDelayed(100);
        }
    }

完整代码如下:

public class CustomTextView extends AppCompatTextView {

    Paint mPaint;
    Paint mPaint1;
    Paint mPaint2;
    private int mViewWidth = 0;
    private LinearGradient mLinearGradient;
    private Matrix mGradientMatriX;
    private int mTranslate = 0;

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

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容前
        initPaint(canvas);
        super.onDraw(canvas);
        //在回调父类方法前,实现自己的逻辑,对于TextView来说是在绘制文本内容后
        canvas.restore();

        if (mGradientMatriX !=null){
            mTranslate += mViewWidth/5;
            if (mTranslate > 2*mViewWidth){
                mTranslate = -mViewWidth;
            }
            mGradientMatriX.setTranslate(mTranslate,0);
            mLinearGradient.setLocalMatrix(mGradientMatriX);
            postInvalidateDelayed(100);
        }
    }

    private void initPaint(Canvas canvas){
        mPaint1 = new Paint();
        mPaint1.setColor(getResources().getColor(R.color.colorAccent));
        mPaint1.setStyle(Paint.Style.FILL);

        mPaint2 = new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.FILL);

        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint2);
        //绘制文字前平移10像素
        canvas.translate(10,0);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mViewWidth == 0){
            mViewWidth = getMeasuredWidth();
            if(mViewWidth > 0){
                mPaint = getPaint();
                mLinearGradient = new LinearGradient(0,0,mViewWidth,0,
                        new int[]{Color.BLUE,Color.RED,Color.GREEN},
                        null, Shader.TileMode.CLAMP);//渲染器
                mPaint.setShader(mLinearGradient);
                mGradientMatriX = new Matrix();
            }
        }

    }
}

效果如下:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/zhu522959034/article/details/80733196