其实,android已经给我们提供了比较丰富的状态选择器属性了,比如android:state_checked、android:state_pressed、android:state_selected、android:state_enabled等等,相信大家都不陌生,我今天要介绍的并不是如何使用这些属性,而是教大家如何创建自定义的状态属性。比如我要创建定义一个名字叫state_on的属性,值是一个布尔值,这也是可以实现的。
下图展示了今天的demo例子:
例子中的图片和文字都有2种状态,不同的状态对应了不同的样式,该状态的属性是一个自定义的。
下面介绍下实现步骤:
1.首先得声明这个自定义属性的name和format,在res/values目录下,创建一个xml文件,例如custom_status.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomStatus">
<attr name="state_on" format="boolean" />
</declare-styleable>
</resources>
2.创建一个容器,通过该容器将自定义的状态属性与其关联,然后对外暴露方法来改变自定义属性的状态.
package mchenys.net.csdn.blog.customstatedemo;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* 自定义状态的布局
* Created by mChenys on 2018/4/26.
*/
public class MyCustomStateLayout extends RelativeLayout {
private boolean isStateOn; //状态是否开启
//自定义状态属性
private static final int[] MY_STATE= {R.attr.state_on};
public MyCustomStateLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 对外暴露方法,改变自定义属性的状态
* @param stateOn
*/
public void setStateOn(boolean stateOn) {
if (this.isStateOn != stateOn) {
isStateOn = stateOn;
refreshDrawableState();//刷新状态
}
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
if (isStateOn) {
final int[] drawableState = super
.onCreateDrawableState(extraSpace + 1);
//加入自定义的状态属性
mergeDrawableStates(drawableState, MY_STATE);
return drawableState;
}
return super.onCreateDrawableState(extraSpace);
}
public boolean isStateOn() {
return isStateOn;
}
}
3.至此,就可以试用这个属性来创建选择器了,在本例中,我创建了2个选择器,一个是TextView的color选择器,另一个是ImageView的drawable选择器,分别如下:
res/color/cus_state_font_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cys="http://schemas.android.com/apk/res-auto">
<item android:color="@color/colorAccent" cys:state_on="true"/>
<item android:color="@color/colorPrimary" />
</selector>
res/drawable/cus_state_img_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cys="http://schemas.android.com/apk/res-auto">
<item android:drawable="@drawable/ic_state_on" cys:state_on="true"/>
<item android:drawable="@drawable/ic_launcher"/>
</selector>
最后,就是使用这2个选择器了,在res/layout/activity_main.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<mchenys.net.csdn.blog.customstatedemo.MyCustomStateLayout
android:id="@+id/mcsl"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="20dp"
android:paddingHorizontal="10dp">
<!--android:duplicateParentState="true"
作用是为了让子View的状态和父View同步
-->
<ImageView
android:id="@+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/cus_state_img_bg"
android:duplicateParentState="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/iv"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@+id/iv"
android:duplicateParentState="true"
android:text="Hello World!"
android:textColor="@color/cus_state_font_color"
android:textSize="30sp"
/>
<CheckBox
android:id="@+id/cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/iv"
android:layout_alignParentRight="true"
android:text="开启"/>
</mchenys.net.csdn.blog.customstatedemo.MyCustomStateLayout>
注意,TextView和ImageView的状态改变其实通过它们的父View,即MyCustomStateLayout来改变的,前提是子View需要设置android:duplicateParentState=”true”属性,代码有注释,另一个原因就是MyCustomStateLayout有对外暴露改变状态的方法。当然如果你想改变的是MyCustomStateLayout自身也是可以的,这点比较符合我们使用的习惯,只需在MyCustomStateLayout上使用选择器就可以,比如加一个背景颜色选择器,或者其他你喜欢的都可以,但是别忘了在选择器中要使用我们自定义的属性,才能看到想要的效果。
ok,上面的布局已经设置好了选择器,那么如何触发呢?在本例中,我是通过布局中的checkbox的勾选状态变化来控制MyCustomStateLayout的状态,代码如下:
MainActivity.java
package mchenys.net.csdn.blog.customstatedemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.CompoundButton;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CheckBox checkBox = findViewById(R.id.cb);
final MyCustomStateLayout mcsl = findViewById(R.id.mcsl);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
buttonView.setText("关闭");
mcsl.setStateOn(true);
}else{
buttonView.setText("开启");
mcsl.setStateOn(false);
}
}
});
}
}
当然,你也可以重写MyCustomStateLayout的onTouchEvent,当ACTION_DOWN的时候将状态改为true,这个就随你们喜欢了。