Android 自定义View学习(1)

本文介绍如何自定义一个简单的TextView,并详细解释了定义控件属性、构造方法、重写onMeasure和onDraw方法的过程。还展示了如何在布局文件中使用自定义控件,并提供了拓展功能的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如标题所见,最近我自己在网上看了很多资料来学习自定义控件。。自定义View对很多人来说还是有些难度的,我希望我的博客能帮助到一些人,这样写的话对自己巩固知识也有很大的帮助,我们先来总结一下自定义View的步骤。


1,考虑清楚自己的控件需要做到什么事情需要什么属性,如自定义一个圆形滚动条需要考虑颜色,速度,指定进度等


2,在自己的构造方法中获得这些属性


3,有些情况需要考虑重写onMeasure方法来确定控件大小,如使用wrap_content时


4,绘制出来自己需要的样子


今天我们首先来定义一个简单的控件,就像简易的TextView,参照上面的四个步骤我们可以开始代码之旅了


1, Textview需要什么属性,我擦类,肯定是要能显示字体,然后可以改变字体颜色,设定字体大小,还可以改变背景色,那么我们首先就在res/values下面新建一个attrs.xml文件

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

    <attr name="text" format="string" />
    <attr name="textColor" format="color" />
    <attr name="textSize" format="dimension" />

    <declare-styleable name="ViewText">
        <attr name="text" />
        <attr name="textColor" />
        <attr name="textSize" />
    </declare-styleable>

</resources>

上面我定义了三个属性,一个是要显示的text一个是textColor还有一个是textSize.

format是对应属性名的格式总共有:


1. reference:参考某一资源ID,以此类推

2. color:颜色值

3. boolean:布尔值

4. dimension:尺寸值。注意,这里如果是dp那就会做像素转换

5. float:浮点值。

6. integer:整型值。

7. string:字符串

8. fraction:百分数。

9. enum:枚举值

10. flag:是自己定义的,类似于 android:gravity="top",就是里面对应了自己的属性值。

11. reference|color:颜色的资源文件。
12. reference|boolean布尔值的资源文件


接下来在我们布局文件中使用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:wrh="http://schemas.android.com/apk/res/com.example.viewtext"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.viewtext.ViewText
        android:id="@+id/view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="106dp"
        android:padding="10dp"
        wrh:text="自定义Text"
        wrh:textColor="#ff0000"
        wrh:textSize="20sp" />

   

</RelativeLayout>

一定要在最外层布局中写 xmlns:wrh="http://schemas.android.com/apk/res/com.example.viewtext",后面com.xxxx是我们的包名


2,在我们的构造方法中获得这些属性

	/**
	 * 需要显示的Text
	 */
	private String mText;
	/**
	 * 字体颜色
	 */
	private int mTextColor;
	/**
	 * 字体大小
	 */
	private int mTextSize;
	/**
	 * 绘制区域
	 */
	private Rect mRect;
	/**
	 * 画笔
	 */
	private Paint mPaint;
	private final String TAG = "ViewText";

	public ViewText(Context context) {
		this(context, null);
		// TODO Auto-generated constructor stub
	}

	public ViewText(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		// TODO Auto-generated constructor stub
	}

	public ViewText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// 获得我们在attrs里面声明的属性
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.ViewText, defStyle, 0);

		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			case R.styleable.ViewText_text:
				mText = a.getString(attr);
				break;
			case R.styleable.ViewText_textColor:
				// 默认为蓝色
				mTextColor = a.getColor(attr, Color.BLUE);
				break;
			case R.styleable.ViewText_textSize:
				// 字体大小
				mTextSize = a.getDimensionPixelSize(attr, R.dimen.text_size);
				break;
			default:
				break;
			}
		}
		// 回收
		a.recycle();
		mPaint = new Paint();
		mPaint.setTextSize(mTextSize);
		mRect = new Rect();
		// 获得字体需要多大地方显示
		mPaint.getTextBounds(mText, 0, mText.length(), mRect);
	}


3,需不需要重写onMeasure方法,首先我们需要了解MeasureSpec的specMode,一共三种类型:

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

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

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

也就是说如果我们明确了大小的话是没有问题的,但是我们如果是把大小设为wrap_content,系统会自动把大小设为match_parent。

所以这种情况我们还是重写onMeasure方法

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 获得宽度大小以及mode
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		// 获得长度大小以及mode
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		// 最终确定的大小
		int width;
		int height;
		// 如果宽度是显示的指定了可以直接赋值
		if (widthMode == MeasureSpec.EXACTLY) {
			width = widthSize;
		} else {
			// 获得控件自适应的大小
			mPaint.setTextSize(mTextSize);
			mPaint.getTextBounds(mText, 0, mText.length(), mRect);
			float textWidth = mRect.width();
			int width2 = (int) (getPaddingLeft() + textWidth + getPaddingRight());
			width = width2;
		}
		if (heightMode == MeasureSpec.EXACTLY) {
			height = heightSize;
		} else {
			mPaint.setTextSize(mTextSize);
			mPaint.getTextBounds(mText, 0, mText.length(), mRect);
			float textHeight = mRect.height();
			int height2 = (int) (getPaddingTop() + textHeight + getPaddingBottom());
			height = height2;
		}
		//设置控件大小
		setMeasuredDimension(width, height);
	}

4,最关键的绘制了,重写onDraw方法:

	@Override
	protected void onDraw(Canvas canvas) {
		//默认背景为白色
		mPaint.setColor(Color.WHITE);
		//绘制显示区域
		canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
		//字体颜色
		mPaint.setColor(mTextColor);
		//绘制字体居中
		canvas.drawText(mText, getWidth() / 2 - mRect.width() / 2, getHeight()
				/ 2 + mRect.height() / 2, mPaint);

	}




效果也是很让人满意的,现在我们可以拓展一下,比如点击按钮字体变色?

public void setChangeColor(int color) {
		mTextColor = color;
		invalidate();
	}
ViewText viewText;
	Button button;
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		viewText=(ViewText)findViewById(R.id.view1);
		button=(Button)findViewById(R.id.button1);
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				viewText.setChangeColor(Color.BLUE);
				
			}
		});
	}




项目源码

       

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值