Android项目:手机安全卫士(4)—— 自定义(组合)控件、属性

Android项目:手机安全卫士(4)—— 自定义(组合)控件、属性

1 总纲

手机安全卫士共有 9 个功能,我们先来看看设置界面长什么样:

Android项目:手机安全卫士(4)—— 自定义(组合)控件、属性_第1张图片

大家已经发现了,第一反应就是用 ListView 实现,但是,我们仔细一看,每一个 Item 并不完全一样,况且 Item 数量也不多,所以,我们可以用自定义(组合)控件来实现,把每一个 Item 抽象出来,做成控件,之所以叫组合控件,因为这个控件中用到了很多系统控件,我们只是修改了它们的布局而已。

关于项目相关文章,请访问:

  • Android 项目:手机安全卫士(1)—— 闪屏界面
  • Android 项目:手机安全卫士(2)—— 版本升级
  • Android 项目:手机安全卫士(3)—— 主界面布局

项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe

2 自定义组合控件

先按照上图中的自动更新设置为模板进行实现,包括四个控件:两个 TextView,一个 CheckBox,一条横线。其中横线的实现思路很有意思,它也是一个 TextView,只是设置了它的高度为 1 个像素,然后这是背景为黑色即可。好了,废话不多说,开始写代码,首先创建布局文件:item_setting.xml,内容如下:


    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp">

        <TextView  android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="自动更新设置" android:textColor="@android:color/black"/>

        <TextView  android:id="@+id/tv_desc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="自动更新已开启" android:layout_below="@id/tv_title" android:textColor="#b000"/>

        <CheckBox  android:id="@+id/cb_check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:focusableInTouchMode="false" android:focusable="false" android:layout_alignParentRight="true" android:layout_centerVertical="true"/>

        <TextView  android:layout_width="match_parent" android:layout_height="1px" android:background="@android:color/black" android:layout_marginTop="5dp" android:layout_below="@id/tv_desc"/>
    </RelativeLayout>

这就是自动更新设置的 UI 实现了,注意,该布局中屏蔽了 CheckBox 的点击事件,并且不让它获取焦点。接下来就是创建自定义组件,且使用该 UI 作为界面。创建类:SettingItemView,继承自 RelativeLayout,代码如下:


    /** * Created by XWdoor on 2016/3/1 001 16:19. * 博客:http://blog.csdn.net/xwdoor */
    public class SettingItemView extends RelativeLayout {

        private TextView tvTitle;
        private TextView tvDesc;
        private CheckBox cbCheck;

        public SettingItemView(Context context) {
            super(context);
            initView();
        }

        public SettingItemView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }

        public SettingItemView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView();
        }

        private void initView(){
            View view = View.inflate(getContext(), R.layout.item_setting,null);
            tvTitle = (TextView) view.findViewById(R.id.tv_title);
            tvDesc = (TextView) view.findViewById(R.id.tv_desc);
            cbCheck = (CheckBox) view.findViewById(R.id.cb_check);

            addView(view);
        }

        /** 设置标题 */
        public void setTitle(String title){
            tvTitle.setText(title);
        }

        /** 设置描述 */
        public void setDesc(String desc){
            tvDesc.setText(desc);
        }

        /** 是否开启 */
        public boolean isChecked(){
            return cbCheck.isChecked();
        }

        /** 设置开启状态 */
        public void setChecked(boolean checked){
            cbCheck.setChecked(checked);
        }
    }

SettingItemView 使用了先前定义的布局,并对外公开 4 个接口,分别是:设置标题、设置描述、获取开启状态、设置开启状态。接下来就是使用它了,先是创建 SettingActivity,及其布局文件:activity_setting.xml,在布局文件中,使用刚才自定义的控件,代码如下:


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

        <TextView  android:id="@+id/tv_title" style="@style/TitleBar" android:text="设置"/>

        <!-- 自定义控件 -->
        <net.xwdoor.mobilesafe.view.SettingItemView  android:id="@+id/siv_update" android:layout_width="match_parent" android:layout_height="wrap_content"/>
    </LinearLayout>

