自定义View并自定义其属性学习小Demo

最近在看徐老师的《Android群英传》,里面有一章是讲的如何自定义View,之前一直觉得自定义挺复杂的,感觉像座大山一直压在自己的Android之路上,看了书中讲解之后,发现原来一直神秘的自定义View也没那么神秘,下面就和我一起来通过一个简单的小Demo一起来体验一下吧。

重写TextView实现一个简单的动态渐变效果的TextView

首先讲一下思路和知识准备,实现渐变需要使用到一个渲染对象LinearGradient,只有一个渲染对象还不行,因为这样知识一个静态的效果,要实现动态还需要一个矩阵位移对象Matrix。

1、首先我们重写View的onSizeChanged方法,在里面执行一些初始化的操作,比如为TextView的Paint画笔对象设置渲染对象等,代码如下:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // 初始化操作
    if (mViewWidth == 0) {
        // 设置自定义textview的宽度值
        mViewWidth = getMeasuredWidth();
        if (mViewWidth > 0) {
            // 获取到TextView的paint对象
            mPaint = getPaint();
            // 设置自定义的线性渲染
            // CLAMP重复最后一个颜色至最后
            // MIRROR重复着色的图像水平或垂直方向已镜像方式填充会有翻转效果
            // REPEAT重复着色的图像水平或垂直方向
            mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, new int[]{colorOne, colorTwo, colorThree}, null, Shader.TileMode.CLAMP);
            // 为textview的paint设置渲染器
            mPaint.setShader(mLinearGradient);
            // 初始化全局矩阵
            mGradientMatrix = new Matrix();
        }
    }
}

2、重写onDraw方法,在里面实现动态的渐变效果,代码如下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mGradientMatrix != null) {
        // 每次执行一次,就将偏移增加一个值
        mTranslate += mViewWidth / 5;
        Log.e("gu", "mTranslate==>" + mTranslate);
        // 如果偏移值大于了两倍的textview宽度,则将偏移值置为-mViewWidth
        if (mTranslate > 2 * mViewWidth) {
            mTranslate = -mViewWidth;
        }
        // 为矩阵设置偏移
        mGradientMatrix.setTranslate(mTranslate, 0);
        // 为渲染器加上偏移矩阵
        mLinearGradient.setLocalMatrix(mGradientMatrix);
        // 设置延迟重新提交绘制View
        postInvalidateDelayed(delayTime);
    }
}

3、我们有时也需要自定义一些属性,使我们的控件用起来更加的人性化,这个其实也简单,首先在values目录下新建一个attrs.xml文件,然后在里面自定义一些自定义控件想要的属性:

<declare-styleable name="CustomTextViewTwo">
    <attr name="shaperColorOne" format="color"></attr>
    <attr name="shaperColorTwo" format="color"></attr>
    <attr name="shaperColorThree" format="color"></attr>
    <attr name="delayTime" format="integer"></attr>
</declare-styleable>

4、设置好上面的属性列表之后,就可以在布局文件中使用上面的参数了,只不过要先加一个命名空间xmlns:app="http://schemas.android.com/apk/res-auto",这样编译器就可以找到我们自己定义的属性了:

<com.gu.customviewtest.CustomTextViewTwo
    android:layout_width="100dp"
    android:layout_height="50dp"
    android:gravity="center"
    android:text="我是测试的文字"
    app:delayTime="1000"
    app:shaperColorOne="#cc0e0e"
    app:shaperColorThree="#cc0e0e"
    app:shaperColorTwo="#f6d605" />

5、现在万事具备,只欠东风了,我们还要在自定义View的构造器中,获取到上面xml布局中设置的这些属性值:

private void init(Context context, AttributeSet attrs) {
    //获取到ta对象
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomTextViewTwo);
    //从ta对象中,获取到xml中对象属性配置值
    colorOne = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorOne, Color.BLACK);
    colorTwo = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorTwo, Color.BLACK);
    colorThree = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorThree, Color.BLACK);
    delayTime = ta.getInteger(R.styleable.CustomTextViewTwo_delayTime, 100);
    //TypeArray 对象用完以后必须得回收
    ta.recycle();
}

6、至此,整个一个简单的自定义View代码就实现了,下面我贴一下完整的代码供大家参考:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

/**
 * Created by Nate on 2015/10/22.
 */
public class CustomTextViewTwo extends TextView {

private int mViewWidth = 0;
private Paint mPaint;
private LinearGradient mLinearGradient;
private Matrix mGradientMatrix;
private int mTranslate;
private int colorOne;
private int colorTwo;
private int colorThree;
private int delayTime;

/**
 * 在java代码创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个
 *
 * @param context
 */
public CustomTextViewTwo(Context context) {
    super(context);
}

/**
 * 这个是在xml创建但是没有指定style的时候被调用
 *
 * @param context
 * @param attrs
 */
public CustomTextViewTwo(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
}

/**
 * 这个是在xml创建,并且指定style的时候被调用
 *
 * @param context
 * @param attrs
 * @param defStyleAttr
 */
public CustomTextViewTwo(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
}

private void init(Context context, AttributeSet attrs) {
    //获取到ta对象
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomTextViewTwo);
    //从ta对象中,获取到xml中对象属性配置值
    colorOne = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorOne, Color.BLACK);
    colorTwo = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorTwo, Color.BLACK);
    colorThree = ta.getColor(R.styleable.CustomTextViewTwo_shaperColorThree, Color.BLACK);
    delayTime = ta.getInteger(R.styleable.CustomTextViewTwo_delayTime, 100);
    //TypeArray 对象用完以后必须得回收
    ta.recycle();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // 初始化操作
    if (mViewWidth == 0) {
        // 设置自定义textview的宽度值
        mViewWidth = getMeasuredWidth();
        if (mViewWidth > 0) {
            // 获取到TextView的paint对象
            mPaint = getPaint();
            // 设置自定义的线性渲染
            // CLAMP重复最后一个颜色至最后
            // MIRROR重复着色的图像水平或垂直方向已镜像方式填充会有翻转效果
            // REPEAT重复着色的图像水平或垂直方向
            mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, new int[]{colorOne, colorTwo, colorThree}, null, Shader.TileMode.CLAMP);
            // 为textview的paint设置渲染器
            mPaint.setShader(mLinearGradient);
            // 初始化全局矩阵
            mGradientMatrix = new Matrix();
        }
    }
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mGradientMatrix != null) {
        // 每次执行一次,就将偏移增加一个值
        mTranslate += mViewWidth / 5;
        Log.e("gu", "mTranslate==>" + mTranslate);
        // 如果偏移值大于了两倍的textview宽度,则将偏移值置为-mViewWidth
        if (mTranslate > 2 * mViewWidth) {
            mTranslate = -mViewWidth;
        }
        // 为矩阵设置偏移
        mGradientMatrix.setTranslate(mTranslate, 0);
        // 为渲染器加上偏移矩阵
        mLinearGradient.setLocalMatrix(mGradientMatrix);
        // 设置延迟重新提交绘制View
        postInvalidateDelayed(delayTime);
    }
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值