Nút Android tiêu chuẩn với màu khác


735

Tôi muốn thay đổi màu sắc của nút Android tiêu chuẩn một chút để phù hợp hơn với thương hiệu của khách hàng.

Cách tốt nhất mà tôi đã tìm thấy để làm điều này cho đến nay là thay đổi khả Buttonnăng có thể rút ra thành có thể rút được ở res/drawable/red_button.xml:

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

Nhưng làm điều đó đòi hỏi tôi thực sự tạo ra ba ngăn kéo khác nhau cho mỗi nút tôi muốn tùy chỉnh (một cho nút ở trạng thái nghỉ, một khi tập trung và một khi nhấn). Điều đó có vẻ phức tạp và không DRY hơn tôi cần.

Tất cả những gì tôi thực sự muốn làm là áp dụng một số loại chuyển đổi màu sắc cho nút. Có cách nào dễ dàng hơn để thay đổi màu của nút hơn tôi đang làm không?


Câu trả lời:


724

Tôi phát hiện ra rằng tất cả có thể được thực hiện trong một tệp khá dễ dàng. Đặt một cái gì đó giống như đoạn mã sau vào một tệp có tên custom_button.xmlvà sau đó đặt background="@drawable/custom_button"trong chế độ xem nút của bạn:

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="@color/yellow1"
                android:endColor="@color/yellow2"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="@color/orange4"
                android:startColor="@color/orange5"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="@color/blue2"
                android:startColor="@color/blue25"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>

43
Điều đó hoạt động tốt cho màu nền - bạn có thể đặt màu văn bản theo cùng một cách không?
Rachel

8
Điều này cho tôi "Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')" những tài liệu tham khảo để xây dựng trong màu sắc? có vẻ như tôi cần một res / value / color.xml để thực hiện công việc này
Harry Wood

8
@HarryWood bạn phải xác định các màu đó trong res / value / colors.xml của bạn. Hoặc, thay thế chúng bằng "# ff0000", "# 00ff00", cho mục đích thử nghiệm @ cfarm54 Tệp đó sẽ được đặt trong thư mục res / drawable / custom_button.xml @emmby Cảm ơn đoạn mã!
Espinchi

17
Con trỏ tuyệt vời, cảm ơn! Cũng lưu ý cho những người khác đang thử điều này, thứ tự của các mục trong bộ chọn là rất quan trọng. Nếu bạn đặt <item> không có bộ lọc trạng thái trước trong tệp, nó sẽ ghi đè phần còn lại.
mikerowehl

9
để thực hiện công việc này, hãy đặt custom_button.xml trong thư mục res / "drawable" của bạn - và tạo một tệp res / value / colors.xml với các nội dung sau: stackoverflow.com/questions/3738886/ tựa - thay đổi tên màu trong một trong hai tệp để làm cho nó hoạt động
sami

308

Theo dõi câu trả lời của Tomasz, bạn cũng có thể lập trình cài đặt sắc thái của toàn bộ nút bằng chế độ nhân PorterDuff. Điều này sẽ thay đổi màu nút chứ không chỉ là màu.

Nếu bạn bắt đầu với nút tô màu xám tiêu chuẩn:

button.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);

sẽ cung cấp cho bạn một nút màu đỏ,

button.getBackground().setColorFilter(0xFF00FF00, PorterDuff.Mode.MULTIPLY);

sẽ cung cấp cho bạn một nút tô màu xanh lục, v.v., trong đó giá trị đầu tiên là màu ở định dạng hex.

Nó hoạt động bằng cách nhân giá trị màu của nút hiện tại với giá trị màu của bạn. Tôi chắc chắn rằng bạn cũng có thể làm được nhiều hơn với các chế độ này.


2
Wow, chỉ cần thử nó ra và nó là hoàn toàn tuyệt vời. Cảm ơn bạn! Bạn có tình cờ biết có cách nào để thực hiện nó thông qua xml không?
emmby

4
Các bạn, hãy kiểm tra nó trên HTC Desire! Chúng có các nút tiêu chuẩn khác nhau. Các nút của tôi sử dụng mã này trông tuyệt vời ở đó KHI cài đặt bố cục nhất định như "40dp". Với "quấn_content", nó ổn.
OneWorld

5
Khẳng định, giải pháp này không hoạt động tốt trên HTC Sense UI
emmby

19
Nhật thực không hiển thị điều này như là một sửa chữa có thể:import android.graphics.PorterDuff;
Ai đó ở đâu đó vào

2
Có ai có bất kỳ vấn đề với điều này không hoạt động trong ICS? Nó dường như không hoạt động trên trình giả lập hoặc điện thoại đối với tôi ..
Stev_k

149

Mike, bạn có thể quan tâm đến các bộ lọc màu.

Một ví dụ:

button.getBackground().setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0xFFAA0000));