至此,自定义控件就弄好了,然后我们就可以像其他普通控件一样使用它了,以下是 SettingActivity 中的代码:


    @Override
    protected void initViews(Bundle savedInstanceState) {
        setContentView(R.layout.activity_setting);
        final SettingItemView sivUpdate = (SettingItemView) findViewById(R.id.siv_update);
        sivUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sivUpdate.setChecked(!sivUpdate.isChecked());
                if(sivUpdate.isChecked()){
                    //若选中,开启自动更新设置
                    sivUpdate.setDesc("自动更新已开启");
                }else {
                    //关闭自动更新
                    sivUpdate.setDesc("自动更新已关闭");
                }
            }
        });
    }

运行结果如图:

3 自定义属性

聪明的你已经发现了,每次点击时,我们都要设置它的描述,sivUpdate.setDesc("自动更新已开启"); 是已开启,sivUpdate.setDesc("自动更新已关闭"); 是已关闭,一个 Item 还好,但是如果有很多个的话,管理起来就比较麻烦了,而且文字常量显示什么的属于 UI 的数据,应该在设计 UI 的时候就设置好的,所以,我们最好将这几个状态,以及标题,设置为 SettingItemView 的属性,也就是我们的自定义属性。

res->values 文件夹中创建资源文件:attr.xml,因为我使用的是 Android Studio,不存在该文件,所以手动创建,然后写自定义属性,代码如下:


    <?xml version="1.0" encoding="utf-8"?>
    <resources>

        <declare-styleable name="SettingItemView">
            <attr name="stitle" format="string" />
            <attr name="desc_on" format="string" />
            <attr name="desc_off" format="string" />
        </declare-styleable>

    </resources>

其中 name 是自定义的,format 是该属性的值类型。好了,很简单吧,接下来使用它了,首先在布局文件的根节点中,为自定义属性声明一个命名空间:xmlns:xwdoor="http://schemas.android.com/apk/res-auto", 其中,xwdoor 是自定义部分,这样,系统就可以找到我们的自定义属性文件的位置,然后就可以直接用了,代码如下:


    <!-- 自定义控件 -->
    <net.xwdoor.mobilesafe.view.SettingItemView  android:id="@+id/siv_update" android:layout_width="match_parent" android:layout_height="wrap_content" xwdoor:stitle="自动更新设置" xwdoor:desc_on="自动更新已开启" xwdoor:desc_off="自动更新已关闭"/>

当然,仅仅是这样,我们是看不到效果的,我们还需要在自定义控件 SettingItemView 中做一些修改才行,代码如下:


/** * Created by XWdoor on 2016/3/1 001 16:19. * 博客:http://blog.csdn.net/xwdoor */
public class SettingItemView extends RelativeLayout {

    public static final String NAMESPACE_XWDOOR = "http://schemas.android.com/apk/res-auto";
    private String mDescOff;
    private String mDescOn;

    private TextView tvTitle;
    private TextView tvDesc;
    private CheckBox cbCheck;

    public SettingItemView(Context context) {
        super(context);
        initView();
    }

    public SettingItemView(Context context, AttributeSet attrs) {
        super(context, attrs);

        int attrCount = attrs.getAttributeCount();
        //获取stitle属性的值
        String title = attrs.getAttributeValue(NAMESPACE_XWDOOR, "stitle");
        //获取关闭设置时的描述
        mDescOn = attrs.getAttributeValue(NAMESPACE_XWDOOR, "desc_on");
        //获取开启设置时的描述
        mDescOff = attrs.getAttributeValue(NAMESPACE_XWDOOR, "desc_off");
        initView();

        setTitle(title);
        setDesc(mDescOff);
    }

    public SettingItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    /** 设置开启状态 */
    public void setChecked(boolean checked){
        cbCheck.setChecked(checked);
        if(checked){
            setDesc(mDescOn);
        }else {
            setDesc(mDescOff);
        }
    }
}

4 总结

好了,到此,我们的自定义组合控件、自定义属性就完成了,本文主要是关于 UI 设计与实现,没有多大难度,主要是知识点的整合与熟悉,且整个项目基本如此,都是熟悉 Android 开发的特性、熟悉代码风格、掌握知识点。

关于项目相关文章,请访问:

  • Android 项目:手机安全卫士(1)—— 闪屏界面
  • Android 项目:手机安全卫士(2)—— 版本升级
  • Android 项目:手机安全卫士(3)—— 主界面布局

项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe

你可能感兴趣的:(android,自定义控件,自定义属性)