Android自定义view学习笔记

1. 重写OnMesure()用于测量view宽度和高度

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    {  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    }

当自定义view设置固定数值或者设置为 MATCH_PARENT时不需要重写OnMesure(),系统测量为屏幕大小。 当设置了WRAP_CONTENT时,我们需要自己进行测量。

1.1 重写前先了解下MeasureSpec的specMode

MeasureSpec的specMode,一共三种类型:
- EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
- AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
- UNSPECIFIED:表示子布局想要多大就多大,很少使用

2. 自定义View

layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.lee.myapp.MyviewActivity">

    <com.example.lee.myapp.MyTextView
        xmlns:my="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="10dp"
        android:text="Title"
        android:textColor="@android:color/holo_orange_dark"
        android:textSize="16sp"
        my:mySubText="subTitle"
        my:mySubTextColor="@android:color/darker_gray"
        my:subMarginTop="10dp"
        my:mySubTextSize="12sp"/>

</RelativeLayout>
attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MyTextView">
        <!--使用android自带语义明确属性 -->
        <attr name="android:text"></attr>
        <attr name="android:textColor"></attr>
        <attr name="android:textSize"></attr>
        <!--自定义个性化属性 -->
        <attr name="mySubText" format="string"></attr>
        <attr name="mySubTextColor" format="color"></attr>
        <attr name="mySubTextSize" format="dimension"></attr>
        <attr name="subMarginTop" format="dimension"></attr>
    </declare-styleable>

</resources>
MyTextView.java

    private String mTitleText, mSubTitleText;//内容文字

    private int mTitleTextColor, mSubTitleTextColor;//内容文本颜色

    private int mTitleTextSize, mSubTitleTextSize;//内容文本大小

    private int subMarginTop;//副标题距主标题margin

    private Rect mBounds, mSubBounds;//文本区域范围
    private Paint mPaint;//画笔
    private Paint mSubPaint;//副标题画笔

    public MyTextView(Context context) {
        super(context);
        init(context, null);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);

        //屏幕密度
        final float density = getResources().getDisplayMetrics().density;

        mTitleText = typedArray.getString(R.styleable.MyTextView_android_text);
        mTitleTextColor = typedArray.getColor(R.styleable.MyTextView_android_textColor, Color.BLACK);
        mTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.MyTextView_android_textSize, (int) (16 * density));

        mSubTitleText = typedArray.getString(R.styleable.MyTextView_mySubText);
        mSubTitleTextColor = typedArray.getColor(R.styleable.MyTextView_mySubTextColor, Color.BLACK);
        mSubTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.MyTextView_mySubTextSize, (int) (12 * density));
        subMarginTop = typedArray.getDimensionPixelSize(R.styleable.MyTextView_subMarginTop, (int) (10 * density));

        typedArray.recycle();

        mPaint = new Paint();
        mPaint.setTextSize(mTitleTextSize);
        mBounds = new Rect();
        //mBound为主标题范围
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBounds);

        mSubPaint = new Paint();
        mSubPaint.setTextSize(mSubTitleTextSize);
        mSubPaint.setColor(mSubTitleTextColor);

        //mSubBounds为副标题范围
        mSubBounds = new Rect();
        mSubPaint.getTextBounds(mSubTitleText, 0, mSubTitleText.length(), mSubBounds);

    }

    @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模式下直接使用系统测量值
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            //主标题
            float textWidth = mBounds.width();
            //副标题
            float textSubWidth = mSubBounds.width();

            int mWidth = (int) (getPaddingLeft() + Math.max(textWidth, textSubWidth) + getPaddingRight());

            width = mWidth;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            //主标题
            float textHeight = mBounds.height();
            //副标题
            float textSubHeight = mSubBounds.height();

            //textHeight + subMarginTop + textSubHeight 内容全部高度
            int mHeight = (int) (getPaddingTop() + (textHeight + subMarginTop + textSubHeight) + getPaddingBottom());

            height = mHeight;
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.YELLOW);
        //测量完后再布局
        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);

        mPaint.setColor(mTitleTextColor);
        canvas.drawText(mTitleText, getWidth() / 2 - mBounds.width() / 2, (getHeight() - subMarginTop) / 2 , mPaint);
        canvas.drawText(mSubTitleText, getWidth() / 2 - mSubBounds.width() / 2,(getHeight() + subMarginTop) / 2 + mSubBounds.height(), mSubPaint);
    }

绘制文本函数:canvas.drawText(“”, x, y, paint);
x:默认是字符的左边在屏幕的位置,如果设置了paint.setTextAlign(Paint.Align.CENTER);那就是字符的中心
y:是指定这个字符baseline在屏幕上的位置

最后

    简单的自定义view就这样实现了。
    自定义View还一个原因是需要适配屏幕,在不同设备上能自动缩放满足要求,接下来加上缩放。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值