Hãy thử điều này để đạt được màu sắc bạn muốn.


Hãy thử chuyển null trong phương thức setColorFilter. Không thử nó nhưng nó sẽ hoạt động.
Tomasz

6
@Pacerier để bỏ đặt: button.getBackground (). ClearColorFilter ();
Stan Kurdziel

3
Tôi khuyên bạn nên chọn màu bằng cách sử dụng lớp Màu: developer.android.com/reference/android/graphics/Color.html
Mugen

Hoàn hảo cho các chủ đề tối! Tôi giả sử rằng câu trả lời hàng đầu khác (setColorFilter (0xFFFF0000, PorterDuff.Mode.MULTIPLY)) hoạt động tốt hơn cho các chủ đề nhẹ.
java.is.for.desktop

85

Đây là giải pháp của tôi hoạt động hoàn hảo bắt đầu từ API 15 . Giải pháp này giữ cho tất cả các hiệu ứng nhấp chuột mặc định, như vật liệu RippleEffect. Tôi chưa thử nghiệm nó trên các API thấp hơn, nhưng nó sẽ hoạt động.

Tất cả bạn cần làm là:

1) Tạo kiểu chỉ thay đổi colorAccent:

<style name="Facebook.Button" parent="ThemeOverlay.AppCompat">
    <item name="colorAccent">@color/com_facebook_blue</item>
</style>

Tôi khuyên bạn nên sử dụng ThemeOverlay.AppCompathoặc chính của bạn AppThemelà cha mẹ, để giữ phần còn lại của phong cách của bạn.

2) Thêm hai dòng này vào buttonwidget của bạn :

style="@style/Widget.AppCompat.Button.Colored"
android:theme="@style/Facebook.Button"

Đôi khi, cái mới của bạn colorAccentkhông hiển thị trong Android Studio Preview, nhưng khi bạn khởi chạy ứng dụng của mình trên điện thoại, màu sắc sẽ bị thay đổi.


Tiện ích nút mẫu

<Button
    android:id="@+id/sign_in_with_facebook"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/sign_in_facebook"
    android:textColor="@android:color/white"
    android:theme="@style/Facebook.Button" />

Nút mẫu với màu tùy chỉnh


1
Dòng này làm gì? "style =" @ style / Widget.AppCompat.Button.Colored ""
Charles Li

2
Điều này giúp tôi hiểu được sự khác biệt giữa phong cách và chủ đề. Cảm ơn bạn.
rpattabi

2
Câu trả lời được chấp nhận là đúng nhưng quá cũ. Đây là một câu trả lời đơn giản và cập nhật nhất.
正宗 白

Vấn đề với câu trả lời này là, cài đặt đó colorAccent ảnh hưởng không chỉ đến nền của nút.
Blcknx

@Blcknx Ví dụ gì?
RediOne1

61

Bây giờ bạn cũng có thể sử dụng appcompat-v7 của AppCompatButton với backgroundTintthuộc tính:

<android.support.v7.widget.AppCompatButton
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:backgroundTint="#ffaa00"/>

4
Tôi không làm việc với tôi bằng cách sử dụng không gian tên "android:". Nhưng nó hoạt động khi tôi sử dụng không gian tên "app:".
David Velasquez

@DavidVelasquez Điều đó cũng hiệu quả với tôi trên Android Lollipop trong khi Android: không gian tên không thay đổi gì cả. Cảm ơn đã giúp đỡ!
Avinash Mitchhakar

Đây là giải pháp đơn giản nhất và nên là câu trả lời được chấp nhận. Sử dụng android: backgroundTint hoạt động với tôi.
Ramashish Baranwal

1
Phải app:backgroundTintthay vì android:backgroundTintkhi sử dụng AppCompat.
Hafez Divandari

23

Tôi thích đề xuất bộ lọc màu trong các câu trả lời trước từ @conjiledirection và @Tomasz; Tuy nhiên, tôi thấy rằng mã được cung cấp cho đến nay không dễ áp ​​dụng như tôi mong đợi.

Đầu tiên, nó không được đề cập đến nơi áp dụng và xóa bộ lọc màu. Có thể có những nơi tốt khác để làm điều này, nhưng điều tôi nghĩ đến là OnTouchListener .

Từ việc tôi đọc câu hỏi ban đầu, giải pháp lý tưởng sẽ là một giải pháp không liên quan đến bất kỳ hình ảnh nào. Câu trả lời được chấp nhận bằng cách sử dụng custom_button.xml từ @emmby có lẽ phù hợp hơn các bộ lọc màu nếu đó là mục tiêu của bạn. Trong trường hợp của tôi, tôi bắt đầu với một hình ảnh png từ một nhà thiết kế UI về việc nút được cho là trông như thế nào. Nếu tôi đặt nền nút cho hình ảnh này, phản hồi tô sáng mặc định sẽ bị mất hoàn toàn. Mã này thay thế hành vi đó bằng hiệu ứng làm tối theo chương trình.

button.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 0x6D6D6D sets how much to darken - tweak as desired
                setColorFilter(v, 0x6D6D6D);
                break;
            // remove the filter when moving off the button
            // the same way a selector implementation would 
            case MotionEvent.ACTION_MOVE:
                Rect r = new Rect();
                v.getLocalVisibleRect(r);
                if (!r.contains((int) event.getX(), (int) event.getY())) {
                    setColorFilter(v, null);
                }
                break;
            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                setColorFilter(v, null);
                break;
        }
        return false;
    }

    private void setColorFilter(View v, Integer filter) {
        if (filter == null) v.getBackground().clearColorFilter();
        else {
            // To lighten instead of darken, try this:
            // LightingColorFilter lighten = new LightingColorFilter(0xFFFFFF, filter);
            LightingColorFilter darken = new LightingColorFilter(filter, 0x000000);
            v.getBackground().setColorFilter(darken);
        }
        // required on Android 2.3.7 for filter change to take effect (but not on 4.0.4)
        v.getBackground().invalidateSelf();
    }
});

Tôi đã trích xuất đây là một lớp riêng cho ứng dụng cho nhiều nút - được hiển thị dưới dạng lớp bên trong ẩn danh chỉ để lấy ý tưởng.


Đó là một giải pháp tuyệt vời! Theo mặc định, ảnh hưởng tương tự như bạn nhận được trên iOS, đó là những gì các nhà thiết kế thích :-)
Christer Nordvik

Tôi đã thử điều này với 2 nút trong cùng một màn hình với cùng một nền và hiệu ứng áp dụng cho cả nút onTouch
Goofy

16

Nếu bạn đang tạo các nút màu bằng XML, bạn có thể làm cho mã sạch hơn một chút bằng cách chỉ định trạng thái tập trung và nhấn trong một tệp riêng và sử dụng lại chúng. Nút màu xanh lá cây của tôi trông như thế này:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true" android:drawable="@drawable/button_focused"/>
    <item android:state_pressed="true" android:drawable="@drawable/button_pressed"/>

    <item>
        <shape>
            <gradient android:startColor="#ff00ff00" android:endColor="#bb00ff00" android:angle="270" />
            <stroke android:width="1dp" android:color="#bb00ff00" />
            <corners android:radius="3dp" />
            <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" />
        </shape>
    </item>

</selector>

1
đẹp. Làm thế nào người ta có thể làm cho trạng thái tập trung và nhấn trở lại các định nghĩa Android tiêu chuẩn cho các nút?
larham1

Tôi khá chắc chắn rằng bạn không làm như các nút Android tiêu chuẩn được triển khai dưới dạng bitmap 9 miếng.
haemish

12

Giải pháp ngắn nhất đang hoạt động với mọi phiên bản Android:

<Button
     app:backgroundTint="@color/my_color"

Ghi chú / Yêu cầu :

  • Sử dụng app:không gian tên và không nhữngandroid: không gian tên!
  • phiên bản ứng dụng> 24.2.0

    phụ thuộc {biên dịch 'com.android.support:appcompat-v7:25.3.1'}

Giải thích : nhập mô tả hình ảnh ở đây


1
Thật thú vị, đối với tôi app:backgroundTint="@color/my_color"đã không làm việc. android:backgroundTint="@color/my_color"đã làm việc hoàn hảo mặc dù.
Igor

Đây là giải pháp ngắn nhất và sạch nhất cho tôi và đó là tất cả.
Marty

11

Tôi đang sử dụng phương pháp này

style.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:colorPrimaryDark">#413152</item>
    <item name="android:colorPrimary">#534364</item>
    <item name="android:colorAccent">#534364</item>
    <item name="android:buttonStyle">@style/MyButtonStyle</item>
</style>

<style name="MyButtonStyle" parent="Widget.AppCompat.Button.Colored">
    <item name="android:colorButtonNormal">#534364</item>
    <item name="android:textColor">#ffffff</item>
</style>

Như bạn có thể thấy ở trên, tôi đang sử dụng một kiểu tùy chỉnh cho nút của mình. Màu nút tương ứng với màu nhấn. Tôi thấy đây là một cách tiếp cận tốt hơn nhiều so với cài đặt android:backgroundvì tôi sẽ không mất hiệu ứng gợn mà Google cung cấp.


8

Có một cách dễ dàng hơn nhiều bây giờ: android-holo-colors.com

Nó sẽ cho phép bạn thay đổi màu sắc của tất cả các ngăn kéo holo (nút, spinners, ...) một cách dễ dàng. Bạn chọn màu và sau đó tải xuống tệp zip chứa drawable cho tất cả các độ phân giải.


8

Sử dụng nó theo cách này:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);

4

Đang <Button>sử dụng android:background="#33b5e5". hoặc tốt hơnandroid:background="@color/navig_button"


3

Các DroidUX thư viện thành phần có một ColorButtonphụ tùng mà màu sắc có thể được thay đổi một cách dễ dàng, cả hai thông qua định nghĩa xml và lập trình tại thời gian chạy, vì vậy bạn thậm chí có thể cho phép người dùng để thiết lập màu sắc của nút / theme nếu ứng dụng của bạn cho phép.


3

Bạn cũng có thể sử dụng công cụ trực tuyến này để tùy chỉnh nút của mình http://angrytools.com/android/button/ và sử dụng android:background="@drawable/custom_btn"để xác định nút tùy chỉnh trong bố cục của bạn.


2

Bạn có thể đặt chủ đề của nút của bạn thành này

<style name="AppTheme.ButtonBlue" parent="Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/HEXColor</item>
 <item name="android:textColor">@color/HEXColor</item>
</style>

1

Một cách dễ dàng là chỉ cần định nghĩa một lớp Nút tùy chỉnh chấp nhận tất cả các thuộc tính mà bạn mong muốn như bán kính, độ dốc, màu nhấn, màu bình thường, v.v. và sau đó chỉ sử dụng nó trong bố cục XML của bạn thay vì thiết lập nền bằng XML. Một mẫu ở đây

Điều này cực kỳ hữu ích nếu bạn có nhiều nút có cùng thuộc tính như bán kính, màu được chọn, v.v. Bạn có thể tùy chỉnh nút kế thừa của mình để xử lý các thuộc tính bổ sung này.

Kết quả (Không có bộ chọn nền nào được sử dụng).

Nút bình thường

Hình ảnh bình thường

Nhấn nút

nhập mô tả hình ảnh ở đây


0

Cách tôi thực hiện một nút theo kiểu khác hoạt động khá tốt là phân lớp đối tượng Nút và áp dụng bộ lọc màu. Điều này cũng xử lý các trạng thái kích hoạt và vô hiệu hóa bằng cách áp dụng một alpha cho nút.

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Button;

public class DimmableButton extends Button {

    public DimmableButton(Context context) {
        super(context);
    }

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

    public DimmableButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void setBackgroundDrawable(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackgroundDrawable(layer);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void setBackground(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackground(layer);
    }

    /**
     * The stateful LayerDrawable used by this button.
     */
    protected class DimmableButtonBackgroundDrawable extends LayerDrawable {

        // The color filter to apply when the button is pressed
        protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
        // Alpha value when the button is disabled
        protected int _disabledAlpha = 100;
        // Alpha value when the button is enabled
        protected int _fullAlpha = 255;

        public DimmableButtonBackgroundDrawable(Drawable d) {
            super(new Drawable[] { d });
        }

        @Override
        protected boolean onStateChange(int[] states) {
            boolean enabled = false;
            boolean pressed = false;

            for (int state : states) {
                if (state == android.R.attr.state_enabled)
                    enabled = true;
                else if (state == android.R.attr.state_pressed)
                    pressed = true;
            }

            mutate();
            if (enabled && pressed) {
                setColorFilter(_pressedFilter);
            } else if (!enabled) {
                setColorFilter(null);
                setAlpha(_disabledAlpha);
            } else {
                setColorFilter(null);
                setAlpha(_fullAlpha);
            }

            invalidateSelf();

            return super.onStateChange(states);
        }

        @Override
        public boolean isStateful() {
            return true;
        }
    }

}

0

giá trị \ style.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

<style name="RedAccentButton" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorAccent">#ff0000</item>
</style>

sau đó:

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="text" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="text"
    android:theme="@style/RedAccentButton" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text"
    android:theme="@style/RedAccentButton" />

kết quả


0

Theo hướng dẫn thiết kế vật liệu, bạn cần sử dụng kiểu như mã dưới đây

<style name="MyButton" parent="Theme.AppCompat.Light>
    <item name="colorControlHighlight">#F36F21</item>
    <item name="colorControlHighlight">#FF8D00</item>
</style>

và trong bố trí thêm thuộc tính này vào nút của bạn

    android:theme="@style/MyButton"

0

Thật đơn giản .. thêm sự phụ thuộc này vào dự án của bạn và tạo một nút với 1. Bất kỳ hình dạng 2. Bất kỳ màu nào 3. Bất kỳ đường viền 4. Với các hiệu ứng vật liệu

https://github.com/manojbhadane/QButton

<com.manojbhadane.QButton
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="OK"
       app:qb_backgroundColor="@color/green"
       app:qb_radius="100"
       app:qb_strokeColor="@color/darkGreen"
       app:qb_strokeWidth="5" />
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.