XButton-萬能的Button告別各種shape檔案

zhuxh發表於2019-01-19

XButton介紹

XButton取代各種shape檔案,因為大家專案中基本都是用到的button都不需要變化大小,所以寫了個簡單的[XButton]

參考效果

[圖片上傳失敗...(image-7258a7-1530790718680)]

0.控制元件原始碼

先上程式碼:github.com/zhxhcoder/X… 參考我的上篇文章:www.jianshu.com/p/c8f8818a7…

1. 引用方法

通過Maven或Gradle引用

<dependency>
  <groupId>com.zhxh</groupId>
  <artifactId>xbuttonlib</artifactId>
  <version>3.9</version>
  <type>pom</type>
</dependency>
複製程式碼
implementation 'com.zhxh:xbuttonlib:3.9'
複製程式碼

2. 使用方法

    <com.zhxh.android.xbuttonlib.XButton
        android:id="@+id/XButton4"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:layout_marginLeft="112dp"
        android:layout_marginStart="112dp"
        android:layout_marginTop="204dp"
        android:text="圓角矩形 "
        android:textColor="@color/colorPrimary"
        app:XangleCorner="2dp"
        app:XstrokeColor="@color/colorPrimary"
        app:XstrokeWidth="1dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
複製程式碼

實體的圓角矩形,需要配置三個欄位

        app:XangleCorner="2dp"   //表示圓角
        app:XdefaultColor="@color/colorPrimary" //正常顏色
        app:XpressedColor="@color/colorPrimaryDark" //按壓後的顏色
複製程式碼
    <com.zhxh.android.xbuttonlib.XButton
        android:id="@+id/XButton5"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="140dp"
        android:layout_marginStart="140dp"
        android:layout_marginTop="276dp"
        android:text="圓形 "
        android:textColor="@color/colorPrimary"
        app:XangleCorner="45dp"
        app:XstrokeColor="@color/colorPrimary"
        app:XstrokeWidth="1dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

複製程式碼

空心圓角矩形,需配置三個欄位

        app:XangleCorner="45dp"    //表示圓角
        app:XstrokeColor="@color/colorPrimary" //表示邊框顏色
        app:XstrokeWidth="1dp"               //表示邊框寬度
複製程式碼

3. 版本變更

V1.3版本加上了可以程式碼控制的功能

比如

    //對外定義介面
    public void setPressedColor(int pressedColor) {
        this.pressedColor = pressedColor;
        setBtnDrawable();
    }

    public void setDefaultColor(int defaultColor) {
        this.defaultColor = defaultColor;
        setBtnDrawable();
    }

    public void setStrokeColor(int strokeColor) {
        this.strokeColor = strokeColor;
        setBtnDrawable();
    }
複製程式碼

使用方法

            button1.setDefaultColor(0xffff0000);
複製程式碼
V1.4版本加上了自定義的XdrawablePadding屬性

原生的android:drawablePadding這個屬性在 我們給view設定的寬度或者高度足夠小(以至於將兩者擠壓在一起)的時候,這個屬性才會起作用,也即在圖片和文字之間會有間距產生。如果你的view所設定的寬度或者高度大於drawableLeft/drawableRight或者drawableTop/drawableBottom所產生的間距,那麼這個屬性當然也就不會起作用。

可以通過自定義View來精確的計算:

我們先自定義屬性drawablePadding來設定間距,並提供方法給外部呼叫 重寫setCompoundDrawablesWithIntrinsicBounds()方法來獲取我們設定的drawable寬度。 最後重寫onLayout方法,因為這裡面改變了一些位置屬性,需要通過重新佈局才能起作用。

    <com.zhxh.xbuttonlib.XButton
        android:id="@+id/XButton6"
        android:layout_width="322dp"
        android:layout_height="51dp"
        android:layout_marginEnd="28dp"
        android:layout_marginRight="28dp"
        android:layout_marginTop="352dp"
        android:drawableRight="@drawable/ic_arrow"
        android:gravity="center"
        android:text="圓角矩形"
        android:textColor="@android:color/white"
        app:XangleCorner="2dp"
        app:XdefaultColor="@color/colorPrimary"
        app:XdrawablePadding="10dp"
        app:XpressedColor="@color/colorPrimaryDark"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
複製程式碼

在這裡加入新的配置XdrawablePadding

        app:XdrawablePadding="10dp"
複製程式碼
V2.1版本加上了動畫設定
        app:XisShaderAnim="true"

複製程式碼
V2.8版本刪除了defaultColor 並新增了 pressTextColor 以及方便地從 solid型到stroke型button的相互轉換
        button1.setOnClickListener(v -> {
            Toast.makeText(this, "button1", Toast.LENGTH_LONG).show();
            button1.setStrokeAttr(0xffff0000, 2);
        });

複製程式碼
    <com.zhxh.xbuttonlib.XButton
        android:id="@+id/XButton5"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="140dp"
        android:layout_marginStart="140dp"
        android:layout_marginTop="276dp"
        android:gravity="center"
        android:text="圓形"
        android:textColor="@color/colorPrimary"
        app:XangleCorner="45dp"
        app:XpressedColor="@color/colorPrimaryDark"
        app:XpressedTextColor="@android:color/white"
        app:XstrokeColor="@color/colorPrimary"
        app:XstrokeWidth="1dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
複製程式碼
        android:textColor="@color/colorPrimary"

        app:XpressedColor="@color/colorPrimaryDark"

複製程式碼

程式碼實現

    //處理按下去的顏色 區分solid和stroke模式
    public boolean setColor(int action) {
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                gradientDrawable.setColor(pressedColor);
                this.setTextColor(pressedTextColor);
                break;
            case MotionEvent.ACTION_UP:
                gradientDrawable.setColor(solidColor);
                this.setTextColor(defaultTextColor);
                break;
            case MotionEvent.ACTION_CANCEL:
                gradientDrawable.setColor(solidColor);
                this.setTextColor(defaultTextColor);
                break;
        }

        return isTouchPass;
    }

複製程式碼

4. 關鍵程式碼分析

    GradientDrawable gradientDrawable;
複製程式碼

GradientDrawable可以在res/drawable目錄下以xml檔案用標籤來定義。看看官方文件給出的xml定義說明吧。

<?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"] />
    <padding
        android:left="integer"
        android:top="integer"
        android:right="integer"
        android:bottom="integer" />
    <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>

複製程式碼
    private void setBtnDrawable() {
        //設定按鈕顏色
        gradientDrawable.setColor(solidColor);
        //設定按鈕的邊框寬度
        gradientDrawable.setStroke(strokeWidth, strokeColor);
        //設定按鈕圓角大小
        gradientDrawable.setCornerRadius(angleCorner);
        setBackgroundDrawable(gradientDrawable);
        ...
    }

複製程式碼

自定義GradientDrawable,並根據屬性自定義,以取代shape檔案

原生的android:drawablePadding這個屬性在 我們給view設定的寬度或者高度足夠小(以至於將兩者擠壓在一起)的時候,這個屬性才會起作用,也即在圖片和文字之間會有間距產生。如果你的view所設定的寬度或者高度大於drawableLeft/drawableRight或者drawableTop/drawableBottom所產生的間距,那麼這個屬性當然也就不會起作用。

可以通過自定義View來精確的計算:

我們先自定義屬性drawablePadding來設定間距,並提供方法給外部呼叫 重寫setCompoundDrawablesWithIntrinsicBounds()方法來獲取我們設定的drawable寬度。 最後重寫onLayout方法,因為這裡面改變了一些位置屬性,需要通過重新佈局才能起作用。


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        Paint textPaint = getPaint();
        String text = getText().toString();
        textPaint.getTextBounds(text, 0, text.length(), bounds);

        int textWidth = bounds.width();
        int factor = (position == DrawablePosition.LEFT_AND_RIGHT) ? 2 : 1;
        int contentWidth = drawableWidth + drawablePadding * factor + textWidth;
        int horizontalPadding = (int) ((getWidth() / 2.0) - (contentWidth / 2.0));

        setCompoundDrawablePadding(-horizontalPadding + drawablePadding);

        switch (position) {
            case LEFT:
                setPadding(horizontalPadding, getPaddingTop(), 0, getPaddingBottom());
                break;

            case RIGHT:
                setPadding(0, getPaddingTop(), horizontalPadding, getPaddingBottom());
                break;

            case LEFT_AND_RIGHT:
                setPadding(horizontalPadding, getPaddingTop(), horizontalPadding, getPaddingBottom());
                break;

            default:
                setPadding(0, getPaddingTop(), 0, getPaddingBottom());
        }
    }


    //重新設定位置
    @Override
    public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) {
        super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);

        if (left != null && right != null) {
            drawableWidth = left.getIntrinsicWidth() + right.getIntrinsicWidth();
            position = DrawablePosition.LEFT_AND_RIGHT;
        } else if (left != null) {
            drawableWidth = left.getIntrinsicWidth();
            position = DrawablePosition.LEFT;
        } else if (right != null) {
            drawableWidth = right.getIntrinsicWidth();
            position = DrawablePosition.RIGHT;
        } else {
            position = DrawablePosition.NONE;
        }

        requestLayout();
    }
複製程式碼

開源協議

Copyright (C) 2018, zhxh

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

www.apache.org/licenses/LI…

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

相關文章