簡介
日常項目開發(fā)中,經(jīng)常會遇到把TextView設(shè)置成一個按鈕,就像下面這個:
而一般的實現(xiàn)方式就是在res/drawable目錄下定義一個drawable.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="@color/blue" />
</shape>
然后設(shè)置為TextView的背景弹谁,如果需要選中時改變狀態(tài),可以這么設(shè)置:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bule" android:state_pressed="false" />
<item android:drawable="@drawable/red" android:state_pressed="true" />
<item android:drawable="@drawable/bule" />
</selector>
這樣寫的好處是簡單易懂句喜,但是如果項目中用到了很多不同風(fēng)格的邊框背景時预愤,就會創(chuàng)建非常多的相似的資源文件,比較麻煩藤滥。為了避免這種麻煩鳖粟,這里使用Java代碼來創(chuàng)建Drawable。
自定義ShapeTextView
使用自定義view繼承TextView來實現(xiàn)上面說的效果
定義屬性
在res/values/attrs.xml中添加自定義屬性
<!--自定義矩形邊框的TextView-->
<declare-styleable name="ShapeTextView">
<!--是否使用Selector選擇器-->
<attr name="openSelector" format="boolean" />
<!--填充色-->
<attr name="solidColor" format="color" />
<!--邊框色-->
<attr name="strokeColor" format="color" />
<!--按下填充色-->
<attr name="solidTouchColor" format="color" />
<!--按下邊框色-->
<attr name="strokeTouchColor" format="color" />
<!--邊框?qū)挾?->
<attr name="strokeWidth" format="dimension" />
<!--圓角弧度-->
<attr name="radius" format="dimension" />
<!--四個角的圓角弧度-->
<attr name="topLeftRadius" format="dimension" />
<attr name="topRightRadius" format="dimension" />
<attr name="bottomLeftRadius" format="dimension" />
<attr name="bottomRightRadius" format="dimension" />
<!--虛線邊框?qū)挾?->
<attr name="dashWidth" format="dimension" />
<!--虛線邊框間隙-->
<attr name="dashGap" format="dimension" />
</declare-styleable>
自定義View繼承TextView
/**
* @author Lin
* @date 2019/8/22
* @description 實現(xiàn)自定義圓角背景
* 支持
* 1.四邊圓角
* 2.指定邊圓角
* 3.支持填充色以及邊框色,邊框虛線
* 4.支持按下效果
*/
@SuppressLint("AppCompatCustomView")
public class ShapeTextView extends TextView {
private boolean openSelector;
//自定背景邊框Drawable
private GradientDrawable gradientDrawable;
//按下時的Drawable
private GradientDrawable selectorDrawable;
//填充色
private int solidColor = 0;
//邊框色
private int strokeColor = 0;
//按下填充色
private int solidTouchColor = 0;
//按下邊框色
private int strokeTouchColor = 0;
//按下字體色
private int textTouchColor = 0;
//邊框?qū)挾? private int strokeWidth = 0;
//四個角的弧度
private float radius;
private float topLeftRadius;
private float topRightRadius;
private float bottomLeftRadius;
private float bottomRightRadius;
//邊框虛線的寬度
float dashWidth = 0;
//邊框虛線的間隙
float dashGap = 0;
//字體色
private int textColor = 0;
public ShapeTextView(Context context) {
this(context, null);
}
public ShapeTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ShapeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
//默認背景
gradientDrawable = getNeedDrawable(new float[]{topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius},
solidColor, strokeWidth, strokeColor, dashWidth, dashGap);
//如果設(shè)置了選中時的背景
if (openSelector) {
selectorDrawable = getNeedDrawable(new float[]{topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius},
solidTouchColor, strokeWidth, strokeTouchColor, dashWidth, dashGap);
//動態(tài)生成Selector
StateListDrawable stateListDrawable = new StateListDrawable();
//是否按下
int pressed = android.R.attr.state_pressed;
stateListDrawable.addState(new int[]{pressed}, selectorDrawable);
stateListDrawable.addState(new int[]{}, gradientDrawable);
setBackground(stateListDrawable);
} else {
setBackground(gradientDrawable);
}
}
/**
* 初始化參數(shù)
*
* @param context
* @param attrs
*/
private void init(Context context, AttributeSet attrs) {
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ShapeTextView, 0, 0);
openSelector = ta.getBoolean(R.styleable.ShapeTextView_openSelector, false);
solidColor = ta.getInteger(R.styleable.ShapeTextView_solidColor, 0x00000000);
strokeColor = ta.getInteger(R.styleable.ShapeTextView_strokeColor, 0x00000000);
solidTouchColor = ta.getInteger(R.styleable.ShapeTextView_solidTouchColor, 0x00000000);
strokeTouchColor = ta.getInteger(R.styleable.ShapeTextView_strokeTouchColor, 0x00000000);
textTouchColor = ta.getInteger(R.styleable.ShapeTextView_textTouchColor, 0x00000000);
textColor = getCurrentTextColor();
strokeWidth = (int) ta.getDimension(R.styleable.ShapeTextView_strokeWidth, 0);
//四個角單獨設(shè)置會覆蓋radius設(shè)置
radius = ta.getDimension(R.styleable.ShapeTextView_radius, 0);
topLeftRadius = ta.getDimension(R.styleable.ShapeTextView_topLeftRadius, radius);
topRightRadius = ta.getDimension(R.styleable.ShapeTextView_topRightRadius, radius);
bottomLeftRadius = ta.getDimension(R.styleable.ShapeTextView_bottomLeftRadius, radius);
bottomRightRadius = ta.getDimension(R.styleable.ShapeTextView_bottomRightRadius, radius);
dashGap = ta.getDimension(R.styleable.ShapeTextView_dashGap, 0);
dashWidth = ta.getDimension(R.styleable.ShapeTextView_dashWidth, 0);
ta.recycle();
}
/**
* @param radius 四個角的半徑
* @param colors 漸變的顏色
* @param strokeWidth 邊框?qū)挾? * @param strokeColor 邊框顏色
* @return
*/
public static GradientDrawable getNeedDrawable(float[] radius, int[] colors, int strokeWidth, int strokeColor) {
//TODO:判斷版本是否大于16 項目中默認的都是Linear散射 都是從左到右 都是只有開始顏色和結(jié)束顏色
GradientDrawable drawable;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
drawable = new GradientDrawable();
drawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
drawable.setColors(colors);
} else {
drawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
}
drawable.setCornerRadii(radius);
drawable.setStroke(strokeWidth, strokeColor);
drawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
return drawable;
}
/**
* @param radius 四個角的半徑
* @param bgColor 背景顏色
* @param strokeWidth 邊框?qū)挾? * @param strokeColor 邊框顏色
* @return
*/
public static GradientDrawable getNeedDrawable(float[] radius, int bgColor, int strokeWidth, int strokeColor) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setCornerRadii(radius);
drawable.setStroke(strokeWidth, strokeColor);
drawable.setColor(bgColor);
return drawable;
}
/**
* @param radius 四個角的半徑
* @param bgColor 背景顏色
* @param strokeWidth 邊框?qū)挾? * @param strokeColor 邊框顏色
* @param dashWidth 虛線邊框?qū)挾? * @param dashGap 虛線邊框間隙
* @return
*/
public static GradientDrawable getNeedDrawable(float[] radius, int bgColor, int strokeWidth, int strokeColor, float dashWidth, float dashGap) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setCornerRadii(radius);
drawable.setStroke(strokeWidth, strokeColor, dashWidth, dashGap);
drawable.setColor(bgColor);
return drawable;
}
}
使用示例
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="50dp">
<com.lin.module_base.view.ShapeTextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:gravity="center"
android:text="@string/about"
app:openSelector="true"
app:radius="10dp"
app:solidColor="@color/white"
app:solidTouchColor="@color/gray_light"
app:strokeColor="@color/blue"
app:strokeTouchColor="@color/red"
app:strokeWidth="1dp"
app:textTouchColor="@color/red" />
<com.lin.module_base.view.ShapeTextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:gravity="center"
android:text="@string/about"
app:bottomRightRadius="20dp"
app:openSelector="true"
app:solidColor="@color/white"
app:solidTouchColor="@color/gray_light"
app:strokeColor="@color/blue"
app:strokeTouchColor="@color/red"
app:strokeWidth="1dp"
app:textTouchColor="@color/red"
app:topLeftRadius="20dp" />
<com.lin.module_base.view.ShapeTextView
android:id="@+id/text2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:gravity="center"
android:text="@string/about"
app:dashGap="1dp"
app:dashWidth="2dp"
app:openSelector="true"
app:radius="10dp"
app:solidColor="@color/white"
app:strokeColor="@color/blue"
app:strokeTouchColor="@color/red"
app:strokeWidth="0.5dp"
app:textTouchColor="@color/red" />
<com.lin.module_base.view.ShapeTextView
android:id="@+id/text3"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:layout_margin="5dp"
android:gravity="center"
android:text="@string/about"
app:openSelector="true"
app:radius="25dp"
app:solidColor="@color/blue"
app:strokeColor="@color/blue"
app:strokeTouchColor="@color/red"
app:strokeWidth="1dp"
app:textTouchColor="@color/red" />
</LinearLayout>
效果如下圖:
踩坑
如果需要selector選擇器的效果拙绊,需要在xml中設(shè)置app:openSelector="true"
然后要給View設(shè)置監(jiān)聽事件
text1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
總結(jié)
這里我們使用了Java代碼來創(chuàng)建Drawable向图,可以把常用方法提取到工具類中泳秀。
日常開發(fā)中也有其他類似的需要定義CheckBox、RadioButton等背景的榄攀,也可以參考這種做法嗜傅。