Android ShapeButton

来源:互联网 发布:通达信软件怎么用 编辑:程序博客网 时间:2024/06/08 02:40

写控件的初衷:
      在日常的项目中,我们常常会用到一个按钮拥有两种点击状态,一种是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" />

原创粉丝点击