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

      PS: 需要注意的是,当获取完所有的属性值后,需要调用TypedArray的recyle()方法来完成资源的回收。 

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

      定义接口对象,在TopBar控件中,实现左右按钮的点击事件,调用接口方法:

     1 // 定义接口
     2 mLeftButton.setOnClickListener(new OnClickListener()
     3 {
     4     @Override
     5     public void onClick(View v)
     6     {
     7         mListener.leftClick();
     8     }
     9 });
    10 
    11 mRightButton.setOnClickListener(new OnClickListener()
    12 {
    13     @Override
    14     public void onClick(View v)
    15     {
    16         mListener.rightClick();
    17     }
    18 });
    19 
    20 ......
    21 
    22 // 左右按钮接口类
    23 public interface TopBarClickListener
    24 {
    25     void leftClick();
    26     void rightClick();
    27 }
    28 
    29 // 设置左右按钮点击事件接口实现的实例
    30 public void setOnTopBarClickListener(TopBarClickListener topBarClickListener)
    31 {
    32     mListener = 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
     3     xmlns:android="http://schemas.android.com/apk/res/android"
     4     xmlns:custom="http://schemas.android.com/apk/res-auto"
     5     android:layout_width="wrap_content"
     6     android:layout_height="wrap_content"
     7     custom:titleText="自定义控件"
     8     custom:titleColor="#da0c0c"
     9     custom:titleTextSize="18sp"
    10     custom:leftBackground="#999999"
    11     custom:leftTextColor="#da0c0c"
    12     custom:leftText="back"
    13     custom:rightBackGround="#999999"
    14     custom:rightTextColor="#da0c0c"
    15     custom:rightText="more">
    16 
    17 </com.naray.radialview.View.TopBar>

      使用自定义的View与系统原生的View最大的区别就是在申明控件时,需要指定完整的包名,而在引用自定义的属性时,需要使用自定义的xmlns名字。

    二、重写View来实现全新的控件

    三、自定义ViewGroup

     

  • 相关阅读:
    流程图制作在云上 https://www.processon.com/
    白板编程浅谈——Why, What, How
    如何创建一个非常酷的3D效果菜单
    Xcode及模拟器SDK下载
    Swift项目兼容Objective-C问题汇总
    iOS 多个精致动画
    代码注释中的5要与3不要
    如何处理iOS中照片的方向
    会报编译器警告的Xcode 6.3新特性:Nullability Annotations
    iOS应用架构谈 view层的组织和调用方案
  • 原文地址:https://www.cnblogs.com/naray/p/5623900.html
Copyright © 2011-2022 走看看