在开发过程中我们的按钮基本都有自己的样式风格,有的时候需要搞个圆角,有时候需要边框,有的时候需要虚线边框亦或者需要一个圆形的按钮。想大部分的实现方式都是写一个shape文件,在里边定义边框圆角等相关属性,如果项目中类似按钮很多切风格各不相同,那我们就需要写很多很多shape文件,这是我们无法忍受的。而SuperButton的出现可以帮你解决以上问题,从此远离shape文件的编写。
有图有真相
github源码地址传送门
开篇
开始之前我们先来看看shape文件是如何编写的
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
<gradient
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:useLevel=["true" | "false"] />
<size
android:width="integer"
android:height="integer" />
<solid
android:color="color" />
<stroke
android:width="integer"
android:color="color"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>
以上shape文件列出了常用的属性,当然并不是所有属性都会用到,我们就以这个shape文件作为参考开始本篇文章的分析。
我们知道写好shape文件之后是通过android:background="@drawable/shape"这样的方式引入的,那么Android有没有方法去获取shape相关属性的类呐,经过一番查阅发现还是有个GradientDrawable类可以实现的,关于GradientDrawable的介绍请自行Google了解。
通过GradientDrawable的源码可以看到里边有很多方法和shape各个节点的名称一样,所以这正是我们需要的类,剩下的就是开始用GradientDrawable实现我们的封装之路。
具体实现
由于代码不复杂,看下注释也都能理解,就直接贴代码了
先初始化一下gradientDrawable = new GradientDrawable();
/**
* 设置shape类型,对应shape的四个属性
*/
private void setShape() {
switch (shapeType) {
case RECTANGLE:
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
break;
case OVAL:
gradientDrawable.setShape(GradientDrawable.OVAL);
break;
case LINE:
gradientDrawable.setShape(GradientDrawable.LINE);
break;
case RING:
gradientDrawable.setShape(GradientDrawable.RING);
break;
}
}
通过一下方法可以整体设置四个圆角也可以对各个角分别设置
/**
* 只有类型是矩形的时候设置圆角半径才有效
*/
private void setRadius() {
if (shapeType == GradientDrawable.RECTANGLE) {
if (cornersRadius != 0) {
gradientDrawable.setCornerRadius(dip2px(mContext, cornersRadius));//设置圆角的半径
} else {
//1、2两个参数表示左上角,3、4表示右上角,5、6表示右下角,7、8表示左下角
gradientDrawable.setCornerRadii(
new float[]
{
cornersTopLeftRadius, cornersTopLeftRadius,
cornersTopRightRadius, cornersTopRightRadius,
cornersBottomRightRadius, cornersBottomRightRadius,
cornersBottomLeftRadius, cornersBottomLeftRadius
}
);
}
}
}
设置渐变色的相关属性
/**
* 设置背景颜色
* 如果设定的有Orientation 就默认为是渐变色的Button,否则就是纯色的Button
*/
private void setOrientation() {
if (gradientOrientation != -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
gradientDrawable.setOrientation(getOrientation(gradientOrientation));
if (gradientCenterColor == -1) {
gradientDrawable.setColors(new int[]{gradientStartColor, gradientEndColor});
} else {
gradientDrawable.setColors(new int[]{gradientStartColor, gradientCenterColor, gradientEndColor});
}
switch (gradientType) {
case linear:
gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
break;
case radial:
gradientDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT);
gradientDrawable.setGradientRadius(gradientGradientRadius);
break;
case sweep:
gradientDrawable.setGradientType(GradientDrawable.SWEEP_GRADIENT);
break;
}
gradientDrawable.setUseLevel(gradientUseLevel);
if (gradientCenterX != 0 && gradientCenterY != 0) {
gradientDrawable.setGradientCenter(gradientCenterX, gradientCenterY);
}
}
} else {
gradientDrawable.setColor(solidColor);
}
}
/**
* 设置颜色渐变类型
*
* @param gradientOrientation gradientOrientation
* @return Orientation
*/
private GradientDrawable.Orientation getOrientation(int gradientOrientation) {
GradientDrawable.Orientation orientation = null;
switch (gradientOrientation) {
case TOP_BOTTOM:
orientation = GradientDrawable.Orientation.TOP_BOTTOM;
break;
case TR_BL:
orientation = GradientDrawable.Orientation.TR_BL;
break;
case RIGHT_LEFT:
orientation = GradientDrawable.Orientation.RIGHT_LEFT;
break;
case BR_TL:
orientation = GradientDrawable.Orientation.BR_TL;
break;
case BOTTOM_TOP:
orientation = GradientDrawable.Orientation.BOTTOM_TOP;
break;
case BL_TR:
orientation = GradientDrawable.Orientation.BL_TR;
break;
case LEFT_RIGHT:
orientation = GradientDrawable.Orientation.LEFT_RIGHT;
break;
case TL_BR:
orientation = GradientDrawable.Orientation.TL_BR;
break;
}
return orientation;
}
对应shape中的size设置shape布局大小及设置边框和分割线
/*
* 设置size的值
*/
private void setSize() {
if (shapeType == RECTANGLE) {
gradientDrawable.setSize(sizeWidth, sizeHeight);
}
}
/**
* 设置边框 宽度 颜色 虚线 间隙
*/
private void setBorder() {
gradientDrawable.setStroke(dip2px(mContext, strokeWidth), strokeColor, strokeDashWidth, strokeDashGap);
}
至此需要的方法都已经写完了,剩下的就是自定义view继承button,添加自己定义的属性
然后在代码中这样使用
<com.allen.library.SuperButton
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_margin="5dp"
android:text="圆角边框"
stv:sCornersRadius="5dp"
stv:sStrokeColor="@color/colorAccent"
stv:sStrokeWidth="0.2dp" />
通过配置shapeType的类型可以以此实现矩形,椭圆,线和圆环
至此关于shape代码实现的部分已经完成了,可以实现shape很多中效果,不过细心的你发现按钮按下的触摸反馈没有了,以前都是通过selector去实现的,那么代码能否实现呐。答案肯定是OK啦
/**
* 获取设置之后的Selector
*
* @return stateListDrawable
*/
public StateListDrawable getSelector() {
StateListDrawable stateListDrawable = new StateListDrawable();
//注意该处的顺序,只要有一个状态与之相配,背景就会被换掉
//所以不要把大范围放在前面了,如果sd.addState(new[]{},normal)放在第一个的话,就没有什么效果了
stateListDrawable.addState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}, getDrawable(android.R.attr.state_pressed));
stateListDrawable.addState(new int[]{-android.R.attr.state_enabled}, getDrawable(-android.R.attr.state_enabled));
stateListDrawable.addState(new int[]{}, getDrawable(android.R.attr.state_enabled));
return stateListDrawable;
}
然后把selector设置到setBackground中就好了
if (Build.VERSION.SDK_INT < 16) {
setBackgroundDrawable(useSelector ? getSelector() : getDrawable(0));
} else {
setBackground(useSelector ? getSelector() : getDrawable(0));
}
在运行一下,看看效果
最后
看了以上介绍是不是感觉很简单,那就赶快撸起袖子,自己撸一个玩玩吧!毕竟以后不用在写那么多shape文件了,哈哈!以后可以少搬点砖了