Android 自定义View控件

非淡泊无以明志,非宁静无以致远。这篇文章主要讲述Android 自定义View控件相关的知识,希望能为你提供帮助。
一、简介在自定义View时,我们通常会重写onDraw()方法来绘制View的显示内容。如果,该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法。另外,通过自定义attrs属性,还可以设置新的属性配置值。
在View中通常有以下一些比较重要的回调方法:

  • onFinisInflate():从XML加载组件后回调;
  • onSizeChanged():组件大小改变时回调;
  • onMeasure():回调该方法来进行测量;
  • onLayout():回调该方法来确定显示位置;
  • onTouchEvent():监听到触摸事件时回调;
当然,创建自定义View的时候,并不需要重写所有方法,只需要重写特定条件的回调方法即可。
通常情况下,有以下三种方法来实现自定义的控件:
  • 对现有控件进行拓展;
  • 通过组合来实现新的控件;
  • 重写View来实现全新的控件;
二、实例: 一、创建复合控件 1. 定义属性为一个View提供可自定义的属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件,并在该文件中通过如下代码定义相应的属性即可。
1 < ?xml version="1.0" encoding="utf-8"?> 2 < resources> 3< declare-styleable name="TopBar"> 4< attr name="title" format="string" /> 5< attr name="titleTextSize" format="dimension" /> 6< attr name="titleTextColor" format="color" /> 7< attr name="leftTextColor" format="color" /> 8< attr name="leftBackground" format="reference|color" /> 9< attr name="leftText" format="string" /> 10< attr name="rightTextColor" format="color" /> 11< attr name="rightBackGround" format="reference|color" /> 12< attr name="rightText" format="string" /> 13< /declare-styleable> 14 < /resources>

  我们在代码中通过< declare-styleable> 标签声明了使用自定义属性,并通过name属性来确定引用的名称。最后,通过< attr> 标签来声明具体的自定义属性,比如:标题文字、颜色、大小等属性。并通过format属性来指定属性的类型。需要注意的是,有些属性可以是颜色属性,也可以是引用属性。比如:按钮的背景,可以把其指定为具体颜色,也可以把它指定为一张图片,所以,使用“ |” 来分隔不同的属性— — "reference|color"。
  在构造方法中,通过如下代码来获取在XML布局文件中自定义的那些属性,即与我们使用系统提供的那些属性一样。
1 /** 2* attrs : 属性设置 3* R.styleable.TopBar : 在attrs.xml文件中,配置的属性 4*/ 5 TypeArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);

