package com.loaderman.settingitemviewdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; public class MainActivity extends AppCompatActivity { private SettingItemView siv1; private SettingItemView siv2; private SettingItemView siv3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); siv1 = (SettingItemView) findViewById(R.id.siv_test1); siv2 = (SettingItemView) findViewById(R.id.siv_test2); siv3 = (SettingItemView) findViewById(R.id.siv_test3); siv1.setTitle("测试1"); siv1.setToggleOn(true); siv2.setToggleOn(false); siv1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { siv1.toggle(); } }); siv2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (siv2.isToggleOn()) { siv2.setToggleOn(false); } else { siv2.setToggleOn(true); } } }); siv3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } }
package com.loaderman.settingitemviewdemo; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; /** * * <p/> * 如果一个控件A包含了控件B, 那么A就是B的父控件, B是A的子控件; 和继承没有任何关系, 只是一种称谓而已. * <p/> * 自定义组合控件: * <p/> * 1. 写一个类继承ViewGroup(LinearLayout, RelativeLayout) * 2. 给当前空布局添加布局对象View.inflate(getContext(), R.layout.setting_item_view, this); * 3. 添加方法, 修改标题和背景 * 4. 维护开关状态, boolean isOpen, 点击控件,切换开关状态,并更新开关图片 * * 自定义属性: * 1. 在values中创建attrs.xml文件, 配置自定义属性 * 2. 在布局文件中声明命名空间, 并给相关控件配置自定义属性 * 3. 在自定义控件中, 从属性集合中获取自定义属性,并更新相关控件 */ public class SettingItemView extends RelativeLayout { private TextView tvTitle; private ImageView ivToggle; private boolean isOpen = false;//标记当前开关状态 private static final String NAMESPACE = "http://schemas.android.com/apk/res-auto"; public SettingItemView(Context context) { this(context, null); } public SettingItemView(Context context, AttributeSet attrs) { this(context, attrs, -1); } public SettingItemView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); //1.从AttributeSet中取出自定义的属性 String title = attrs.getAttributeValue(NAMESPACE, "title"); int bgId = attrs.getAttributeIntValue(NAMESPACE, "bg", 0);//0,1,2 boolean showToggle = attrs.getAttributeBooleanValue(NAMESPACE, "show_toggle", true); //2.根据自定义属性的值更新相关控件 setTitle(title);//修改标题 //修改背景 switch (bgId) { case 0: setBackgroundResource(R.drawable.first_selector); break; case 1: setBackgroundResource(R.drawable.middle_selector); break; case 2: setBackgroundResource(R.drawable.last_selector); break; } //控制开关的显示和隐藏 ivToggle.setVisibility(showToggle ? VISIBLE : GONE); } private void initView() { //给当前空布局添加布局对象 //A view group that will be the parent //参3: 如果是null, 表示加载出的布局对象没有父控件, 绝大部分情况下都传null //如果是this,代表在加载布局对象时, 以当前的SettingItemView为父控件; 这样写也可以实现给SettingItemView填充布局的效果 View view = View.inflate(getContext(), R.layout.setting_item_view, this); //addView(view); tvTitle = (TextView) view.findViewById(R.id.tv_title); ivToggle = (ImageView) view.findViewById(R.id.iv_toggle); } //公开一个方法,供外界修改标题 public void setTitle(String title) { tvTitle.setText(title); } //获取当前开关状态 public boolean isToggleOn() { return isOpen; } //修改当前开关状态 public void setToggleOn(boolean isOpen) { this.isOpen = isOpen; System.out.println("当前开关状态:" + isOpen); //修改开关图片 ivToggle.setImageResource(isOpen ? R.drawable.on : R.drawable.off); } //如果开,则关; 如果关,则开 public void toggle() { setToggleOn(!isOpen); } }
自定义属性.在values/下新建attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SettingItemView"> <!--自定义标题属性--> <attr name="title" format="string"/> <!--自定义背景属性, 枚举--> <attr name="bg"> <enum name="first" value="0" /> <enum name="middle" value="1" /> <enum name="last" value="2" /> </attr> <!--自定义是否显示开关的属性--> <attr name="show_toggle" format="boolean"/> </declare-styleable> </resources>
activtity_main.xml,使用自定义属性记得添加命名空间
xmlns:YOU_NAME="http://schemas.android.com/apk/res-auto"
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:loaderman="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" tools:context="com.loaderman.settingitemviewdemo.MainActivity"> <com.loaderman.settingitemviewdemo.SettingItemView android:id="@+id/siv_test1" android:layout_width="match_parent" android:layout_height="wrap_content" loaderman:bg="first" /> <com.loaderman.settingitemviewdemo.SettingItemView android:id="@+id/siv_test2" android:layout_width="match_parent" android:layout_height="wrap_content" loaderman:title="测试2" loaderman:bg="middle" /> <com.loaderman.settingitemviewdemo.SettingItemView android:id="@+id/siv_test3" android:layout_width="match_parent" android:layout_height="wrap_content" loaderman:bg="last" loaderman:title="测试3" loaderman:show_toggle="false" /> </LinearLayout>
setting_item_view.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" android:paddingBottom="10dp" android:paddingLeft="5dp" android:paddingRight="5dp" android:paddingTop="10dp" > <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:textColor="@color/black" android:textSize="18sp" /> <ImageView android:id="@+id/iv_toggle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:src="@drawable/off" /> </RelativeLayout>
实现效果: