当前位置: 美高梅集团手机版 > 美高梅集团 > 正文

都会先继承View并实现View的三个构造函数,【美高

时间:2019-09-30 15:31来源:美高梅集团
Github地址(完整Demo,欢迎下载) 参考文章。 http://blog.csdn.net/xmxkf/article/details/51468648 http://blog.csdn.net/lmj623565791/article/details/45022631; 1.写一个自定义控件类,这个类就是你的自定义控件的

Github地址(完整Demo,欢迎下载)

参考文章。
http://blog.csdn.net/xmxkf/article/details/51468648
http://blog.csdn.net/lmj623565791/article/details/45022631;

1.写一个自定义控件类,这个类就是你的自定义控件的实现.

美高梅集团手机版 1组合控件1.png美高梅集团手机版 2组合控件2.PNG

1.初始Custom View的构造函数

通常我们在实现Custom View的时候,都会先继承View并实现View的三个构造函数,例如:

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class MyCustomView extends View {
    /**
     * 第一个构造函数
     */
    public MyCustomView(Context context) {
        this(context, null);
    }

    /**
     * 第二个构造函数
     */
    public MyCustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 第三个构造函数
     */
    public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO:获取自定义属性
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}
  • 在代码中直接new一个Custom View实例的时候,会调用第一个构造函数.
  • 在xml布局文件中调用Custom View的时候<CustomView/>,确切的说是xml解析到当前的标签的时候,会调用第二个构造函数.
  • 在xml布局文件中调用Custom View,并且Custom View标签中还有自定义属性时,这里调用的还是第二个构造函数.
    也就是说,系统默认只会调用Custom View的前两个构造函数,至于第三个构造函数的调用,通常是我们自己在构造函数中主动调用的(例如,在第二个构造函数中调用第三个构造函数).

接下来就针对自定义View的属性展开:

2.在res/values目录下建立一个attrs.xml的文件,在这个文件中增加对控件的自定义属性的定义.

在很多APP当中,有些页面需要填写很多资料,比如个人中心,还有一些页面,点击每个Item都要跳转页面或者弹框选择。这样的组合控件,相信大家都见过,说到这里,可能有人不服了,不就是一个线性布局或者相对布局吗,我分分钟写出来。是的,我承认你可以搞定,因为我以前也是一个个布局嵌套写出来的,但是我想说,这么多相似的重复布局,你难道真的要一个个去写吗?复制粘贴一个个改,而且有些功能是重复的,比如输入框那个清除输入内容按钮,你也去写,你累吗?这样的代码看上去可读性高吗?所以,我今天就是来和大家一起解决这个问题的,我们完全可以把这种组合控件封装起来,然后专注于处理我们的业务逻辑就好。

2.为什么要自定义属性

要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用。但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为什么?我想大家应该都知道:系统定义好的属性我们就可以拿来用呗,但是你们知道系统定义了哪些属性吗?哪些属性是我们自定义控件可以直接使用的,哪些不能使用?什么样的属性我们能使用?这些问题我想大家不一定都弄得清除,下面我们去一一解开这些谜团。
  系统定义的所有属性我们可以在sdkplatformsandroid-xxdataresvalues目录下找到attrs.xml这个文件,这就是系统自带的所有属性,打开看看一些比较熟悉的:

    <declare-styleable name="View">
    <attr name="id" format="reference" />
    <attr name="background" format="reference|color" />
    <attr name="padding" format="dimension" />
     ...
    <attr name="focusable" format="boolean" />
     ...
</declare-styleable>

<declare-styleable name="TextView">
    <attr name="text" format="string" localization="suggested" />
    <attr name="hint" format="string" />
    <attr name="textColor" />
    <attr name="textColorHighlight" />
    <attr name="textColorHint" />
     ...
</declare-styleable>

