zoukankan      html  css  js  c++  java
  • 014 Android 自定义组合控件

    1.需求介绍

    将已经编写好的布局文件,抽取到一个类中去做管理,下次还需要使用类似布局时,直接使用该组合控件的对象。

    优点:可复用。

    例如要重复利用以下布局:

    <RelativeLayout
            android:padding="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/tvSet_title"
                android:textSize="18dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#000"
                android:text="自动更新设置" />
    
            <TextView
                android:id="@+id/tvSet_def"
                android:textSize="18dp"
                android:textColor="#000"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/tvSet_title"
                android:text="自动更新已关闭" />
    
            <!--android:layout_alignParentRight="true" 设置控件在父控件的最右边-->
            <!--android:layout_centerVertical="true" 垂直方向居中-->
            <CheckBox
                android:id="@+id/cbSet_1"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
    
            <!--实现分割线的效果-->
            <View
                android:background="#000"
                android:layout_marginTop="5dp"
                android:layout_below="@id/tvSet_def"
                android:layout_width="match_parent"
                android:layout_height="1dp"/>
        </RelativeLayout>

    2.事件传递规则与相应规则

    SettingActivity对应布局文件的根布局获取点击事件
    此事件传递给SettingItemView控件

    (1)点击在SettingItemView非CheckBox区域,事件就由SettingItemView去做响应
    (2)点击在SettingItemView中CheckBox区域,事件就由SettingItemView传递给CheckBox,由CheckBox去做响应
    CheckBox响应当前的点击事件,则SettingItemView就不能再去响应此事件,不能调用onClick方法,去改变状态

    解决此问题的方案为:不让checkBox响应点击事件

    3.自定义属性

    在复用SettingItemView的时候,每一个条目对应的标示,描述内容都不一致。

    解决方案:给自定义控件SettingItemView定义属性

    (1)在resvalues目录下新建attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="SetttingItemView">
            <attr name="destitle" format="string"/>
            <attr name="desoff" format="string"/>
            <attr name="deson" format="string"/>
        </declare-styleable>
    </resources>

    (2)自定义属性的使用

    后3个属性就是自定义属性

    safeguard替换掉原有android

    com.example.administrator.test62360safeguard(工程的包名)必须这样编写,替换掉了android,代表当前应用自定义属性

    <com.example.administrator.test62360safeguard.Utils.SetttingItemView
            xmlns:safeguard="http://schemas.android.com/apk/res/com.example.administrator.test62360safeguard"
            android:id="@+id/siv_update"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            safeguard:destitle="自动更新设置"
            safeguard:desoff="自动更新已关闭"
            safeguard:deson="自动更新已开启"
            >

    (3)获取属性值

    在自定义控件类(SetttingItemView)中创建获取属性值的方法

    /**
         * @param attrs 自定义属性值
         */
        private void initAttrs(AttributeSet attrs) {
            destitle=attrs.getAttributeValue(NAMESPACE,"destitle");
            desoff=attrs.getAttributeValue(NAMESPACE,"desoff");
            deson=attrs.getAttributeValue(NAMESPACE,"deson");
        }

    4.实现步骤

    (1)将组合控件的布局,抽取到一个xml文件中

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <RelativeLayout
            android:padding="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/tvSet_title"
                android:textSize="18dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#000"
                android:text="自动更新设置" />
    
            <TextView
                android:id="@+id/tvSet_def"
                android:textSize="18dp"
                android:textColor="#000"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/tvSet_title"
                android:text="自动更新已关闭" />
    
            <!--android:layout_alignParentRight="true" 设置控件在父控件的最右边-->
            <!--android:layout_centerVertical="true" 垂直方向居中-->
            <!--android:clickable="false"-->
            <!--android:focusable="false"-->
            <!--android:focusableInTouchMode="false" 让当前的CheckBox不能被点击,即不能相应事件-->
            <CheckBox
                android:id="@+id/cbSet_1"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:clickable="false"
                android:focusable="false"
                android:focusableInTouchMode="false"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
    
            <!--实现分割线的效果-->
            <View
                android:background="#000"
                android:layout_marginTop="5dp"
                android:layout_below="@id/tvSet_def"
                android:layout_width="match_parent"
                android:layout_height="1dp"/>
        </RelativeLayout>
    </RelativeLayout>

    (2)通过一个单独的类,去加载此段布局文件

    获取自定义的属性值,并将属性值的内容赋值给自定义控件;

    package com.example.administrator.test62360safeguard.Utils;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.View;
    import android.widget.CheckBox;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    import com.example.administrator.test62360safeguard.R;
    
    //通过一个单独的类,去加载此段布局文件,由于布局采用相对布局,所以此类需继承RelativeLayout
    public class SetttingItemView extends RelativeLayout {
        CheckBox cbSet_1;
        TextView tvSet_def;
        String destitle;
        String desoff;
        String deson;
        private static final String NAMESPACE="http://schemas.android.com/apk/res/com.example.administrator.test62360safeguard";
        //使得该方法调用第二个构造方法
        public SetttingItemView(Context context) {
            this(context,null);
        }
    
        //使得该方法调用第三个构造方法
        public SetttingItemView(Context context, AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public SetttingItemView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            //将xml转化为一个view对象,直接添加到当前的SetttingItemView对应的view中
            View.inflate(context, R.layout.setting_item_view,this);
            TextView tvSet_title=findViewById(R.id.tvSet_title);
            tvSet_def=findViewById(R.id.tvSet_def);
            cbSet_1=findViewById(R.id.cbSet_1);
    
            //获取自定义以及原生属性
            initAttrs(attrs);
            //获取布局文件中定义的字符串,赋值给自定义组合控件的标题
            tvSet_title.setText(destitle);
            tvSet_def.setText(desoff);
        }
    
    
        /**
         * @param attrs 自定义属性值
         */
        private void initAttrs(AttributeSet attrs) {
            destitle=attrs.getAttributeValue(NAMESPACE,"destitle");
            desoff=attrs.getAttributeValue(NAMESPACE,"desoff");
            deson=attrs.getAttributeValue(NAMESPACE,"deson");
        }
    
        //判断SetttingItemView组件是否被选中,true(选中),false(未选中)
        public boolean isChecked(){
            //SetttingItemView组件是否被选中与该自定义组件内部的checkbox的状态绑定
            return cbSet_1.isChecked();
        }
    
        //切换选中状态
        public void setChecked(boolean isCheck){
            if(isCheck){
                cbSet_1.setChecked(isCheck);
                tvSet_def.setText(deson);
            }else {
                cbSet_1.setChecked(isCheck);
                tvSet_def.setText(desoff);
            }
        }
    
    }

    (3)自定义组合控件在xml使用

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".SettingActivity">
    
        <!--调用可复用的样式-->
        <TextView
            style="@style/TitleStyle"
            android:text="设置中心"/>
        <!--使用自定义的组合控件-->
        <com.example.administrator.test62360safeguard.Utils.SetttingItemView
            xmlns:safeguard="http://schemas.android.com/apk/res/com.example.administrator.test62360safeguard"
            android:id="@+id/siv_update"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            safeguard:destitle="自动更新设置"
            safeguard:desoff="自动更新已关闭"
            safeguard:deson="自动更新已开启"
            >
        </com.example.administrator.test62360safeguard.Utils.SetttingItemView>
    
        <com.example.administrator.test62360safeguard.Utils.SetttingItemView
            xmlns:safeguard="http://schemas.android.com/apk/res/com.example.administrator.test62360safeguard"
    
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            safeguard:destitle="电话归属地显示设置"
            safeguard:desoff="归属地显示已关闭"
            safeguard:deson="归属地显示已开启"
            >
        </com.example.administrator.test62360safeguard.Utils.SetttingItemView>
    
    
    </LinearLayout>

    (4)UI界面应用

    package com.example.administrator.test62360safeguard;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    
    import com.example.administrator.test62360safeguard.ViewUtil.SetttingItemView;
    
    public class SettingActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_setting);
            initUpdate();
        }
    
        private void initUpdate() {
            final SetttingItemView siv_update=findViewById(R.id.siv_update);
            siv_update.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //获取之前的选中状态
                    boolean isCheck=siv_update.isChecked();
                    //将原有状态取反,设置为当前状态
                    siv_update.setChecked(!isCheck);
                }
            });
        }
    }

    5.效果图

            

  • 相关阅读:
    for循环里面不要进行remove操作,for循环里remove元素后,list的下标会减小,导致遍历不完全
    elasticsearch,java api, transport Client, 查询时索引库可以用通配符*和删除接口不能用
    (一)WebPack4.0 从零开始
    合并代码 dev 到 master
    vscode 终端无法输入问题 看这个就行了
    node 学习笔记:一、 nvm 安装管理Node版本
    常见的对象创建模式
    深入理解闭包
    sort对数组排序
    图片压缩
  • 原文地址:https://www.cnblogs.com/luckyplj/p/10813121.html
Copyright © 2011-2022 走看看