带你一起瞧瞧自定义属性以及自定义View的使用

       都说Android技术博大精深,Android控件强大无比,想想也确实如此。随着Android的不断发展,Android控件日趋强大以及完善化。But,有些还是满足不了公司多变的需求。遇到这种情况,咋办?凉拌,我们只能自定义一些自定义控件了。今天就和大家一起来聊聊自定义属性以及自定义控件的使用。开始之前我们来看看下面的效果。



               效果图

        看到这效果图有啥想法,心里会不会有点放烟花的节奏.....so easy。看到这图,想必你心中肯定已经闪过无数的实现方式。那,怎么用自定义View的方式来实现呢?有人说先画个背景Bitmap圆,然后在圆上画上Text就Ok啦,还有人说直接自定义一个CircleTextView就Ok了。当然条条大路通罗马,Just like it。这里选择自定义CirlceTextView作为Demo来说明自定义View属性以及自定义View的使用。好费话不多说,下面开始正式介绍。自定义CircleTextView主要有下面几个步骤:

1.自定义属性

2.自定义View中获取自定义属性

3.添加控制自定义属性的条件

4.在layout中添加自定义控件以及自定义属性


下面分别从这四个方面来介绍自定义属性以及自定义View的使用。


1.自定义属性

自定义属性首先在values文件加下,新建一attrs.xml文件,其具体的代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <declare-styleable name="CircleTextView">
    <attr name="text" format="string|reference" />
    <attr name="textColor" format="color|reference" />
    <attr name="textSize" format="dimension|reference" />
    <attr name="bacground" format="color|reference" />
    <attr name="radius" format="dimension" />
       </declare-styleable>
 <!--    <declare-styleable name="CircleTextView">
    <attr name="text"  />
    <attr name="textColor" />
    <attr name="textSize"  />
    <attr name="bacground"  />
    <attr name="radius"  />
    </declare-styleable> -->

</resources>

文件说明:

       当然自定义属性也有很多中方式。可以在上部分先添加属性以及属性的类型,下部分declare-styleable即可。也可以直接declare-styleable的时,直接添加并声明属性。其中string | reference表示既可以是String类型,也可以引用,比如@string/ID。其他的以此类推。


2.获取自定义属性

获取自定义属性一般在CircleTextView的两个或三个参数的构造方法中获取。其具体的代码片段如下所示。

<pre name="code" class="java">	public CircleTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		//获取对应的自定义属性
		TypedArray a = null;
		try{
			 a = context.obtainStyledAttributes(attrs, R.styleable
					 .CircleTextView, defStyle, 0);
			int n = a.getIndexCount();
			for(int i=0;i<n;i++){
				int attr = a.getIndex(i);
				switch (attr) {
				case R.styleable.CircleTextView_radius:
					mRadius = (int) a.getDimension(attr, TypedValue
							.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
							14, getResources().getDisplayMetrics()));
					break;
				case R.styleable.CircleTextView_text:
	                mText = a.getString(attr);
					break;
				case R.styleable.CircleTextView_textSize:
					mTextSize = (int) a.getDimension(attr, TypedValue
							.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14,
									getResources().getDisplayMetrics()));
					break;
				case R.styleable.CircleTextView_textColor:
					mTextColor = a.getColor(attr, 0x000000);
					break;
				case R.styleable.CircleTextView_bacground:
					mBacground = a.getColor(attr, 0x000000);
					break;

				}
			}
		}finally{
			if(null!=a){
				a.recycle();
			}
		}
	}


 
 


3. 控制自定义属性的条件

       控制自定义属性也就是提供一些set和get方法,供开发者随心所欲的设置一些自定义的属性,其具体的代码片段如下所示。 

	/**
	 * 设置CircleTextView的内容
	 * @param mText
	 */
	public void setText(String mText){
		this.mText = mText;
		invalidate();
	}
	
	/**
	 * 获取CircleTextView的内容
	 * @param mText
	 */
	public String getText(){
		
		return mText;
		
	}
	
	/**
	 * 设置CircleTextView的文字颜色
	 * @param mText
	 */
	public void setTextColor(int mTextColor){
		this.mTextColor = mTextColor;
		invalidate();
	}
	
	/**
	 * 设置CircleTextView的文字大小
	 * @param mText
	 */
	public void setTextSize(int mTextSize) {
		mTextSize = (int) TypedValue
				.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize,
						getResources().getDisplayMetrics());
		this.mTextSize = mTextSize;
		invalidate();
	}
	
	/**
	 * 设置CircleTextView的背景色
	 * @param mBacground
	 */
	public void setBacground(int mBacground){
		this.mBacground = mBacground;
		invalidate();
	}
       这里需要注意两点。一是setTextSize时,TypeValue.COMPLEX_UNIT_SP单位,不然没有效果,因为Text文字一般都是设置SP单位。二是每设置完一个属性必须调用下invalidate()方法,控件属性才会生效。


4.在layout中添加自定义控件以及自定义属性

       上面的三步都逐渐完成了,下面我们要在layout文件中添加自定义控件以及自定义属性。其具体的Layout文件如下所示。

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

    <com.example.testcircletextview.CircleTextView
       android:id="@+id/mTextView"
        android:layout_width="300dp"
        android:layout_height="200dp"
        jamy:text="" 
        jamy:textSize="18sp"
        android:layout_centerInParent="true"
        jamy:textColor="#ff0000"
        jamy:bacground="@android:color/holo_green_dark"
        />

</RelativeLayout>

       好了上面的自定View的一些系统的步骤已经介绍完毕,下面整体来看下CircleTextView.java这个类。其具体的代码如下所示。


package com.example.testcircletextview;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;

public class CircleTextView extends TextView{
	
	private int mTextSize;
	private int mTextColor;
	private String mText;
	private int mBacground;
	private int mRadius;
	private Paint mBacPaint;
	private Paint mTextPaint;
	// 文字的宽和高
	private Rect mTextBound;
	
	public CircleTextView(Context context) {
		super(context,null);
		
	}
	
	public CircleTextView(Context context, AttributeSet attrs) {
		this(context, attrs,0);
		
	}

	public CircleTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		//获取对应的自定义属性
		TypedArray a = null;
		try{
			 a = context.obtainStyledAttributes(attrs, R.styleable
					 .CircleTextView, defStyle, 0);
			int n = a.getIndexCount();
			for(int i=0;i<n;i++){
				int attr = a.getIndex(i);
				switch (attr) {
				case R.styleable.CircleTextView_radius:
					mRadius = (int) a.getDimension(attr, TypedValue
							.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
							14, getResources().getDisplayMetrics()));
					break;
				case R.styleable.CircleTextView_text:
	                mText = a.getString(attr);
					break;
				case R.styleable.CircleTextView_textSize:
					mTextSize = (int) a.getDimension(attr, TypedValue
							.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14,
									getResources().getDisplayMetrics()));
					break;
				case R.styleable.CircleTextView_textColor:
					mTextColor = a.getColor(attr, 0x000000);
					break;
				case R.styleable.CircleTextView_bacground:
					mBacground = a.getColor(attr, 0x000000);
					break;

				}
			}
		}finally{
			if(null!=a){
				a.recycle();
			}
		}
	}
	
	
	
	/**
	 * 初始化背景画笔以及文字画笔
	 */
	private void init() {
		mBacPaint = new Paint();
		mBacPaint.setColor(mBacground);
		mBacPaint.setAntiAlias(true);  
		
		mTextBound = new Rect();
		mTextPaint = new Paint();
		mTextPaint.setColor(mTextColor);
		mTextPaint.setTextSize(mTextSize);
		mTextPaint.setStyle(Style.FILL);
		mTextPaint.getTextBounds(mText,0,mText.length(),mTextBound);
		
		
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		init();
		mRadius = Math.min(getWidth(),getHeight());
		System.out.println("onDraw   Width:"+getWidth()+"Height:"+getHeight()+"mRadius:"+mRadius);
		canvas.drawCircle(getWidth()/2, getHeight()/2, mRadius/2, mBacPaint);  
    	canvas.drawText(mText, getWidth()/2-mTextBound.width()/2, getHeight()/2+mTextBound.height()/2, mTextPaint);
	
	}
	
	/**
	 * 设置CircleTextView的内容
	 * @param mText
	 */
	public void setText(String mText){
		this.mText = mText;
		invalidate();
	}
	
	/**
	 * 获取CircleTextView的内容
	 * @param mText
	 */
	public String getText(){
		
		return mText;
		
	}
	
	/**
	 * 设置CircleTextView的文字颜色
	 * @param mText
	 */
	public void setTextColor(int mTextColor){
		this.mTextColor = mTextColor;
		invalidate();
	}
	
	/**
	 * 设置CircleTextView的文字大小
	 * @param mText
	 */
	public void setTextSize(int mTextSize) {
		mTextSize = (int) TypedValue
				.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize,
						getResources().getDisplayMetrics());
		this.mTextSize = mTextSize;
		invalidate();
	}
	
	/**
	 * 设置CircleTextView的背景色
	 * @param mBacground
	 */
	public void setBacground(int mBacground){
		this.mBacground = mBacground;
		invalidate();
	}

}

按照上面的步骤走完,自定义CircleTextView剩下最核心的OnDraw()绘制View了。下面仔细来瞧瞧这个方法。

在OnDraw()主要进行了对背景画笔以及文本画笔进行初始化,其次获取我们设置的宽高中的最小值,作为所画圆的直径。紧随绘制我们的圆形背景(即DrawCircle())以及Text内容(即drawText()),由此绘制完成。

经过上面的一系列步骤还不知道自定义的CircleTextView会呈现啥效果,下面来正式测试下。运行其效果如下所示。

           

     

                                       运行效果图

       经过上面的介绍,现在对自定义View属性以及自定义View有了点了解吧。虽然这里的自定义View so easy不过有些细节不容忽视。下面我们就稍微做下总结,看看那些地方需要注意下。


1.自定义声明属性时,最好加上declare-styleable(因为加上declare-styleable相当于在xml中加上控件id类似,系统会默认生成一些对应属性的常量,方便我们获取属性时查找)。


2.代码控制自定义属性时必须invalidate(),假如单位是dp或sp的属性必须设置对应的属性单位。


3.设置画笔的一些属性,最好写在onDraw(),方便属性的刷新(因为每执行一次invalidate就执行一次onDraw())。


4.在layout.xml文件中引用自定义属性以及自定义View必须加入   xmlns:jamy="http://schemas.android.com/apk/res/+应用包名"(其中jamy可以为任意命名,假如命名jamy下面属性必须是jamy:属性名)


由此自定义View属性和自定义View介绍到此完毕,好久没有更新博客了,有点小激动咋办?哈哈,上面自定义View可能介绍的还不是很全面,欢迎各位给出批评与建议。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值