【问题标题】:How to gradient fill a button's background?如何渐变填充按钮的背景?
【发布时间】:2011-01-24 22:52:34
【问题描述】:

我必须创建一个带有渐变填充的彩色按钮(从按钮中间沿 Y 轴开始)。如果我将按钮的背景属性设置为我想要的颜色,我将失去按钮的 圆角 外观和渐变填充(看起来像带有背景的TextView)。

另外,我希望在用户按下按钮时改变这种颜色。我可以通过选择器 XMLs(Color State Lists) 指定这个吗?

感谢任何可以帮助我的教程或链接。

谢谢。

【问题讨论】:

    标签: android android-ui


    【解决方案1】:

    我相信您想要做的是让您的按钮在正常状态、按下状态、聚焦状态等下显示不同的渐变。这可以使用 XML 来完成(在 res/ 中创建一个 selector.xml 文件drawable 引用 res/drawable 中的 shape.xml 文件,每个文件都包含一个渐变元素,然后将按钮的背景设置为您创建的 selector.xml 文件。)但是,XML 路由只允许您使用两个(或可选的三种)静态颜色,并且无法控制颜色停止点的位置。编程解决方案将为您提供更大的灵活性,并允许您动态更改颜色。这是一个名为 GradientLab 的 Android 项目的示例。

    res/layouts 中的 main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
      style="@style/LayoutArea"
    >
     <TextView
      style="@style/LayoutRow"
      android:text="@string/hello" />
     <Button
      style="@style/RowButton"
      android:id="@+id/btn1"
      android:text="1" />
     <Button
      style="@style/RowButton"
      android:id="@+id/btn2"
      android:text="2" />
     <Button
      style="@style/RowButton"
      android:id="@+id/btn3"
      android:text="3" />
    </LinearLayout>
    

    res/values 中的styles.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
     <style name="LayoutArea">
      <item name="android:layout_width">fill_parent</item>
      <item name="android:layout_height">fill_parent</item>
     </style>
     <style name="LayoutRow">
      <item name="android:layout_width">fill_parent</item>
      <item name="android:layout_height">wrap_content</item>
     </style>
     <style name="LayoutColumn">
      <item name="android:layout_width">wrap_content</item>
      <item name="android:layout_height">fill_parent</item>
     </style>
     <style name="LayoutItem">
      <item name="android:layout_width">wrap_content</item>
      <item name="android:layout_height">wrap_content</item>
     </style>
     <style name="RowButton" parent="LayoutRow">
      <item name="android:layout_weight">1</item>
      <item name="android:layout_margin">8dp</item>
      <item name="android:gravity">center_horizontal</item>
     </style>
    </resources>
    

    android.examples 中的 GradientLab.java 演示使用带有按钮的渐变:

    package android.example;
    
    import android.app.Activity;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.widget.Button;
    import android.widget.LinearLayout;
    
    public class GradientLab extends Activity {
        // Layout fields
        protected LinearLayout mainLayout;
        public static Button btn1 = null;
        public static Button btn2 = null;
        public static Button btn3 = null;
    
        // Members
        private int[] normalColors = new int[4];
        private int[] focusedColors = new int[2];
        private int[] disabledColors = new int[1];
        private int defaultSkinR = 94;
        private int defaultSkinG = 128;
        private int defaultSkinB = 219;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            /*
             * This creates View objects from the xml file. The xml file should
             * define all views and all static attributes.
             */
            mainLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.main,
                    null);
    
            normalColors[0] = Color.argb(255, defaultSkinR, defaultSkinG,
                    defaultSkinB);
            normalColors[1] = Color.argb(255, 217, 217, 217);
            normalColors[2] = Color.argb(191, defaultSkinR, defaultSkinG,
                    defaultSkinB);
            normalColors[3] = Color.argb(140, defaultSkinR, defaultSkinG,
                    defaultSkinB);
    
            focusedColors[0] = Color.argb(229, 242, 242, 242);
            focusedColors[1] = Color.BLUE;
    
            UIGradientSelector gradientSelector1 = new UIGradientSelector(
                    normalColors, focusedColors, null);
            UIGradientSelector gradientSelector2 = new UIGradientSelector(
                    normalColors, focusedColors, null);
    
            disabledColors[0] = Color.argb(153, 216, 216, 216);
            UIGradientDrawable disabledGradient = new UIGradientDrawable(
                    disabledColors);
    
            btn1 = (Button) mainLayout.findViewById(R.id.btn1);
            btn1.setBackgroundDrawable(gradientSelector1);
    
            btn2 = (Button) mainLayout.findViewById(R.id.btn2);
            btn2.setBackgroundDrawable(gradientSelector2);
    
            btn3 = (Button) mainLayout.findViewById(R.id.btn3);
            btn3.setBackgroundDrawable(disabledGradient);
    
            setContentView(mainLayout);
        }
    }
    

    android.examples 中的 UIGradientSelector.java 根据按钮状态选择渐变:

    package android.example;
    
    import android.graphics.drawable.StateListDrawable;
    
    /**
     * {@link StateListDrawable} that controls selection of
     * {@link UIGradientDrawable} based on the three basic button states.
     */
    public class UIGradientSelector extends StateListDrawable {
    
        /**
         * {@link UIGradientSelector} that selects the {@link UIGradientDrawable}
         * defined by the colors for the three basic button states.
         * 
         * @param normalColors
         *            Array of primitive ints that define the gradient colors for a
         *            button in its normal state.
         * @param focusedColors
         *            Array of primitive ints that define the gradient colors for a
         *            button in its focused state.
         * @param pressedColors
         *            Array of primitive ints that define the gradient colors for a
         *            button in its pressed state. If the array is null, then
         *            focusedColors will be used for the pressed state.
         */
        public UIGradientSelector(int[] normalColors, int[] focusedColors,
                int[] pressedColors) {
            int stateFocused = android.R.attr.state_focused;
            int statePressed = android.R.attr.state_pressed;
            UIGradientDrawable normalGradient = new UIGradientDrawable(normalColors);
            UIGradientDrawable focusedGradient = new UIGradientDrawable(
                    focusedColors);
            UIGradientDrawable pressedGradient;
    
            if (pressedColors == null) {
                pressedGradient = focusedGradient;
            } else {
                pressedGradient = new UIGradientDrawable(pressedColors);
            }
    
            addState(new int[] { stateFocused }, focusedGradient);
            addState(new int[] { statePressed }, pressedGradient);
            addState(new int[] { -statePressed, -stateFocused }, normalGradient);
        }
    }
    

    在 android.examples 中绘制表面的 UIGradientDrawable.java:

    package android.example;
    
    import android.graphics.drawable.PaintDrawable;
    import android.graphics.drawable.shapes.RectShape;
    
    /**
     * {@link PaintDrawable} that paints the surface via a {@link UIGradientShader}.
     */
    public class UIGradientDrawable extends PaintDrawable {
    
        /**
         * {@link UIGradientDrawable} with an initial shape of a rounded rectangle
         * that transitions evenly between the specified colors.
         * 
         * @param colors
         *            Array of primitive ints that contain the argb values of the
         *            color to use for transitioning.
         */
        public UIGradientDrawable(int[] colors) {
            UIGradientShader gradientShader = new UIGradientShader(colors);
            setShape(new RectShape());
            setCornerRadius(8);
            setShaderFactory(gradientShader);
            setDither(true);
        }
    
    }
    

    android.examples 中处理实际转换的 UIGradientShader.java:

    package android.example;
    
    import android.graphics.Color;
    import android.graphics.LinearGradient;
    import android.graphics.Shader;
    import android.graphics.drawable.ShapeDrawable.ShaderFactory;
    
    /**
     * {@link ShaderFactory} that uses a {@link LinearGradient} to transition
     * between specified colors. Any number of colors may be specified.
     */
    public class UIGradientShader extends ShaderFactory {
        private int[] colors;
        private float[] positions;
    
        /**
         * {@link UIGradientShader} that spaces color transitions evenly across the
         * painting surface.
         * 
         * @param colors
         *            Array of primitive ints that contain the argb values of the
         *            color to use for transitioning. If the array contains only one
         *            color, then an argb of (0, 0, 0, 0) will be used for the end
         *            color of the transition. If the array is set to null or
         *            contains zero colors, then the transition will be from an argb
         *            of (255, 255, 255, 255) to and argb of (0, 0, 0, 0).
         * 
         * @see Color
         */
        public UIGradientShader(int[] colors) {
            init(colors, null);
        }
    
        /**
         * {@link UIGradientShader} that spaces color transitions across the
         * painting surface as specified.
         * 
         * @param colors
         *            Array of primitive ints that contain the argb values of the
         *            color to use for transitioning. If the array contains only one
         *            color, then an argb of (0, 0, 0, 0) will be used for the end
         *            color of the transition. If the array is set to null or
         *            contains zero colors, then the transition will be from an argb
         *            of (255, 255, 255, 255) to and argb of (0, 0, 0, 0).
         * @param positions
         *            Array of primitive floats that contain the position of the
         *            transition points. If the array is null, then the color
         *            transitions will be spaced evenly.
         */
        public UIGradientShader(int[] colors, float[] positions) {
            init(colors, positions);
        }
    
        private void init(int[] colors, float[] positions) {
            if (colors == null || colors.length == 0) {
                this.colors = new int[2];
                this.colors[0] = Color.argb(255, 255, 255, 255);
                this.colors[1] = Color.argb(0, 0, 0, 0);
            } else if (colors.length == 1) {
                this.colors = new int[2];
                this.colors[0] = colors[0];
                this.colors[1] = Color.argb(0, 0, 0, 0);
            } else {
                this.colors = colors;
            }
    
            this.positions = positions;
        }
    
        public Shader resize(int width, int height) {
            LinearGradient lg = new LinearGradient(0, 0, 0, height, colors,
                    positions, Shader.TileMode.REPEAT);
            return lg;
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      How to set background color of a View

      您将需要定义一个自定义的StateListDrawable 资源,该资源可能是从默认情况下用于按钮的 Android 克隆而来,您可以在其中将九个补丁图像更改为渐变。您也许可以在 XML 中定义这些渐变,这意味着它们可以很好地拉伸。

      【讨论】:

        猜你喜欢
        • 2013-10-12
        • 1970-01-01
        • 1970-01-01
        • 2012-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-13
        相关资源
        最近更新 更多