自定义View学习

Hongyang自定义View学习笔记总结

Hongyang原文地址:http://blog.csdn.net/lmj623565791/article/details/24252901

  1. 自定义View的属性
  2. 在View的构造方法中获得我们自定的属性
  3. 重写onDraw和onMesure方法
1、自定义View的属性,首先在res/values/文件夹下建立一个attrs.xml ,
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="titleText" format="string"/>
    <attr name="titleTextColor" format="color"/>
    <attr name="titleTextSize" format="dimension"/>

    <declare-styleable name="CustomTitleView">
        <attr name="titleText"/>
        <attr name="titleTextColor"/>
        <attr name="titleTextSize"/>
    </declare-styleable>
</resources>

attr属性的意思,attribute的缩写;format定义属性类型;attr不依赖styleable,styleable只是为了方便attr的使用。我们自己定义的属性也可不放在styleable中,可以直接定义一些属性

attr和styleable的关系

attr不依赖styleable,styleable只是为了方便attr的使用。我们自己定义的属性也可不放在styleable中,可以直接定义一些属性而不使用styleable:

    <attr name="titleText" format="string"/>
    <attr name="titleTextColor" format="color"/>
    <attr name="titleTextSize" format="dimension"/>

此时定义一个attr就会在R文件中生成一个Id,如果需要获取这些属性时必须调用如下代码:

  /**
     * 获取我们所定义的自定义属性
     */    
 int[] custom_attrs = {R.attr.titleText,
                      R.attr.titleTextColor,
                      R.attr.titleTextSize};
TypedArray typedArray = context.obtainStyledAttributes(set,custom_attrs);

如果定义一个styleable,我们可以在R文件中自动生成一个int[],数组里面的int就是定义在styleable里面的attr的id。所以我们在获取属性的时候就可以直接使用styleable数组来获取一系列的属性会比较方便一点。

    <declare-styleable name="CustomTitleView">
        <attr name="titleText"/>
        <attr name="titleTextColor"/>
        <attr name="titleTextSize"/>
    </declare-styleable>
</resources>

获取:

    /**
     * 获取我们所定义的自定义属性
     */
    TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.CustomTitleView, defStyleAttr, 0);

定义一个declare-styleable,在获取属性的时候为我们自动提供了一个属性数值。此外,我觉得使用declare-styleable的方式有利于我们我们把相关的属性组织起来,有一个分组的概念,属性的使用范围更加明确。

在布局中声明自定义的View

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.duxinwu.myview.MainActivity">

<com.example.duxinwu.myview.CustomTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
</RelativeLayout>

注意:一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”
之前在Hongyang博客中是这样引入xmlns:custom=”http://schemas.android.com/apk/res/com.example.customview01但是你会发现在Android Studio中报错,Gradle使用res-auto自动导入代替了com.example.customview01使得我们编写代码更加方便。

其中custom是自己定义的,你也可以根据自己的喜好定义

2.在View的构造方法中获得我们自定的属性
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    /**
     * 获取我们所定义的自定义属性
     */
    TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.CustomTitleView, defStyleAttr, 0);
    int n = array.getIndexCount();
    for (int i = 0; i < n; i++) {
        int attr = array.getIndex(i);
        switch (attr) {
            case R.styleable.CustomTitleView_titleText:
                mTitleText = array.getString(attr);
                break;
            case R.styleable.CustomTitleView_titleTextColor:
                mTitleTextColor=array.getColor(attr, Color.BLACK);
                break;
            case R.styleable.CustomTitleView_titleTextSize:
                mTitleTextSize=array.getDimensionPixelSize(attr,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,
                                getResources().getDisplayMetrics()));
                break;
            default:
                break;
        }
    }
    array.recycle();
    initView();
}
private void initView() {
    /**
     * 获取绘制文本的宽和高
     */
    mPaint=new Paint();
    mPaint.setTextSize(mTitleTextSize);
    mBound=new Rect();
    mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);

    this.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            mTitleText=randomText();
            postInvalidate();
        }
    });
}
  • TypedArray:存储了从obtainStyledAttributes(AttributeSet, int[], int, int) or obtainAttributes(AttributeSet, int[])检索出值。确保在使用结束后调用recycle()方法回收。其实是用来简化我们的工作的,如果布局中的属性的值是引用类型(比如:@dimen/dp100),如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程
  • obtainStyledAttributes:获取样式属性
3.重写onDraw和onMesure方法

onDraw方法:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.YELLOW);
    canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);

    mPaint.setColor(mTitleTextColor);
    canvas.drawText(mTitleText,getWidth()/2-mBound.width()/2,getHeight()/2+mBound.height()/2,mPaint);
}

onMesure方法:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthMode=MeasureSpec.getMode(widthMeasureSpec);
    int widthSize=MeasureSpec.getSize(widthMeasureSpec);
    int heightMode=MeasureSpec.getMode(heightMeasureSpec);
    int heightSize=MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;
    if (widthMode==MeasureSpec.EXACTLY){
        width=widthSize;
    }else {
        float textWidth=mBound.width();
        int desired= (int) (getPaddingLeft()+mBound.width()+getPaddingRight());
        width=desired;

    }
    if (heightMode==MeasureSpec.EXACTLY){
        height=heightSize;
    }else{
        float textHeight=mBound.height();
        int desired= (int) (getPaddingTop()+mBound.height()+getPaddingBottom());
        height=desired;
    }
    setMeasuredDimension(width,height);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值