<declare-styleable name="ViewGroup_Layout">
    <attr name="layout_width" format="dimension">
        <enum name="fill_parent" value="-1" />
        <enum name="match_parent" value="-1" />
        <enum name="wrap_content" value="-2" />
    </attr>
    <attr name="layout_height" format="dimension">
        <enum name="fill_parent" value="-1" />
        <enum name="match_parent" value="-1" />
        <enum name="wrap_content" value="-2" />
    </attr>
</declare-styleable>

<declare-styleable name="LinearLayout_Layout">
    <attr name="layout_width" />
    <attr name="layout_height" />
    <attr name="layout_weight" format="float" />
    <attr name="layout_gravity" />
</declare-styleable>

<declare-styleable name="RelativeLayout_Layout">
    <attr name="layout_centerInParent" format="boolean" />
    <attr name="layout_centerHorizontal" format="boolean" />
    <attr name="layout_centerVertical" format="boolean" />
     ...
</declare-styleable>

看看上面attrs.xml文件中的属性,发现他们都是有规律的分组的形式组织的。以declare-styleable 为一个组合,后面有一个name属性,属性的值为View 、TextView 等等,有没有想到什么?没错,属性值为View的那一组就是为View定义的属性,属性值为TextView的就是为TextView定义的属性…。

因为所有的控件都是View的子类,所以为View定义的属性所有的控件都能使用,这就是为什么我们的自定义控件没有定义属性就能使用一些系统属性。

但是并不是每个控件都能使用所有属性,比如TextView是View的子类,所以为View定义的所有属性它都能使用,但是子类肯定有自己特有的属性,得单独为它扩展一些属性,而单独扩展的这些属性只有它自己能有,View是不能使用的,比如View中不能使用android:text=“”。又比如,LinearLayout中能使用layout_weight属性,而RelativeLayout却不能使用,因为layout_weight是为LinearLayout的LayoutParams定义的。

综上所述,自定义控件如果不自定义属性,就只能使用VIew的属性,但为了给我们的控件扩展一些属性,我们就必须自己去定义。

3.使用带AttributeSet参数的类的构造函数,并在构造函数中将自定义控件类中变量与attrs.xml中的属性连接起来.

1、分析布局(以组合控件1为例子来分析)从上面图我们可以看出,每一个Item的布局从左往右依次是:标题,输入框,清除输入的按钮,向右的箭头。前2个Item,我们点击中间输入框的时候,直接跳出来软键盘,直接输入文字内容,当有内容的时候,显示清除按钮,没有内容的时候,隐藏清除按钮。后2个Item,是带箭头的,是不可以输入的,提示我们这一项是用来跳转或者点击弹出选择框等。

2. 怎样自定义属性

自定义属性的步骤想必大家都所了解:
1、自定义一个CustomView(extends View )类
2、编写values/attrs.xml,在其中编写styleable和item等标签元素
3、在布局文件中CustomView使用自定义的属性(注意命名空间)
4、在CustomView的构造方法中通过TypedArray获取

有几个问题不知道是否知道:

  • 以上步骤是如何奏效的?
  • styleable 的含义是什么?可以不写嘛?我自定义属性,我声明属性就好了,为什么一定要写个styleable呢?
  • 如果系统中已经有了语义比较明确的属性,我可以直接使用嘛?
  • 构造方法中的有个参数叫做AttributeSet
    (eg: MyTextView(Context context, AttributeSet attrs) )这个参数看名字就知道包含的是参数的数组,那么我能不能通过它去获取我的自定义属性呢?
  • TypedArray是什么鬼?从哪冒出来的,就要我去使用?
    看完本篇文章,相信你会彻底解决上述问题。
    翻阅系统的属性文件,你会发现,有两种获取形式(下面讲);这两种
    区别就是attr标签后面带不带format属性,如果带format的就是在定义属性,如果不带format的就是在使用已有的属性,name的值就是属性的名字,format是限定当前定义的属性能接受什么值。

打个比方,比如系统已经定义了android:text属性,我们的自定义控件也需要一个文本的属性,可以有两种方式:

