Android ShapeButton - 简化xml selector写法

写控件的初衷:
      在日常的项目中,我们常常会用到一个按钮拥有两种点击状态,一种是pressed state,另外一种是unpressed state,通常我们会使用xml先写两个drawable xml文件:


(1)pressed state xml文件[android_shape_round_error_button_pressed.xml]:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp"></corners>
    <solid android:color="@color/error_button_pressed_color"></solid>
</shape>


(2)unpressed state xml文件[android_shape_round_error_button_unpressed.xml]:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp"></corners>
    <solid android:color="@color/error_button_unpressed_color"></solid>
</shape>


(3)利用上面两个xml最后写一个selctor xml 文件[android_error_button.xml]:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/android_shape_round_error_button_pressed" android:state_pressed="true"></item>
    <item android:drawable="@drawable/android_shape_round_error_button_unpressed" android:state_pressed="false"></item>
</selector>


(4)在自己页面xml控件属性中应用此selector背景:
 

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/android_error_button"/>


       在以上的两个xml文件中,我们看似是很简单的操作,一旦项目中冗杂的代码按钮,你会每个都要写这样的代码,如果你只是追求吧项目完工之类的,于是就直接用个普通背景
代替了,这样你也就没必要来写自定义View了吧,Coder是一个动脑的行业,因此我们选择这一行业,就应该在项目中吸取应有的教训,怎么把下一次的项目更好、更快地去完成,
这样的代码自己写着舒服,别人接管的人看着也舒服,后期维护一方便。

控件思路:
    此类控件无非就是先加载的时候默认有一个颜色,在点击事件或者触摸事件的时候就换了一种加深的颜色,我们不可能只想到我们做到
能换颜色就行了,因为即使你把两种颜色传递给你控件,那么你还要想这个颜色对应加深的颜色是什么颜色,没有必要,既然我们要
自定义控件,那么就一次性搞定控件,总之一句话,那就是我们怎么方便使用、怎么简单就怎么设计View。那么看似简单的控件有这么
几个问题:
(1)动态设置2种背景颜色
(2)默认颜色和点击颜色相似但是点击颜色要身些。
第一个问题其实不算什么问题,我们只要是控件都可以设置颜色,只是有一个问题的是,颜色处置问题。目前颜色拥有色调、饱和度
、色值。这种颜色变暗就只能在饱和度上面下功夫。饱和度在android有没有方法呢,我们开始只能猜测。于是我们可以在Android中寻找对应的类和方法,当然第一次想到的是Color
类,你可以先看饱和度对应的English:saturation,这时候你可以在Color类中find this word.你将会看着下面这几个类:

/**
 * Convert the argb color to its HSV components.
 *     hsv[0] is Hue [0 .. 360)
 *     hsv[1] is Saturation [0...1]
 *     hsv[2] is Value [0...1]
 * @param color the argb color to convert. The alpha component is ignored.
 * @param hsv  3 element array which holds the resulting HSV components.
 */
public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) {
    RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
}


     此方法是将ARGB颜色转成HSV组件,在HSV组件中可以设置hsv[1]的饱和度,当然看到这,我们的目的还是没达到的,我们的
目的是调颜色的饱和度,那么饱和度已经调整了,那么肯定需要HSV组件转换成颜色。我们先猜测是HSVto...类似的方法搜索,
结果是就是这个方法下面,所有有时候别先急着搜,先看看需要的方法的附近代码。下面就是HSV组件转换成颜色方法:

/**
 * Convert HSV components to an ARGB color. Alpha set to 0xFF.
 *     hsv[0] is Hue [0 .. 360)
 *     hsv[1] is Saturation [0...1]
 *     hsv[2] is Value [0...1]
 * If hsv values are out of range, they are pinned.
 * @param hsv  3 element array which holds the input HSV components.
 * @return the resulting argb color
*/
public static int HSVToColor(@Size(3) float hsv[]) {
    return HSVToColor(0xFF, hsv);
}


好了以上问题现在都不是问题了,现在是可以着手写自己的自定义View,此处的思路只是一种,我只是利用原有的控件的
属性加上原有的方法构造新控件,不想再draw,个人认为再次渲染没有原控件来的性能优越。


控件代码[ShapeButton]:
(1)attr.xml:

<!--ShapeButton-->
<attr name="shape" format="enum">
    <enum name="rectangle" value="0"></enum>
    <enum name="oval" value="1"></enum>
</attr>
<declare-styleable name="ShapeButton">
    <attr name="solid_color" format="color" />
    <attr name="stroke_color" format="color"/>
    <attr name="stroke_width" format="dimension"/>
    <attr name="corner_radius" format="dimension"/>
    <attr name="top_left_corner_radius" format="dimension"/>
    <attr name="top_right_corner_radius" format="dimension"/>
    <attr name="bottom_left_corner_radius" format="dimension"/>
    <attr name="bottom_right_corner_radius" format="dimension"/>
    <attr name="shape"/>
    <attr name="saturation" format="float"/>
</declare-styleable>


(2)ShapeButton源码:
 

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.R;


/**
 * Created by Relin on 2017/11/22.
 * This class is ButtonView you can setting background,stroke color
 * stroke width ,stroke width,the kinds of corner in sample way.
 * button color is change auto when click it and the color is old
 * color's saturation 92% ,if you think isn't suit to you application
 * you can change it,saturation is bright deep.
 */
public class ShapeButton extends TextView implements View.OnTouchListener{


    private int solidColor = Color.parseColor("#B4B4B4");
    private int strokeWidth = 0;
    private int strokeColor = Color.parseColor("#B4B4B4");
    private int shape = 0;
    private float cornerRadius = 0;
    private float topLeftCornerRadius = 0;
    private float topRightCornerRadius = 0;
    private float bottomLeftCornerRadius = 0;
    private float bottomRightCornerRadius = 0;


    private float saturation = 0.90f;


    private Drawable normalDrawable;
    private Drawable pressedDrawable;


    public ShapeButton(Context context) {
        super(context);
        initAttrs(context,null);
    }


    public ShapeButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context,attrs);
    }


    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                setDrawable(pressedDrawable);
                break;
            case MotionEvent.ACTION_UP:
                setDrawable(normalDrawable);
                break;
        }
        return false;
    }


    private void initAttrs(Context context, AttributeSet attrs) {
        setOnTouchListener(this);
        if (attrs!=null){
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShapeButton);
            solidColor = typedArray.getColor(R.styleable.ShapeButton_solid_color, Color.parseColor("#B4B4B4"));
            strokeWidth = (int) typedArray.getDimension(R.styleable.ShapeButton_stroke_width, 0);
            strokeColor = typedArray.getColor(R.styleable.ShapeButton_stroke_color, Color.parseColor("#B4B4B4"));
            if (typedArray.getString(R.styleable.ShapeButton_shape)!=null){
                shape = Integer.parseInt(typedArray.getString(R.styleable.ShapeButton_shape));
            }
            cornerRadius = typedArray.getDimension(R.styleable.ShapeButton_corner_radius, 0);
            topLeftCornerRadius = typedArray.getDimension(R.styleable.ShapeButton_top_left_corner_radius, 0);
            topRightCornerRadius = typedArray.getDimension(R.styleable.ShapeButton_top_right_corner_radius, 0);
            bottomLeftCornerRadius = typedArray.getDimension(R.styleable.ShapeButton_bottom_left_corner_radius, 0);
            bottomRightCornerRadius = typedArray.getDimension(R.styleable.ShapeButton_bottom_right_corner_radius, 0);
            saturation = typedArray.getFloat(R.styleable.ShapeButton_saturation,0.90f);
            typedArray.recycle();
        }
        normalDrawable = createShape(shape,strokeWidth, strokeColor, solidColor, cornerRadius, topLeftCornerRadius, topRightCornerRadius, bottomLeftCornerRadius, bottomRightCornerRadius);
        pressedDrawable = createShape(shape, strokeWidth, createPressedColor(strokeColor), createPressedColor(solidColor), cornerRadius, topLeftCornerRadius, topRightCornerRadius, bottomLeftCornerRadius, bottomRightCornerRadius);


        setDrawable(normalDrawable);
    }


    /**
     * create pressed state color by HSV
     *  hsv[2] :values is big - is deep or bright
     * @param color
     * @return
     */
    private int createPressedColor(int color) {
        int alpha = Color.alpha(color);
        float[] hsv = new float[3];
        Color.colorToHSV(color, hsv);
        hsv[2] *= saturation;
        return Color.HSVToColor(alpha, hsv);
    }


    /**
     * for all android api
     * set all kinds of background.
     * @param drawable
     */
    private void setDrawable(Drawable drawable) {
        if (Build.VERSION.SDK_INT >= 16) {
            setBackground(drawable);
        } else {
            setBackgroundDrawable(drawable);
        }
    }


    /**
     * create shape drawable
     * this method create you self background drawable
     * by shape.the same as code in xml.
     *
     * @param shape                   GradientDrawable.RECTANGLE  GradientDrawable.OVAL
     * @param strokeWidth             button stroke width
     * @param strokeColor             button stroke color
     * @param solidColor              button background color
     * @param cornerRadius            all corner is the same as is the radius
     * @param topLeftCornerRadius     top left corner radius
     * @param topRightCornerRadius    top right corner radius
     * @param bottomLeftCornerRadius  bottom left corner radius
     * @param bottomRightCornerRadius bottom right corner radius
     * @return
     */
    public Drawable createShape(int shape, int strokeWidth,
                                int strokeColor, int solidColor, float cornerRadius,
                                float topLeftCornerRadius, float topRightCornerRadius,
                                float bottomLeftCornerRadius, float bottomRightCornerRadius) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setShape(shape);
        drawable.setSize(10,10);
        drawable.setStroke(strokeWidth, strokeColor);
        drawable.setColor(solidColor);
        if (cornerRadius!=0){
            drawable.setCornerRadius(cornerRadius);
        }else{
            drawable.setCornerRadii(new float[]{topLeftCornerRadius, topLeftCornerRadius, topRightCornerRadius, topRightCornerRadius, bottomLeftCornerRadius, bottomLeftCornerRadius, bottomRightCornerRadius, bottomRightCornerRadius});
        }
        return drawable;
    }




}

 


(3)使用:
按钮类型可以是圆形、正方形、椭圆形,shape的选择+View自身的宽高设置就可以了。其中saturation设置点击后的饱和度的。

<com.android.widget.ShapeButton
    android:id="@+id/elven_fbtn_reloading"
    android:layout_width="160dp"
    android:layout_height="35dp"
    android:layout_marginTop="15dp"
    android:text="重新加载"
    app:corner_radius="8dp"
    android:textColor="@android:color/white"
    android:textSize="14sp"
    app:shape="rectangle"
    android:gravity="center" />

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值