Android 自定义控件学习之一 基础知识



基本实现 步骤

             

1、自定义View的属性

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

[ 3、重写onMesure ]

4、重写onDraw

在最新的andriod studio 中,选择自定义空间,它会生成相应的attr 文件,布局文件,属性实现文件,通过这三个文件,我们就可以设计自己的控件。


<resources>
    <declare-styleable name="MyTextView">
        <attr name="codeString" format="string" />
        <attr name="codeDimension" format="dimension" />
        <attr name="codeColor" format="color" />
        <attr name="codeDrawable" format="color|reference" />
    </declare-styleable>
</resources>

我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:

一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。

然后在布局中声明我们的自定义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:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context="com.selftextview.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:id="@+id/codes_linear">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/codes"
                android:hint="@string/codes"
                android:textSize="21sp"/>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:weightSum="1">

            <com.selftextview.MyTextView
                android:layout_width="match_parent"
                android:layout_height="58dp"
                android:background="#c1c7c3"
                app:codeColor="#33b5e5"
                app:codeDimension="24sp"
                app:codeString="@string/codes"
             />

        </LinearLayout>

    </LinearLayout>

    <Button
        android:layout_below="@id/codes_linear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sureBtn"
        android:text="@string/sure"
        />

</RelativeLayout>
2、在View的构造方法中,获得我们的自定义的样式

<span style="color:#555555;">    private Paint paint = new Paint();
    /**
     * 验证码内容
     */
    private String[] content = null;
    /**
     * 验证码图片
     */
    private Bitmap bitmap = null;


    private String mCodeString;
    private int mCodeColor = Color.RED;
    private float mCodeDimension = 0;
    private Drawable mCodeDrawable;

    private TextPaint mTextPaint;
    private float mTextWidth;
    private float mTextHeight;

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

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

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

    private void init(AttributeSet attrs, int defStyle) {
        // Load attributes
        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.MyTextView, defStyle, 0);

        //mCodeString = a.getString(
        //        R.styleable.MyTextView_codeString);

        mCodeString = randomText();

        mCodeColor = a.getColor(
                R.styleable.MyTextView_codeColor,
                mCodeColor);
        // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
        // values that should fall on pixel boundaries.
        mCodeDimension = a.getDimension(
                R.styleable.MyTextView_codeDimension,
                mCodeDimension);

        if (a.hasValue(R.styleable.MyTextView_codeDrawable)) {
            mCodeDrawable = a.getDrawable(
                    R.styleable.MyTextView_codeDrawable);
            mCodeDrawable.setCallback(this);
        }

        a.recycle();

        // Set up a default TextPaint object
        mTextPaint = new TextPaint();
        mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextAlign(Paint.Align.LEFT);

        invalidateTextPaintAndMeasurements();

        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mCodeString = randomText();
                postInvalidate();  /</span><span style="color:#ff6666;">/通过这个方法重新绘制</span><span style="color:#555555;">
            }
        });
    }</span>

3.绘制该View
   private void invalidateTextPaintAndMeasurements() {
        mTextPaint.setTextSize(mCodeDimension);
        mTextPaint.setColor(mCodeColor);
        mTextWidth = mTextPaint.measureText(mCodeString);

        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
        mTextHeight = fontMetrics.bottom;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // allocations per draw cycle.
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int contentWidth = getWidth() - paddingLeft - paddingRight;
        int contentHeight = getHeight() - paddingTop - paddingBottom;

        // Draw the text.
        canvas.drawText(mCodeString,
                paddingLeft + (contentWidth - mTextWidth) / 2,
                paddingTop + (contentHeight + mTextHeight) / 2,
                mTextPaint);

        // Draw the example drawable on top of the text.
        if (mCodeDrawable != null) {
            mCodeDrawable.setBounds(paddingLeft, paddingTop,
                    paddingLeft + contentWidth, paddingTop + contentHeight);
            mCodeDrawable.draw(canvas);
        }


    }

4.关于onmeasure 的相关介绍
     把布局文件的宽和高写成wrap_content ,会发生铺满全屏的现象。

这里是鸿洋大神写的解释

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:

重写之前先了解MeasureSpec的specMode,一共三种类型:

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

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

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

下面是我们重写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 ;
		if (widthMode == MeasureSpec.EXACTLY)
		{
			width = widthSize;
		} else
		{
			mPaint.setTextSize(mTitleTextSize);
			mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
			float textWidth = mBounds.width();
			int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
			width = desired;
		}

		if (heightMode == MeasureSpec.EXACTLY)
		{
			height = heightSize;
		} else
		{
			mPaint.setTextSize(mTitleTextSize);
			mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
			float textHeight = mBounds.height();
			int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
			height = desired;
		}
		
		

		setMeasuredDimension(width, height);
	}

通过上面的实现可以实现文字的wrap_conent







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值