第一种:我们并不知道系统定义了此名称的属性,我们自己定义一个名为text或者mText的属性(属性名称可以随便起的)

    <resources>
        <declare-styleable name="MyTextView">
            <attr name=“text" format="string" />
        </declare-styleable>
    </resources>

第二种:我们知道系统已经定义过名称为text的属性,我们不用自己定义,只需要在自定义属性中申明,我要使用这个text属性
(注意加上android命名空间,这样才知道使用的是系统的text属性)

<resources>
    <declare-styleable name="MyTextView">
        <attr name=“android:text"/>
    </declare-styleable>
</resources>

为什么系统定义了此属性,我们在使用的时候还要声明?因为,系统定义的text属性是给TextView使用的,如果我们不申明,就不能使用text属性。

4.在自定义控件类中使用这些已经连接的属性变量.

美高梅集团手机版 3选择城市.jpg

4. 属性值的类型format

5.将自定义的控件类定义到布局用的xml文件中去.

上面这些个Item的布局很简单,大致结构是这样的

format支持的类型一共有11种:

6.在界面中生成此自定义控件类对象,就完成了自定义控件的创建和使用了.

<LinearLayout> <LinearLayout> <TextView /> <EditText /> <!--清除输入内容--> <ImageView /> <!--点击跳转或者弹出选择框--> <ImageView /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/item_group_divider" /></LinearLayout>

(1). reference:参考某一资源ID

  • 属性定义:
<declare-styleable name = "名称">
     <attr name = "background" format = "reference" />
</declare-styleable>
  • 属性使用:
<ImageView android:background = "@drawable/图片ID"/>

二、带你用代码写出来。

然后每一项都这么写一个相似的LinearLayout,然后如果没有右边的箭头,我们又把它去掉,如果我们的项目中也有这种类似的item,而且有很多,那么这个界面的layout的代码会显得很臃肿,维护起来也不清晰。

(2). color:颜色值

  • 属性定义:
<attr name = "textColor" format = "color" />
  • 属性使用:
<TextView android:textColor = "#00FF00" />