示例代码如下所示:
1 public class TopBar extends View 2 { 3protected Color mLeftTextColor; 4 5public TopBar(Context context) 6{ 7this(context, null); 8} 9 10public TopBar(Context context, AttributeSet attrs) 11{ 12super(context, attrs); 13// 通过这个方法将在attrs.xml文件中,定义的< declare-styleable> 的所有属性的值存储到TypedArray中 14TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar); 15 16// 在TypedArray中,取出对应的值来为要设置的属性赋值 17mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0); 18 19// 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误 20ta.recycle(); 21} 22 }

PS: 需要注意的是,当获取完所有的属性值后,需要调用TypedArray的recyle()方法来完成资源的回收。 
2. 组合控件
1 public class TopBar extends RelativeLayout 2 { 3protected String mTitle; 4protected float mTitleTextSize; 5protected int mTitleTextColor; 6protected int mLeftTextColor; 7protected Drawable mLeftBackground; 8protected String mLeftText; 9protected int mRightTextColor; 10protected Drawable mRightBackground; 11protected String mRightText; 12 13public Button mLeftButton; 14public TextView mTitleView; 15public Button mRightButton; 16 17protected RelativeLayout.LayoutParams mLeftLayoutParams; 18protected RelativeLayout.LayoutParams mTitleLayoutParams; 19protected RelativeLayout.LayoutParams mRightLayoutParams; 20 21public TopBar(Context context) 22{ 23this(context, null); 24} 25 26public TopBar(Context context, AttributeSet attrs) 27{ 28super(context, attrs); 29// 通过这个方法将在attrs.xml文件中,定义的< declare-styleable> 的所有属性的值存储到TypedArray中 30TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar); 31 32// 在TypedArray中,取出对应的值来为要设置的属性赋值 33// left button 34mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0); 35mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground); 36mLeftText = ta.getString(R.styleable.TopBar_leftText); 37 38// title 39mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10); 40mTitleTextColor = ta.getColor(R.styleable.TopBar_titleColor, 0); 41mTitle = ta.getString(R.styleable.TopBar_titleText); 42 43// right button 44mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0); 45mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackGround); 46mRightText = ta.getString(R.styleable.TopBar_rightText); 47 48// 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误 49ta.recycle(); 50 51initView(context); 52} 53 54private void initView(Context context) 55{ 56mLeftButton = new Button(context); 57mTitleView = new TextView(context); 58mRightButton = new Button(context); 59 60mLeftButton.setText(mLeftText); 61mLeftButton.setBackground(mLeftBackground); 62mLeftButton.setTextColor(mLeftTextColor); 63 64mTitleView.setText(mTitle); 65mTitleView.setTextColor(mTitleTextColor); 66mTitleView.setTextSize(mTitleTextSize); 67 68mRightButton.setText(mRightText); 69mRightButton.setBackground(mRightBackground); 70mRightButton.setTextColor(mRightTextColor); 71 72mLeftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); 73mLeftLayoutParams.addRule(ALIGN_PARENT_LEFT, TRUE); 74addView(mLeftButton, mLeftLayoutParams); 75 76mTitleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); 77mTitleLayoutParams.addRule(CENTER_IN_PARENT, TRUE); 78addView(mTitleView, mTitleLayoutParams); 79 80mRightLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); 81mRightLayoutParams.addRule(ALIGN_PARENT_RIGHT, TRUE); 82addView(mRightButton, mRightLayoutParams); 83} 84 85 }

  3. 定义接口定义接口对象,在TopBar控件中,实现左右按钮的点击事件,调用接口方法:
1 // 定义接口 2 mLeftButton.setOnClickListener(new OnClickListener() 3 { 4@Override 5public void onClick(View v) 6{ 7mListener.leftClick(); 8} 9 }); 10 11 mRightButton.setOnClickListener(new OnClickListener() 12 { 13@Override 14public void onClick(View v) 15{ 16mListener.rightClick(); 17} 18 }); 19 20 ...... 21 22 // 左右按钮接口类 23 public interface TopBarClickListener 24 { 25void leftClick(); 26void rightClick(); 27 } 28 29 // 设置左右按钮点击事件接口实现的实例 30 public void setOnTopBarClickListener(TopBarClickListener topBarClickListener) 31 { 32mListener = topBarClickListener; 33 }

4. 引用UI模板在引用UI模板前,需要指定引用第三方控件的命名空间。在布局文件中,如下所示:
1 xmlns:androi="http://schemas.android.com/apk/res/android"

这行代码就是在指定引用的名字控件xmlns,即xml namespace。这里指定了命名空间为“ android” ,因此,在接下来使用系统属性的时候,才可以使用“ android:” 来引用Android的系统属性。同样地,使用自定义的属性,那么就需要创建自己的命名空间,在Android Studio中,第三方控件 都使用如下代码引入命名空间:
1 xmlns:custom="http://schemas.android.com/apk/res-auto"

这里引用的第三方命名空间为custom,之后在XML文件中使用自定义的属性时,就可以通过这个命名空间来引用,代码如下所示:
1 < ?xml version="1.0" encoding="utf-8"?> 2 < com.naray.radialview.View.TopBar 3xmlns:android="http://schemas.android.com/apk/res/android" 4xmlns:custom="http://schemas.android.com/apk/res-auto" 5android:layout_width="wrap_content" 6android:layout_height="wrap_content" 7custom:titleText="自定义控件" 8custom:titleColor="#da0c0c" 9custom:titleTextSize="18sp" 10custom:leftBackground="#999999" 11custom:leftTextColor="#da0c0c" 12custom:leftText="back" 13custom:rightBackGround="#999999" 14custom:rightTextColor="#da0c0c" 15custom:rightText="more"> 16 17 < /com.naray.radialview.View.TopBar>

使用自定义的View与系统原生的View最大的区别就是在申明控件时,需要指定完整的包名,而在引用自定义的属性时,需要使用自定义的xmlns名字。
 
二、重写View来实现全新的控件 三、自定义ViewGroup【Android 自定义View控件】 

    推荐阅读