Android 自定义View(基础)

一,为什么要自定义View

android原生控件基本上可以满足我们简易APP界面设计需求了,在随着APP越来越复杂,android系统提供的控件已无法满足我们的需求,于是自定义View闪亮登场!!

二,如何自定义View

自定义控件的实现有三种方式,分别是:组合控件、自绘控件和继承控件。今天我就写写如何自绘控件,另外两个在此就不写了。

在自定义view的时候,其实很简单,只需要知道4步骤:

1.属性--自定义View属性。

2.测量--onMeasure():决定View的大小。

3.布局--onLayout():决定View在ViewGroup中的位置。

4.绘制--onDraw():如何绘制这个View。

废话不多说,直接来个亲密接触!!,我们就来个简单的,自定义TextView》》》MyTextView

一,自定义View的属性,我们可以在Values文件夹下面创建attrs.xml文件,样式如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="titleTextColor" format="color"/>
    <attr name="titleTextSize"  format="dimension"/>
    <attr name="titleTextString"  format="string"/>
    <declare-styleable name="customTitleView">
        <attr name="titleTextColor"/>
        <attr name="titleTextSize"/>
        <attr name="titleTextString"/>
    </declare-styleable>
</resources>

我分别定义了3个属性:字体颜色、字体大小、字体文本。 format为属性格式,还有其他格式:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;具体的可以根据自己的需求定义。

二,我们自定义一个TextView。

public class MyTextView extends View {

    private String mTitleText;
    /**
     * 文本的颜色
     */
    private int mTitleTextColor;
    /**
     * 文本的大小
     */
    private int mTitleTextSize;

    private Paint mPaint;
    private Rect mBound;

    public MyTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyTextView(Context context) {
        this(context, null);
    }

    public MyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        /**
         * 获得我们所定义的自定义样式属性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.customTitleView, defStyle, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.customTitleView_titleTextString:
                    mTitleText = a.getString(attr);
                    break;
                case R.styleable.customTitleView_titleTextColor:
                    // 默认颜色设置为黑色
                    mTitleTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.customTitleView_titleTextSize:
                    // 默认设置为16sp,TypeValue也可以把sp转化为px
                    mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;

            }

        }
        a.recycle();
        mPaint=new Paint();
        //先设置字体大小(在没有设置字体区域大小时,可以根据字体大小获取字体区域大小)
        mPaint.setTextSize(mTitleTextSize);
        mBound = new Rect();//字体区域
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int width = 0;
        int height = 0;

        /**
         * 设置宽度 获得控件View的宽度。如果xml里面设置了宽度为match_parent或具体的宽度,
         * 则该控件的宽度就是match_parent或具体的宽度。如果设置宽度WARP_CONTENT,
         * 则控件宽度就是控件区域本身宽度
         */
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (specMode)
        {
            case MeasureSpec.EXACTLY:// 明确指定了大小  match_parent或具体大小如20dp
                width = getPaddingLeft() + getPaddingRight() + specSize;
                break;
            case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
                width = getPaddingLeft() + getPaddingRight() + mBound.width();
                break;
        }

        /**
         * 设置高度
         */
        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        switch (specMode)
        {
            case MeasureSpec.EXACTLY:// 明确指定了match_parent或具体大小如20dp
                height = getPaddingTop() + getPaddingBottom() + specSize;
                break;
            case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
                height = getPaddingTop() + getPaddingBottom() + mBound.height();
                break;
        }

        setMeasuredDimension(width, height);

    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        //绘一个矩形背景为蓝色,大小看onMeasure方法
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);

        //绘字,字为区域中心
        mPaint.setColor(mTitleTextColor);
        canvas.drawText(mTitleText, getWidth() / 2-mBound.width()/2 , getHeight() / 2+mBound.height()/2 , mPaint);
    }
}


是不是很简单?哈哈,一般人都能看懂,除非,你是大神,不屑看。。。

三,在布局中声明我们的自定义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">

    <pw.onlyou.testapplication.MyTextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        custom:titleTextColor="#ff0000"
        custom:titleTextSize="30dp"
        custom:titleTextString="Hello Word!"/>
    
</RelativeLayout>

来看运行效果,是不是丑?不要太在意这些。。


在此,肯定有人说,册那,这个和原生TextView有啥区别?

下一节讲解 自定义动画

文章目前仍在更新中,如果你觉得我的文章有错误或者纰漏,欢迎指正,另外,如果你觉得有用的话,点个赞呗。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值