使用 Android Studio自定义View01——注意是否重写onMeasure的区别,实现真正的自适应布局

来源:互联网 发布:淘宝油画 莫奈的花园 编辑:程序博客网 时间:2024/06/05 15:23

整理并总结自鸿洋的博客:http://blog.csdn.net/lmj623565791/article/details/24252901

一、不重写onMeasure,在res/layout/activity_main.xml中限定view的高度和宽度

com.cctvjiatao.customview01.act.MainActivity.java

/** * 自定义View 第一课 *  1、自定义View的属性 *  2、在View的构造方法中获得第1步中的自定义属性 *  3、重写onMeasure(这一步可省略) *  4、重写onDraw */public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="title" format="string"/>    <attr name="titleColor" format="color"/>    <attr name="titleSize" format="dimension"/>    <declare-styleable name="AuthCode">        <attr name="title"/>        <attr name="titleColor"/>        <attr name="titleSize"/>    </declare-styleable></resources>

res/layout/activity_main.xml

<?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:authcode="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".act.MainActivity">    <com.cctvjiatao.customview01.view.AuthCode        android:layout_width="200dp"        android:layout_height="100dp"        authcode:title="9527"        authcode:titleColor="#ff0000"        authcode:titleSize="40sp" /></RelativeLayout>


注意:在Android Studio中,使用的是xmlns:authcode="http://schemas.android.com/apk/res-auto",而在Eclipse中则应该使用xmlns:authcode="http://schemas.android.com/apk/res/com.cctvjiatao.customview01",即在res后的路径指向项目的package。


com.cctvjiatao.customview01.view.AuthCode.java

class AuthCode extends View {    private String mTitle;    private int mTitleColor;    private int mTitleSize;    private Rect mBound;    private Paint mPaint;    public AuthCode(Context context) {        this(context, null);    }    public AuthCode(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        /*        获得自定义属性         */        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0);        int a = typedArray.getIndexCount();        for (int i = 0; i < a; i++) {            int attr = typedArray.getIndex(i);            switch (attr) {                case R.styleable.AuthCode_title:                    mTitle = typedArray.getString(attr);                    break;                case R.styleable.AuthCode_titleColor:                    mTitleColor = typedArray.getColor(attr, Color.BLACK);                    break;                case R.styleable.AuthCode_titleSize:                    mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));                    break;            }        }        typedArray.recycle();        /*        获得绘制的区域         */        mPaint = new Paint();        mPaint.setTextSize(mTitleSize);        mBound = new Rect();        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);    }    /**     * 调用系统的onMeasure,没有重写     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    /**     * 重写onDraw     */    @Override    protected void onDraw(Canvas canvas) {        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mTitleColor);        canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);    }}


程序运行结果如图:

二、不重写onMeasure,在res/layout/activity_main.xml中自适应view的高度和宽度

修改res/layout/activity_main.xml代码如下:

<?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:authcode="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".act.MainActivity">    <com.cctvjiatao.customview01.view.AuthCode        android:layout_width="wrap_content"        android:layout_height="wrap_content"        authcode:title="9527"        authcode:titleColor="#ff0000"        authcode:titleSize="40sp" /></RelativeLayout>

注意:把高度和宽度都修改成了 wrap_content

程序运行结果如图:


为什么会铺满全屏,而不是自适应文本的大小呢?系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。


三、重写onMeasure,在res/layout/activity_main.xml中自适应view的高度和宽度,但不允许铺满全屏,实现真正的自适应

当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”,重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT;

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT;

UNSPECIFIED:表示子布局想要多大就多大,很少使用;


在二的基础上继续修改com.cctvjiatao.customview01.view.AuthCode.java

package com.cctvjiatao.customview01.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import com.cctvjiatao.customview01.R;/** * Created by jiatao on 2016/6/4. */class AuthCode extends View {    private String mTitle;    private int mTitleColor;    private int mTitleSize;    private Rect mBound;    private Paint mPaint;    public AuthCode(Context context) {        this(context, null);    }    public AuthCode(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        /*        获得自定义属性         */        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0);        int a = typedArray.getIndexCount();        for (int i = 0; i < a; i++) {            int attr = typedArray.getIndex(i);            switch (attr) {                case R.styleable.AuthCode_title:                    mTitle = typedArray.getString(attr);                    break;                case R.styleable.AuthCode_titleColor:                    mTitleColor = typedArray.getColor(attr, Color.BLACK);                    break;                case R.styleable.AuthCode_titleSize:                    mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));                    break;            }        }        typedArray.recycle();        /*        获得绘制的区域         */        mPaint = new Paint();        mPaint.setTextSize(mTitleSize);        mBound = new Rect();        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);    }    /**     * 重写onMeasure     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int width, height;        if (widthMode == MeasureSpec.EXACTLY) {            width = widthSize;        } else {            mPaint.setTextSize(mTitleSize);            mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);            width = (int) (getPaddingLeft() + mBound.width() + getPaddingRight());        }        if (heightMode == MeasureSpec.EXACTLY) {            height = heightSize;        } else {            mPaint.setTextSize(mTitleSize);            mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);            height = (int) (getPaddingTop() + mBound.height() + getPaddingBottom());        }        setMeasuredDimension(width, height);    }    /**     * 重写onDraw     */    @Override    protected void onDraw(Canvas canvas) {        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mTitleColor);        canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);    }}

程序运行结果如图:


如果想美化显示,则修改res/layout/activity_main.xml即可,比如添加padding、居中等属性

继续修改res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:authcode="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".act.MainActivity">    <com.cctvjiatao.customview01.view.AuthCode        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:padding="20dp"        authcode:title="9527"        authcode:titleColor="#ff0000"        authcode:titleSize="40sp" /></RelativeLayout>

程序运行结果如图:



四、增加view的点击事件,使随机生成验证码

在三的基础上继续修改com.cctvjiatao.customview01.view.AuthCode.java

class AuthCode extends View {    private String mTitle;    private int mTitleColor;    private int mTitleSize;    private Rect mBound;    private Paint mPaint;    public AuthCode(Context context) {        this(context, null);    }    public AuthCode(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        /*        获得自定义属性         */        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0);        int a = typedArray.getIndexCount();        for (int i = 0; i < a; i++) {            int attr = typedArray.getIndex(i);            switch (attr) {                case R.styleable.AuthCode_title:                    mTitle = typedArray.getString(attr);                    break;                case R.styleable.AuthCode_titleColor:                    mTitleColor = typedArray.getColor(attr, Color.BLACK);                    break;                case R.styleable.AuthCode_titleSize:                    mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));                    break;            }        }        typedArray.recycle();        /*        获得绘制的区域         */        mPaint = new Paint();        mPaint.setTextSize(mTitleSize);        mBound = new Rect();        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);        /*        添加点击事件         */        this.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                mTitle = randomTitle();                postInvalidate();            }        });    }    /**     * 随机生成验证码     */    private String randomTitle() {        Random random = new Random();        Set<Integer> set = new HashSet<Integer>();        while (set.size() < 4) {            int i = random.nextInt(10);            set.add(i);        }        StringBuffer sb = new StringBuffer();        for (Integer i : set) {            sb.append(i + "");        }        return sb.toString();    }    /**     * 重写onMeasure     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int width, height;        if (widthMode == MeasureSpec.EXACTLY) {            width = widthSize;        } else {            mPaint.setTextSize(mTitleSize);            mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);            width = (int) (getPaddingLeft() + mBound.width() + getPaddingRight());        }        if (heightMode == MeasureSpec.EXACTLY) {            height = heightSize;        } else {            mPaint.setTextSize(mTitleSize);            mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound);            height = (int) (getPaddingTop() + mBound.height() + getPaddingBottom());        }        setMeasuredDimension(width, height);    }    /**     * 重写onDraw     */    @Override    protected void onDraw(Canvas canvas) {        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mTitleColor);        canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);    }}


程序运行结果如图:


0 0
原创粉丝点击