1、新建一个类public class Item extends LinearLayout {

所以我根据我的项目把这种组合控件封装了一个,可能扩展性不是那么好,但是代码少,思路清晰,符合我的项目需求,你拿过去做适当调整也能用。

(3). boolean:布尔值

  • 属性定义:
<attr name = "focusable" format = "boolean" />
  • 属性使用:
<Button android:focusable = "true"/>

private Context mContext;

2、Item的布局 item_group_layout.xml

(1). reference:参考某一资源ID

  • 属性定义:
<declare-styleable name = "名称">
     <attr name = "background" format = "reference" />
</declare-styleable>
  • 属性使用:
<ImageView android:background = "@drawable/图片ID"/>

public CrashWriteItem(Context context, AttributeSet attrs) {

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:andro xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android: android:layout_width="match_parent" android:layout_height="45dp" android:background="@color/white" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:textColor="@color/item_group_title" android:textSize="15sp" tools:text="姓名" /> <EditText android: android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@null" android:gravity="center_vertical|end" android:hint="请输入姓名" android:singleLine="true" android:paddingStart="10dp" android:textColor="@color/item_group_edt" android:textSize="13sp" /> <!--清除输入内容--> <ImageView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:padding="8dp" android:scaleType="centerCrop" android:src="@mipmap/close" /> <!--点击跳转或者弹出选择框--> <ImageView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="7dp" android:padding="8dp" android:scaleType="centerCrop" android:src="@mipmap/jiantou_right" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/item_group_divider" /></LinearLayout>

(4). dimension:尺寸值

  • 属性定义:
<attr name = "layout_width" format = "dimension" />
  • 属性使用:
<Button android:layout_width = "42dip"/>

super(context, attrs);

3.首先新建一个类,继承自FrameLayout,实现对应的构造方法我们引入刚才Item的布局,把它添加到这个FrameLayout

(5). float:浮点值

  • 属性定义:
<attr name = "fromAlpha" format = "float" />
  • 属性使用:
<alpha android:fromAlpha = "1.0"/>

mContext = context;

public class ItemGroup extends FrameLayout implements View.OnClickListener { private LinearLayout itemGroupLayout; //组合控件的布局 private TextView titleTv; //标题 private EditText contentEdt; //输入框 private ImageView clearIv; //清楚输入内容 private ImageView jtRightIv; //向右的箭头 private ItemOnClickListener itemOnClickListener; //Item的点击事件 public ItemGroup(@NonNull Context context) { super; initView; } public ItemGroup(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); initView; } public ItemGroup(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { super(context, attrs, defStyleAttr); initView; } //初始化View private void initView(Context context) { View view = LayoutInflater.from.inflate(R.layout.item_group_layout, null); itemGroupLayout = (LinearLayout) view.findViewById(R.id.item_group_layout); titleTv =  view.findViewById(R.id.title_tv); contentEdt =  view.findViewById(R.id.content_edt); clearIv = (ImageView) view.findViewById(R.id.clear_iv); jtRightIv = (ImageView) view.findViewById(R.id.jt_right_iv); addView; //把自定义的这个组合控件的布局加入到当前FramLayout}}

(6). integer:整型值

  • 属性定义:
<attr name = "framesCount" format="integer" />
  • 属性使用:
<animated-rotate android:framesCount = "12"/>

init(attrs);

4.属性的定义,在完成类的创建后,来自定义相关属性首先需要在values目录下面新建一个attrs.xml文件 , 自定义相关属性,

(7). string:字符串

  • 属性定义:
<attr name = "text" format = "string" />
  • 属性使用:
<TextView android:text = "我是文本"/>

}

其定义格式如下:

(8). fraction:百分数

  • 属性定义:
<attr name = "pivotX" format = "fraction" />
  • 属性使用:
<rotate android:pivotX = "200%"/>

private void init(AttributeSet attrs) {

<declare-styleable name="自定义属性名称"> <attr name="属性名称" format="属性类型"/></declare-styleable>

<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="ItemGroup"> <!--标题的文字--> <attr name="title" format="string" /> <!--标题的字体大小--> <attr name="title_size" format="dimension" /> <!--标题的字体颜色--> <attr name="title_color" format="color" /> <!--输入框的内容--> <attr name="edt_content" format="string" /> <!--输入框的字体大小--> <attr name="edt_text_size" format="dimension" /> <!--输入框的字体颜色--> <attr name="edt_text_color" format="color" /> <!--输入框提示的内容--> <attr name="edt_hint_content" format="string" /> <!--输入框的提示字体的字体颜色--> <attr name="edt_hint_text_color" format="color" /> <!--输入框是否可以编辑内容--> <attr name="isEditable" format="boolean"/> <!--向的右箭头图标是否可见--> <attr name="jt_visible" format="boolean"/> <!--item布局的内边距--> <attr name="paddingLeft" format="dimension"/> <attr name="paddingRight" format="dimension"/> <attr name="paddingTop" format="dimension"/> <attr name="paddingBottom" format="dimension"/> <attr name="drawable_left" format="reference" /> <attr name="drawable_right" format="reference" /> <attr name="line_color" format="color" /> <attr name="line_height" format="integer" /> </declare-styleable></resources>

(9). enum:枚举值

  • 属性定义:
<declare-styleable name="名称">
    <attr name="orientation">
        <enum name="horizontal" value="0" />
        <enum name="vertical" value="1" />
    </attr>
</declare-styleable>
  • 属性使用:
<LinearLayout  
    android:orientation = "vertical">
</LinearLayout>

注意:枚举类型的属性在使用的过程中只能同时使用其中一个,不能 android:orientation = “horizontal|vertical"

// TODO Auto-generated method stub

编辑:美高梅集团 本文来源:都会先继承View并实现View的三个构造函数,【美高

关键词: