Android实用View系列之SuperButton(实现shape的大部分功能)

在开发过程中我们的按钮基本都有自己的样式风格,有的时候需要搞个圆角,有时候需要边框,有的时候需要虚线边框亦或者需要一个圆形的按钮。想大部分的实现方式都是写一个shape文件,在里边定义边框圆角等相关属性,如果项目中类似按钮很多切风格各不相同,那我们就需要写很多很多shape文件,这是我们无法忍受的。而SuperButton的出现可以帮你解决以上问题,从此远离shape文件的编写。

Android实用View系列之SuperButton(实现shape的大部分功能)_第1张图片

有图有真相

Android实用View系列之SuperButton(实现shape的大部分功能)_第2张图片
SuperButton.png

github源码地址传送门

开篇

开始之前我们先来看看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,添加自己定义的属性

然后在代码中这样使用

            
image.png

通过配置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));
        }

在运行一下,看看效果

触摸效果.gif

最后

看了以上介绍是不是感觉很简单,那就赶快撸起袖子,自己撸一个玩玩吧!毕竟以后不用在写那么多shape文件了,哈哈!以后可以少搬点砖了

Android实用View系列之SuperButton(实现shape的大部分功能)_第3张图片
搬砖.png

你可能感兴趣的:(Android实用View系列之SuperButton(实现shape的大部分功能))