GitHub
問題:
在平時(shí)的項(xiàng)目開發(fā)中堕汞,為了實(shí)現(xiàn)圓角矩形、帶邊框的矩形复隆、圓拨匆、橢圓等效果,然后在drawble文件下創(chuàng)建大量的 shape 標(biāo)簽的xml挽拂。項(xiàng)目不斷迭代惭每,還會(huì)出現(xiàn)完全效果一樣的設(shè)計(jì),因?yàn)闀r(shí)間太久而忘記是那個(gè)xml了亏栈,然后就又新建一個(gè)xml台腥,用于實(shí)現(xiàn)。最終導(dǎo)致文件太多绒北,不便維護(hù)黎侈。
解決:
為了解決上面的問題,小弟我自己封裝了一個(gè) ShapeCreator 工具類闷游,用于動(dòng)態(tài)的創(chuàng)建圓角矩形峻汉、帶邊框的矩形贴汪、圓、橢圓等效果休吠。
ShapeCreator介紹
ShapeCreator支持動(dòng)態(tài)設(shè)置shape標(biāo)簽下的 <solid /> <size /> <corners /> <stroke /> <gradient /> 以及<shape shape=''>,同時(shí)還支持state_press,state_enabled 狀態(tài)變化扳埂。
<shape>標(biāo)簽對(duì)應(yīng)的Android類為GradientDrawable,所以ShapeCreator就是對(duì)GradientDrawable進(jìn)行了一個(gè)方法封裝蛛碌,使用起來簡單方便聂喇。
剪輯視頻20190829_095849.gif
使用:
圓角
img_1.png
//圓角
ShapeCreator.create()
.setCornerRadius(10)
.setSolidColor(Color.GRAY)
.into(btn1);
圓角邊框
img_2.png
//圓角邊框
ShapeCreator.create()
.setCornerRadius(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn2);
圓角邊框-虛線效果
img_4.png
//圓角邊框-虛線
ShapeCreator.create()
.setCornerRadius(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.setStrokeDashWidth(10)
.setStrokeDashGap(10)
.into(btn9);
//半圓角
ShapeCreator.create()
.setCornerRadius(100)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.setStrokeDashWidth(10)
.setStrokeDashGap(10)
.into(btn10);
單獨(dú)設(shè)置四個(gè)圓角
img_3.png
//左上圓角
ShapeCreator.create()
.setCornerRadiusLT(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn3);
//右上圓角
ShapeCreator.create()
.setCornerRadiusRT(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn4);
//左下圓角
ShapeCreator.create()
.setCornerRadiusLB(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn5);
//右下圓角
ShapeCreator.create()
.setCornerRadiusRB(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn6);
//對(duì)角圓角
ShapeCreator.create()
.setCornerRadiusLT(10)
.setCornerRadiusRB(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn7);
//對(duì)角圓角
ShapeCreator.create()
.setCornerRadiusRT(10)
.setCornerRadiusLB(10)
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn8);
圓形
img_5.png
//圓形
ShapeCreator.oval()
.setSolidColor(Color.GRAY)
.into(btn11);
//橢圓
ShapeCreator.oval()
.setSolidColor(Color.GRAY)
.setStrokeColor(Color.CYAN)
.setStrokeWidth(2)
.into(btn12);
線
img_6.png
//線
ShapeCreator.line()
.setStrokeColor(Color.RED)
.setStrokeWidth(1)
.into(btn13);
//虛線
ShapeCreator.line()
.setStrokeColor(Color.CYAN)
.setStrokeWidth(1)
.setStrokeDashWidth(10)
.setStrokeDashGap(10)
.into(btn14);
漸變效果
img_7.png
//漸變 線性
ShapeCreator.create()
.setGradientType(ShapeCreator.LINEAR_GRADIENT)
.setGradientAngle(90)
.setGradientStartColor(Color.RED)
.setGradientEndColor(Color.BLUE)
.into(btn15);
//漸變 圓形
ShapeCreator.create()
.setGradientType(ShapeCreator.RADIAL_GRADIENT)
.setGradientRadius(50)
.setGradientCenterX(0.5f)
.setGradientCenterY(0.5f)
.setGradientStartColor(Color.RED)
.setGradientCenterColor(Color.CYAN)
.setGradientEndColor(Color.BLUE)
.into(btn16);
//漸變 sweep
ShapeCreator.create()
.setGradientType(ShapeCreator.SWEEP_GRADIENT)
.setGradientCenterX(0.5f)
.setGradientCenterY(0.5f)
.setGradientStartColor(Color.RED)
.setGradientCenterColor(Color.YELLOW)
.setGradientEndColor(Color.BLUE)
.into(btn17);
帶交互狀態(tài)
img_8.png
//狀態(tài)
ShapeCreator.create()
.setCornerRadius(10)
.setStateEnabled(true)
.setSolidColor(Color.GRAY)
.setSolidPressColor(Color.DKGRAY)
.setStrokeColor(Color.CYAN)
.setStrokePressColor(Color.MAGENTA)
.setStrokeWidth(2)
.setStateTextColorEnabled(true)
.setTextColor(Color.BLACK)
.setTextPressColor(Color.WHITE)
.into(btn18);
//狀態(tài)
ShapeCreator.create()
.setCornerRadius(10)
.setStateEnabled(true)
.setSolidColor(Color.GRAY)
.setSolidPressColor(Color.DKGRAY)
.setSolidDisableColor(Color.LTGRAY)
.setStrokeColor(Color.CYAN)
.setStrokePressColor(Color.MAGENTA)
.setStrokeDisableColor(Color.LTGRAY)
.setStrokeWidth(2)
.setStateTextColorEnabled(true)
.setTextColor(Color.BLACK)
.setTextDisableColor(Color.WHITE)
.into(btn19);
btn19.setEnabled(false);
源碼
public class ShapeCreator {
/**
* 對(duì)應(yīng)標(biāo)簽 shape
*/
private int shape;
public static final int RECTANGLE = 0;
public static final int OVAL = 1;
public static final int LINE = 2;
/**
* 對(duì)應(yīng)標(biāo)簽 corners
*/
private float cornerRadius; //四個(gè)角的半徑
private float cornerRadiusLT; //左上角半徑
private float cornerRadiusRT; //右上角半徑
private float cornerRadiusLB; //左下角半徑
private float cornerRadiusRB; //右下角半徑
/**
* 對(duì)應(yīng)標(biāo)簽 solid
*/
private int solidColor;
private int solidPressColor = 0;
private int solidDisableColor = 0;
/**
* 對(duì)應(yīng)標(biāo)簽stroke
*/
private int strokeColor;
private int strokePressColor = 0;
private int strokeDisableColor = 0;
private int strokeWidth;
private int strokeDashWidth;
private int strokeDashGap;
/**
* 對(duì)應(yīng)標(biāo)簽gradient
*/
private int gradientType = -1;
public static final int LINEAR_GRADIENT = 0;
public static final int RADIAL_GRADIENT = 1;
public static final int SWEEP_GRADIENT = 2;
private int gradientAngle;
private float gradientCenterX;
private float gradientCenterY;
private int gradientStartColor;
private int gradientCenterColor = 0;
private int gradientEndColor;
private float gradientRadius;
/**
* 對(duì)應(yīng)標(biāo)簽 size
*/
private int width;
private int height;
/**
* true 默認(rèn)dp
* false 默認(rèn)px
*/
private boolean dpUnitEnabled = true;
/**
* 狀態(tài)標(biāo)簽是否啟用 selector 標(biāo)簽
*/
private boolean stateEnabled = false;
/**
* 是否支持設(shè)置文字顏色state
*/
private boolean stateTextColorEnabled = false;
private int textColor, textPressColor, textDisableColor;
public static ShapeCreator create() {
return new ShapeCreator();
}
/**
* 直接指定類型 shape line
* @return
*/
public static ShapeCreator line() {
return new ShapeCreator().setShape(LINE);
}
/**
* 直接指定類型 shape oval
* @return
*/
public static ShapeCreator oval() {
return new ShapeCreator().setShape(OVAL);
}
/**
* <corners android:radius=""/>
*
* @param radius
* @return
*/
public ShapeCreator setCornerRadius(float radius) {
this.cornerRadius = radius;
return this;
}
/**
* <corners android:topLeftRadius=""/>
*
* @param cornerRadiusLT
* @return
*/
public ShapeCreator setCornerRadiusLT(float cornerRadiusLT) {
this.cornerRadiusLT = cornerRadiusLT;
return this;
}
/**
* <corners android:topRightRadius=""/>
*
* @param cornerRadiusRT
* @return
*/
public ShapeCreator setCornerRadiusRT(float cornerRadiusRT) {
this.cornerRadiusRT = cornerRadiusRT;
return this;
}
/**
* <corners android:bottomLeftRadius=""/>
*
* @param cornerRadiusLB
* @return
*/
public ShapeCreator setCornerRadiusLB(float cornerRadiusLB) {
this.cornerRadiusLB = cornerRadiusLB;
return this;
}
/**
* <corners android:bottomRightRadius=""/>
*
* @param cornerRadiusRB
* @return
*/
public ShapeCreator setCornerRadiusRB(float cornerRadiusRB) {
this.cornerRadiusRB = cornerRadiusRB;
return this;
}
/**
* <solid android:color=""/>
*
* @param solidColor
* @return
*/
public ShapeCreator setSolidColor(int solidColor) {
this.solidColor = solidColor;
return this;
}
/**
* state_press='true' color
*
* @param solidPressColor
* @return
*/
public ShapeCreator setSolidPressColor(int solidPressColor) {
this.solidPressColor = solidPressColor;
return this;
}
/**
* state_enabled='false' color
*
* @param solidDisableColor
* @return
*/
public ShapeCreator setSolidDisableColor(int solidDisableColor) {
this.solidDisableColor = solidDisableColor;
return this;
}
/**
* <stroke android:color=""/>
*
* @param strokeColor
* @return
*/
public ShapeCreator setStrokeColor(int strokeColor) {
this.strokeColor = strokeColor;
return this;
}
/**
* state_press='true' color
*
* @param strokePressColor
* @return
*/
public ShapeCreator setStrokePressColor(int strokePressColor) {
this.strokePressColor = strokePressColor;
return this;
}
/**
* state_enabled='false' color
*
* @param strokeDisableColor
* @return
*/
public ShapeCreator setStrokeDisableColor(int strokeDisableColor) {
this.strokeDisableColor = strokeDisableColor;
return this;
}
/**
* <stroke android:width=""/>
*
* @param strokeWidth
* @return
*/
public ShapeCreator setStrokeWidth(int strokeWidth) {
this.strokeWidth = strokeWidth;
return this;
}
/**
* <stroke android:dashWidth=""/>
*
* @param strokeDashWidth
* @return
*/
public ShapeCreator setStrokeDashWidth(int strokeDashWidth) {
this.strokeDashWidth = strokeDashWidth;
return this;
}
/**
* <stroke android:dashGap=""/>
*
* @param strokeDashGap
* @return
*/
public ShapeCreator setStrokeDashGap(int strokeDashGap) {
this.strokeDashGap = strokeDashGap;
return this;
}
/**
* <shape xmlns:android="http://schemas.android.com/apk/res/android"
* android:shape="">
*
* @param shape
* @return
*/
public ShapeCreator setShape(int shape) {
this.shape = shape;
return this;
}
/**
* <gradient android:type=""/>
*
* @param gradientType
* @return
*/
public ShapeCreator setGradientType(int gradientType) {
this.gradientType = gradientType;
return this;
}
/**
* <gradient android:angle=""/>
*
* @param gradientAngle
* @return
*/
public ShapeCreator setGradientAngle(int gradientAngle) {
this.gradientAngle = gradientAngle;
defaultGradientType();
return this;
}
/**
* <gradient android:centerX=""/>
*
* @param gradientCenterX
* @return
*/
public ShapeCreator setGradientCenterX(float gradientCenterX) {
this.gradientCenterX = gradientCenterX;
defaultGradientType();
return this;
}
/**
* <gradient android:centerY=""/>
*
* @param gradientCenterY
* @return
*/
public ShapeCreator setGradientCenterY(float gradientCenterY) {
this.gradientCenterY = gradientCenterY;
defaultGradientType();
return this;
}
/**
* <gradient android:startColor=""/>
*
* @param gradientStartColor
* @return
*/
public ShapeCreator setGradientStartColor(int gradientStartColor) {
this.gradientStartColor = gradientStartColor;
defaultGradientType();
return this;
}
/**
* <gradient android:centerColor=""/>
*
* @param gradientCenterColor
* @return
*/
public ShapeCreator setGradientCenterColor(int gradientCenterColor) {
this.gradientCenterColor = gradientCenterColor;
defaultGradientType();
return this;
}
/**
* * <gradient android:endColor=""/>
*
* @param gradientEndColor
* @return
*/
public ShapeCreator setGradientEndColor(int gradientEndColor) {
this.gradientEndColor = gradientEndColor;
defaultGradientType();
return this;
}
/**
* * <gradient android:gradientRadius=""/>
*
* @param gradientRadius
* @return
*/
public ShapeCreator setGradientRadius(float gradientRadius) {
this.gradientRadius = gradientRadius;
defaultGradientType();
return this;
}
/**
* <size android:width="" android:height=""/>
*
* @param w
* @param h
* @return
*/
public ShapeCreator setSize(int w, int h) {
this.width = w;
this.height = h;
return this;
}
/**
* 是否dp轉(zhuǎn)px
*
* @param dpUnitEnabled true dp false px
* @return
*/
public ShapeCreator setDpUnitEnabled(boolean dpUnitEnabled) {
this.dpUnitEnabled = dpUnitEnabled;
return this;
}
/**
* 是否開啟交互狀態(tài)
*
* @param stateEnabled true 支持 state_press="true' state_enabled="false"
* @return
*/
public ShapeCreator setStateEnabled(boolean stateEnabled) {
this.stateEnabled = stateEnabled;
return this;
}
/**
* 文字顏色交互狀態(tài)
*
* @param stateTextColorEnabled
* @return
*/
public ShapeCreator setStateTextColorEnabled(boolean stateTextColorEnabled) {
this.stateTextColorEnabled = stateTextColorEnabled;
return this;
}
/**
* 默認(rèn)顏色
*
* @param textColor
* @return
*/
public ShapeCreator setTextColor(int textColor) {
this.textColor = textColor;
return this;
}
/**
* 按下顏色
*
* @param textPressColor
* @return
*/
public ShapeCreator setTextPressColor(int textPressColor) {
this.textPressColor = textPressColor;
return this;
}
/**
* 禁用顏色
*
* @param textDisableColor
* @return
*/
public ShapeCreator setTextDisableColor(int textDisableColor) {
this.textDisableColor = textDisableColor;
return this;
}
public void into(View view) {
Context context = view.getContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
GradientDrawable drawable = createGradientDrawable(context, -1);
drawable.setUseLevel(false);
ViewCompat.setBackground(view, drawable);
} else {
if (!stateEnabled) {
GradientDrawable drawable = createGradientDrawable(context, -1);
drawable.setUseLevel(false);
ViewCompat.setBackground(view, drawable);
} else {
StateListDrawable drawable = new StateListDrawable();
GradientDrawable press = createGradientDrawable(context, 1);
press.setUseLevel(false);
GradientDrawable disable = createGradientDrawable(context, 2);
disable.setUseLevel(false);
GradientDrawable normal = createGradientDrawable(context, 3);
normal.setUseLevel(false);
drawable.addState(new int[]{android.R.attr.state_pressed}, press);
drawable.addState(new int[]{-android.R.attr.state_enabled}, disable);
drawable.addState(new int[]{}, normal);
ViewCompat.setBackground(view, drawable);
}
}
if (stateTextColorEnabled && view instanceof TextView) {
int[][] state = new int[3][];
state[0] = new int[]{android.R.attr.state_pressed};
state[1] = new int[]{-android.R.attr.state_enabled};
state[2] = new int[]{};
if (textColor != 0) {
if (textPressColor == 0) {
textPressColor = textColor;
}
if (textDisableColor == 0) {
textDisableColor = textColor;
}
ColorStateList colorStateList = new ColorStateList(state, new int[]{textPressColor, textDisableColor, textColor});
((TextView) view).setTextColor(colorStateList);
}
}
}
private GradientDrawable createGradientDrawable(Context context, int type) {
GradientDrawable drawable = new GradientDrawable();
setXmlShapeType(drawable);
setXmlSolid(drawable, type);
setXmlSize(drawable, context);
setXmlCorners(drawable, context);
setXmlStroke(drawable, context, type);
setXmlGradient(drawable, context);
return drawable;
}
/**
* <shape
* android:shape='xxxx'>
*
* @param drawable
*/
private void setXmlShapeType(GradientDrawable drawable) {
drawable.setShape(shape);
}
/**
* <corners />
*
* @param drawable
* @param context
*/
private void setXmlCorners(GradientDrawable drawable, Context context) {
if (shape == RECTANGLE) {
//矩形可以設(shè)置圓角
if (cornerRadius != 0) {
drawable.setCornerRadius(dip2px(context, cornerRadius));
} else {
drawable.setCornerRadii(new float[]{
//左上
dip2px(context, cornerRadiusLT),
dip2px(context, cornerRadiusLT),
//右上
dip2px(context, cornerRadiusRT),
dip2px(context, cornerRadiusRT),
//右下
dip2px(context, cornerRadiusRB),
dip2px(context, cornerRadiusRB),
//左下
dip2px(context, cornerRadiusLB),
dip2px(context, cornerRadiusLB)
});
}
}
}
/**
* <solid/>
*
* @param drawable
* @param type 當(dāng)stateEnabled=true,同時(shí)Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP 生效
* 1:state_pressed=true
* 2:state_enabled=false
* 3:默認(rèn)狀態(tài)
*/
private void setXmlSolid(GradientDrawable drawable, int type) {
if (!stateEnabled) {
drawable.setColor(solidColor);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int[][] state = new int[3][];
state[0] = new int[]{android.R.attr.state_pressed};
state[1] = new int[]{-android.R.attr.state_enabled};
state[2] = new int[]{};
ColorStateList colorStateList = new ColorStateList(state, new int[]{solidPressColor, solidDisableColor, solidColor});
drawable.setColor(colorStateList);
} else {
switch (type) {
case 1:
drawable.setColor(solidPressColor);
break;
case 2:
drawable.setColor(solidDisableColor);
break;
case 3:
drawable.setColor(solidColor);
break;
}
}
}
}
/**
* <stroke/>
*
* @param drawable
* @param context
* @param type 當(dāng)stateEnabled=true,同時(shí)Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP 生效
* 1:state_pressed=true
* 2:state_enabled=false
* 3:默認(rèn)狀態(tài)
*/
private void setXmlStroke(GradientDrawable drawable, Context context, int type) {
if (!stateEnabled) {
drawable.setStroke(dip2px(context, strokeWidth), strokeColor,
dip2px(context, strokeDashWidth), dip2px(context, strokeDashGap));
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int[][] state = new int[3][];
state[0] = new int[]{android.R.attr.state_pressed};
state[1] = new int[]{-android.R.attr.state_enabled};
state[2] = new int[]{};
ColorStateList colorStateList = new ColorStateList(state, new int[]{strokePressColor, strokeDisableColor, strokeColor});
drawable.setStroke(dip2px(context, strokeWidth), colorStateList,
dip2px(context, strokeDashWidth), dip2px(context, strokeDashGap));
} else {
int color = solidColor;
switch (type) {
case 1:
color = strokePressColor;
break;
case 2:
color = strokeDisableColor;
break;
case 3:
color = strokeColor;
break;
}
drawable.setStroke(dip2px(context, strokeWidth), color,
dip2px(context, strokeDashWidth), dip2px(context, strokeDashGap));
}
}
}
/**
* <size/>
*
* @param drawable
* @param context
*/
private void setXmlSize(GradientDrawable drawable, Context context) {
if (width > 0 && height > 0) {
drawable.setSize(dip2px(context, width), dip2px(context, height));
}
}
/**
* <gradient/>
*
* @param drawable
* @param context
*/
private void setXmlGradient(GradientDrawable drawable, Context context) {
if (gradientType == -1) return;
if (gradientType == LINEAR_GRADIENT) {
drawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
} else if (gradientType == RADIAL_GRADIENT) {
drawable.setGradientType(GradientDrawable.RADIAL_GRADIENT);
} else if (gradientType == SWEEP_GRADIENT) {
drawable.setGradientType(GradientDrawable.SWEEP_GRADIENT);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (gradientCenterColor == 0) {
drawable.setColors(new int[]{gradientStartColor, gradientEndColor});
} else {
drawable.setColors(new int[]{gradientStartColor, gradientCenterColor, gradientEndColor});
}
GradientDrawable.Orientation mOrientation = GradientDrawable.Orientation.TOP_BOTTOM;
switch (gradientAngle) {
case 0:
mOrientation = GradientDrawable.Orientation.LEFT_RIGHT;
break;
case 45:
mOrientation = GradientDrawable.Orientation.BL_TR;
break;
case 90:
mOrientation = GradientDrawable.Orientation.BOTTOM_TOP;
break;
case 135:
mOrientation = GradientDrawable.Orientation.BR_TL;
break;
case 180:
mOrientation = GradientDrawable.Orientation.RIGHT_LEFT;
break;
case 225:
mOrientation = GradientDrawable.Orientation.TR_BL;
break;
case 270:
mOrientation = GradientDrawable.Orientation.TOP_BOTTOM;
break;
case 315:
mOrientation = GradientDrawable.Orientation.TL_BR;
break;
}
drawable.setOrientation(mOrientation);
} else {
drawable.setColor(solidColor);
}
drawable.setGradientCenter(gradientCenterX, gradientCenterY);
drawable.setGradientRadius(dip2px(context, gradientRadius));
}
/**
* 設(shè)置默認(rèn)漸變類型
*/
private void defaultGradientType() {
if (gradientType == -1) {
gradientType = LINEAR_GRADIENT;
}
}
private int dip2px(Context context, float dipValue) {
if (dpUnitEnabled) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
} else {
return (int) dipValue;
}
}
}