一个好用的Setting开关(自定义组合控件)

 

 

 

1.在attrs.xml声明好控件属性,这里控件用到了3个文字类描述属性

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SettingSwitchCompat">
        <attr name="title" format="string" />
        <attr name="desc_on" format="string" />
        <attr name="desc_off" format="string" />
    </declare-styleable>
</resources>

 

 

 

 

 

2.view_setting_switchcompat.xml

一般情况会提前写出组合控件的布局,包括组成和摆放位置...

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/selector_setting_switchcompat"
    android:minHeight="?android:listPreferredItemHeight"
    android:padding="16dp">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:textColor="@android:color/black"
        android:textSize="18sp"
        tools:text="某某开关"/>

    <TextView
        android:id="@+id/tvDesc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tvTitle"
        android:layout_marginTop="5dp"
        android:singleLine="true"
        android:textColor="#888888"
        android:textSize="14sp"
        tools:text="开启和关闭的描述"/>

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/sc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true">

    </android.support.v7.widget.SwitchCompat>

</RelativeLayout>

 

 

 

 

 

为了更好的点击用户体验,其中用到了一个背景selector

 

 

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- setting_switchcompat_press 为 #216b74ff -->
    <item android:state_pressed="true" android:drawable="@color/setting_switchcompat_press"/>
    <item android:drawable="@android:color/white"/>

</selector>

 

 

 


3.SettingSwitchCompat  控件的Java类

 

package com.yao.mytestproject;

import android.content.Context;
import android.support.annotation.StringRes;
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * Created by Administrator on 2016/10/1.
 */

public class SettingSwitchCompat extends RelativeLayout {

    private static final String NAMESPACE = "http://schemas.android.com/apk/res-auto";

    private GestureDetector mGestureDetector;

    private TextView tvTitle;
    private TextView tvDesc;
    private SwitchCompat sc;

    private CharSequence title;
    private CharSequence descOn;
    private CharSequence descOff;

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

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

        //获取自定义控件中xml中的属性
        title = attrs.getAttributeValue(NAMESPACE, "title");
        descOn = attrs.getAttributeValue(NAMESPACE, "desc_on");
        descOff = attrs.getAttributeValue(NAMESPACE, "desc_off");

        initView();
    }

    public SettingSwitchCompat(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    private void initView() {
        //inflate出自定义的布局
        View.inflate(getContext(), R.layout.view_setting_switchcompat, this);
        tvTitle = (TextView) findViewById(R.id.tvTitle);
        tvDesc = (TextView) findViewById(R.id.tvDesc);
        sc = (SwitchCompat) findViewById(R.id.sc);

        setTitle(title);
        setChecked(false);
    }

    /**
     * 设置控件标题
     *
     * @param title 标题字符串
     */
    public void setTitle(CharSequence title) {
        tvTitle.setText(title);
    }

    /**
     * 设置控件标题
     *
     * @param resid 字符资源id
     */
    public void setTitle(@StringRes int resid) {
        tvTitle.setText(title);
    }

    /**
     * 设置控件开关时候的描述
     *
     * @param descOn 开启时的描述
     * @param descOff 关闭时的描述
     */
    public void setDesc(CharSequence descOn, CharSequence descOff) {
        this.descOn = descOn;
        this.descOff = descOff;
    }

    /**
     * 设置控件开关时候的描述
     *
     * @param descOnResId 开启时的描述
     * @param descOffResId 关闭时的描述
     */
    public void setDesc(@StringRes int descOnResId, @StringRes int descOffResId) {
        setDesc(getContext().getResources().getText(descOnResId), getContext().getResources().getText(descOffResId));
    }

    /**
     * 获取当前开关状态
     *
     * @return
     */
    public boolean isChecked() {
        return sc.isChecked();
    }

    /**
     * 设置当前开关状态
     *
     * @param check
     */
    public void setChecked(boolean check) {
        sc.setChecked(check);
        if (check) {
            tvDesc.setText(descOn);
        } else {
            tvDesc.setText(descOff);
        }
    }

    @Override
    public boolean performClick() {
        Log.e("YAO", "SettingSwitchCompat.java - performClick() ---------- " );
        setChecked(!isChecked());
        return super.performClick();
    }

}

 

 

自定义组合控件中,如果有属性,都会重写2个参数的那个构造方法来获取xml里面的属性值。

接下来普遍做法就是inflate出组合控件的布局,再根据xml传来的属性值给控件设置一些参数。比如文字,按钮状态。

里面的代码都挺简单,比较重要的是。

第一在我android 事件分发机制源码解析文章里最后部分说了,View在onTouchEvent里会根据传来的down、up事件和一些判断。最终得出这是点击事件(不是长按,不是拖动),然后执行performClick()方法。所以可以重写performClick()方法,在里面写SwitchCompat开关的逻辑。

第二因为View里面的performClick()会执行到setOnClickListener传进去的点击回调事件。所以在需要在最后调用一下super.performClick()而不是直接return true消费这个点击事件。这样以后在使用这个SettingSwitchCompat时依旧可以用setOnClickListener方法来写一些业务逻辑。

 

 

 


 

 

使用方法:

1.在xml中写出控件  因为有3个新属性不属于原生的,注意写出res-auto这个命名空间。app是我取的,名字不限定。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent">

    <com.yao.mytestproject.SettingSwitchCompat
        android:id="@+id/settingSwitchCompat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        app:desc_off="已关闭"
        app:desc_on="已开启"
        app:title="缓存开关"/>

</RelativeLayout>

 

 

 

 

 

 

 

2.代码中使用

 

public class TestActivity extends AppCompatActivity {

    private SettingSwitchCompat settingSwitchCompat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        settingSwitchCompat = (SettingSwitchCompat) findViewById(R.id.settingSwitchCompat);
        settingSwitchCompat.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("YAO", "TestActivity.java - onClick() ---------- settingSwitchCompat.isChecked()" + settingSwitchCompat.isChecked() );
            }
        });

    }

}

由于重写的performClick方法里,先执行了改变状态的setChecked(!isChecked())方法,然后才执行传过去onClick回调。

 

所以在onClick方法里,我们就能准备的获取控件当前状态,以便保存或者使用。
 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值