最近再写一个需求,就是有一个多种状态的文本,每种状态都对应一个背景色。
最初就是用笨方法,每次都是代码手动改变TextView的backgroundDrawable,不胜繁琐 。然后就想有没有类似Button的pressed和focus类似的,能不能自定义状态,然后写一个selector,让textView的background能根据状态自动改变。
于是乎就在网上找了一下,功夫不负有心人,还真找到了几个大佬写过类似的东西,就借鉴一下,顺便记下来留待后用。
话不多说,直接上代码。
package com.example.lee.rollingtextview.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.lee.rollingtextview.R;
@SuppressLint("AppCompatCustomView")
public class TagTextView extends TextView {
public enum State {STATE_RED, STATE_RELLOW, STATE_GREEN}
private static final int[] STATE_LIST1 = {R.attr.state_1};
private static final int[] STATE_LIST2 = {R.attr.state_2};
private static final int[] STATE_LIST3 = {R.attr.state_3};
private int mState;
public TagTextView(Context context) {
super(context);
}
public TagTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public TagTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(@NonNull Context context, @Nullable AttributeSet attrs) {
if (null != attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagTextView);
mState = a.getInteger(R.styleable.TagTextView_state, State.STATE_RED);
a.recycle();
setState(mState);
}
}
public void setState(State state) {
this.mState = state;
refreshDrawableState();
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
switch (mState) {
case State.STATE_RED:
mergeDrawableStates(drawableState, STATE_LIST1);
break;
case State.STATE_YELLOW:
mergeDrawableStates(drawableState, STATE_LIST2);
break;
case State.STATE_GREEN:
mergeDrawableStates(drawableState, STATE_LIST3);
break;
default:
mergeDrawableStates(drawableState, STATE_LIST1);
break;
}
}
}
就是TextView拓展了一下,增加了几个自定义状态。自定义状态在attrs.xml文件中声明如下
<resources>
<declare-styleable name="TagTextView">
<attr name="state_1" format="boolean"/>
<attr name="state_2" format="boolean"/>
<attr name="state_3" format="boolean"/>
<attr name="state" format="enum">
<enum name="red" value="0"/>
<enum name="yellow" value="1"/>
<enum name="green" value="2"/>
attr>
declare-styleable>
resources>
然后写一个selector,这里有一个selector小技巧,可以给selector加一个简单的渐入渐出的动画效果,
android:enterFadeDuration=”@android:integer/config_shortAnimTime”
android:exitFadeDuration=”@android:integer/config_shortAnimTime”
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:enterFadeDuration="@android:integer/config_shortAnimTime"
android:exitFadeDuration="@android:integer/config_shortAnimTime">
<item android:drawable="@drawable/shape_state_1" app:state_1="true" />
<item android:drawable="@drawable/shape_state_2" app:state_2="true" />
<item android:drawable="@drawable/shape_state_3" app:state_3="true" />
selector>
在xml文件中调用和正常的TextView调用没啥区别,就是background要设置成该selector,然后设置一种状态就ok了。
<com.example.lee.rollingtextview.view.TagTextView
android:layout_gravity="center_horizontal"
android:id="@+id/tv_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/state_selector"
app:state="yellow"
android:text="hahahahah"
android:textSize="25sp"
android:textColor="@color/white" />
注意到,我在TagTextView中还预留了一个可以改变状态的public函数setState,在外部可以调用这个函数手动改变状态。
就写到这里吧,如有错误的地方还望大佬指正,感激不尽~
后来我发现这样写,有点特化了。最后要扩展也没有想象中那么容易。因为要改变背景还是要调用一下setState函数,那还不如每次去调用setBackground呢,也没必要绕一大圈。
所以我最后采用的针对不同tag显示不同的背景的做法就是:还是笨方法!
private void initTagMap(){
private Map tagDrawableMap = tagDrawableMap = new HashMap<>();
tagDrawableMap.put("申购", R.drawable.shape_state_1);
tagDrawableMap.put("定投", R.drawable.shape_state_1);
tagDrawableMap.put("赎回", R.drawable.shape_state_2)
tagDrawableMap.put("分红", R.drawable.shape_state_3);
tagDrawableMap.put("调仓", R.drawable.shape_state_3);
}
private Drawable getDrawableFromMap(String tag) {
int resId = tagDrawableMap.get(tag) == null ? R.drawable.shape_state_1 : tagDrawableMap.get(tag);
return ContextCompat.getDrawable(this, resId);
}
ViewCompat.setBackground(tvTag, getDrawableFromMap(mData.get(position).tag));