Android 自定义View

来源:互联网 发布:java中的构造器是什么 编辑:程序博客网 时间:2024/06/08 16:52

自定义View的步骤:

1、自定义View的属性,布局中使用自定义的View

2、在View的构造方法中获得我们自定义的属性

3、重写onMesure 

4、重写onDraw


一、在values建立一个属性的xml文件attr.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyButton">        <attr name="buttonText" format="string"></attr>        <attr name="buttonTextColor" format="color"></attr>        <attr name="buttonTextSize" format="dimension"></attr>    </declare-styleable></resources>


format的类型:string,color,demension(尺寸),integer,enum,reference(引用),float,boolean,fraction(小数),flag; 


如果该属性可同时传两种不同的属性,则可以用“|”分割开即可。

<attr name="itemBackground" format="reference|color"/>

reference指的是是从别的资源文件下引用过来的flag 位或运算
dimension 指的是是从dimension.xml里引用过来的内容.注意,这里如果是dp那就会做像素转换
只有enum是稍有不同的,例如:
<attr name="testEnum">     <enum name="fill_parent" value="-1"/>     <enum name="wrap_content" value="-2"/> </attr>

在布局文件中使用自定义view
<span style="font-family:SimSun;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:MyButton="http://schemas.android.com/apk/<span style="white-space: pre-wrap;">res-auto</span><span style="white-space: pre-wrap;">"</span>    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">    <com.example.administrator.myapplication.MyButton        android:id="@+id/btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        <span style="white-space: pre-wrap;">MyButton</span>:buttonText="123"/></RelativeLayout></span>

一定要引入
xmlns:MyButton="http://schemas.android.com/apk/com.example.administrator.myapplication"
我们的命名空间,后面的包路径指的是项目的package。xmlns:MyButton中的前缀xmlns固定,MyButton是随便加的,新版Android在Studio改为了
xmlns:MyButton="http://schemas.android.com/apk/res-auto"
二、在View的构造方法中,获得我们的自定义的样式
public class MyButton extends Button{    /**     * 文本     */    private String mButtonText;    /**     * 文本的颜色     */    private int mButtonTextColor;    /**     * 文本的大小     */    private int mButtonTextSize;    /**     * 文本的标志     */    private int mButtonFlag;    public MyButton(Context context) {        this(context,null);    }    public MyButton(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        /**         * 获得我们所定义的自定义样式属性         */        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyButton, defStyleAttr, 0);//        自定义属性计算个数        int n = a.getIndexCount();        for(int i = 0;i < n;i++){            int attr = a.getIndex(i);            switch (attr){                case R.styleable.MyButton_buttonText:                    mButtonText = a.getString(attr);                    break;                case R.styleable.MyButton_buttonTextColor:                    mButtonTextColor = a.getColor(attr,Color.CYAN);                    break;                case R.styleable.MyButton_buttonTextSize:                    // 默认设置为16sp,TypeValue也可以把sp转化为px                    mButtonTextSize =                    a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));                    break;                case R.styleable.MyButton_buttonFlag:                    mButtonFlag = a.getInt(attr,0);                    break;            }        }        a.recycle();        /**         * 获得绘制文本的宽和高         */        Paint mPaint = new Paint();        mPaint.setTextSize(mButtonTextSize);        // mPaint.setColor(mTitleTextColor);        Rect mBound = new Rect();        mPaint.getTextBounds(mButtonText, 0, mButtonText.length(), mBound);    }<pre name="code" class="html">    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onDraw(Canvas canvas)    {        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mButtonTextColor);        canvas.drawText(mButtonText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);    }

}

现在重构了测量宽高onMeasure方法和onDraw方法后既可设置自定义的View等设置,基本的自定义就完成了。但是发现效果并不是预期的效果,原因是宽高的计算有问题,出在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;        int height ;//        EXACTLY:一般是设置了明确的值或者是MATCH_PARENT////        AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT////        UNSPECIFIED:表示子布局想要多大就多大        if (widthMode == MeasureSpec.EXACTLY)        {            width = widthSize;        } else        {            mPaint.setTextSize(mButtonTextSize);            mPaint.getTextBounds(mButtonText, 0, mButtonText.length(), mBound);            float textWidth = mBound.width();            int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());            width = desired;        }        if (heightMode == MeasureSpec.EXACTLY)        {            height = heightSize;        } else        {            mPaint.setTextSize(mButtonTextSize);            mPaint.getTextBounds(mButtonText, 0, mButtonText.length(), mBound);            float textHeight = mBound.height();            int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());            height = desired;        }        setMeasuredDimension(width, height);    }    @Override    protected void onDraw(Canvas canvas)    {        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mButtonTextColor);        canvas.drawText(mButtonText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);    }

getMeasuredWidth()表示控件的宽度
getWidth() 表示控件在父控件的右边x坐标减去左边x坐标的值,大部分情况下是相等的

有一点需要注意的是自定义如果是Text时的坐标问题。(x,y) for bitmaps is top-left, (x,y) for text is lower-left.

即bitmaps的坐标起始为view的左上角,而text和其他view有所区别为左下角


0 0