How to gradient fill a button's background?
I have to create a colored button with gradient fill(starting from the middle of the button along Y axis). If I set the background propert开发者_如何学JAVAy of the button to the color I want, I lose the rounded look and feel of a button and also the gradient fill(It looks like a TextView
with a background).
Also, I want this color to change when the user depresses the button. Can i specify this via selector XMLs(Color State Lists)?
Any tutorials or links that can help me here is appreciated.
Thanks.
I believe what you are wanting to do is to have your buttons show different gradients when in the normal state, the pressed state, focused state, etc. This can be done using XML (Create a selector.xml file in res/drawable that references shape.xml files in res/drawable which each contain a gradient element and then set the background of your button to the selector.xml file that you created.) However, the XML route will only let you define gradients with two (or optionally three) static colors and with no control over the location of the color stop points. A programmatic solution will give you far more flexibility and will allow you to dynamically change the colors. Here's an example for an Android project called GradientLab.
main.xml in res/layouts:
<?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>
styles.xml in res/values:
<?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>
GradientLab.java in android.examples that demos using gradients with buttons:
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);
}
}
UIGradientSelector.java in android.examples that selects gradients base on button state:
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);
}
}
UIGradientDrawable.java in android.examples that paints the surface:
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);
}
}
UIGradientShader.java in android.examples that handles the actual transitions:
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;
}
}
How to set background color of a View
You will need to define a custom StateListDrawable
resource, cloned perhaps from the one Android uses for buttons by default, where you change the nine-patch images to be gradients. You might be able to define those gradients in XML, which would mean they would stretch nicely.
精彩评论