[英]Android: How to create a StateListDrawable programmatically
I have a GridView to display some objects, and visually each of the objects will have an image icon and a text label.我有一个 GridView 来显示一些对象,并且在视觉上每个对象都会有一个图像图标和一个文本 label。 I also want the image icon to have some "push and pop" effect when clicked, that is, when pressed, the image will move a small distance to the bottom right direction, and when released get back to its original position.
我还希望图像图标在单击时具有一些“推送和弹出”效果,即按下时,图像将向右下方向移动一小段距离,释放时返回其原始 position。
The objects (and their image icons) are from some dynamic sources.对象(及其图像图标)来自一些动态来源。 My intuition is to create a StateListDrawable for each item, which will have two states: pressed or not.
我的直觉是为每个项目创建一个 StateListDrawable,它将有两种状态:按下或不按下。 For GridView item view, I would use a Button, which can accomodate a Drawable and a label, that perfectly satisfies my requirment.
对于 GridView 项目视图,我会使用一个按钮,它可以容纳一个 Drawable 和一个 label,完全满足我的要求。
I defined an item class to wrap up the original object:我定义了一个项目 class 来包装原始 object:
public class GridItem<T> {
public static final int ICON_OFFSET = 4;
private StateListDrawable mIcon;
private String mLabel;
private T mObject;
public Drawable getIcon() {
return mIcon;
}
public void setIcon(Drawable d) {
if (null == d) {
mIcon = null;
}else if(d instanceof StateListDrawable) {
mIcon = (StateListDrawable) d;
} else {
InsetDrawable d1 = new InsetDrawable(d, 0, 0, ICON_OFFSET, ICON_OFFSET);
InsetDrawable d2 = new InsetDrawable(d, ICON_OFFSET, ICON_OFFSET, 0, 0);
mIcon = new StateListDrawable();
mIcon.addState(new int[] { android.R.attr.state_pressed }, d2);
mIcon.addState(StateSet.WILD_CARD, d1);
//This won't help either: mIcon.addState(new int[]{}, d1);
}
}
public String getLabel() {
return mLabel;
}
public void setLabel(String l) {
mLabel = l;
}
public T getObject() {
return mObject;
}
public void setObject(T o) {
mObject = o;
}
}
Now the problem is, when I touch a grid item, the icon "moves" quite as I have expected, but it won't restore its original position when my finger lifts up leaving the item.现在的问题是,当我触摸一个网格项目时,图标会像我预期的那样“移动”,但是当我的手指抬起离开该项目时,它不会恢复其原始 position。
My question is: how to programmatically create a StateListDrawable equivalent to one inflated from an XML resource like我的问题是:如何以编程方式创建一个 StateListDrawable 等效于从 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/image_pressed" />
<item android:drawable="@drawable/image_normal" />
</selector>
? ?
if your drawables are just bitmaps, you could draw them programmatically, for now it should help, however I wonder what is the problem with InsetDrawable
usage here, basically use prepared BitmapDrawables
that are drawn programatically, you would need to modify your method to accept bitmaps b
如果您的drawables只是位图,您可以以编程方式绘制它们,现在它应该有所帮助,但是我想知道这里使用
InsetDrawable
有什么问题,基本上使用以编程方式绘制的准备好的BitmapDrawables
,您需要修改您的方法以接受位图b
Bitmap bc1 = Bitmap.createBitmap(b.getWidth() + ICON_OFFSET, b.getHeight() + ICON_OFFSET, Bitmap.Config.ARGB_8888);
Canvas c1 = new Canvas(bc1);
c1.drawBitmap(b, 0, 0, null);
Bitmap bc2 = Bitmap.createBitmap(b.getWidth() + ICON_OFFSET, b.getHeight() + ICON_OFFSET, Bitmap.Config.ARGB_8888);
Canvas c2 = new Canvas(bc2);
c2.drawBitmap(b, ICON_OFFSET, ICON_OFFSET, null);
mIcon = new StateListDrawable();
mIcon.addState(new int[] { android.R.attr.state_pressed }, new BitmapDrawable(bc2));
mIcon.addState(StateSet.WILD_CARD, new BitmapDrawable(bc1));
I can see the answer is already accepted.我可以看到答案已被接受。 I am sharing if you want to assign dynamically colors of buttons from the users for normal as well as pressed state.
如果您想从用户那里动态分配 colors 按钮,我将分享正常以及按下 state。 then you can just call this function:
那么你可以直接调用这个 function:
public static StateListDrawable convertColorIntoBitmap(String pressedColor, String normalColor){
/*Creating bitmap for color which will be used at pressed state*/
Rect rectPressed = new Rect(0, 0, 1, 1);
Bitmap imagePressed = Bitmap.createBitmap(rectPressed.width(), rectPressed.height(), Config.ARGB_8888);
Canvas canvas = new Canvas(imagePressed);
int colorPressed = Color.parseColor(pressedColor);
Paint paintPressed = new Paint();
paintPressed.setColor(colorPressed);
canvas.drawRect(rectPressed, paintPressed);
RectF bounds = new RectF();
bounds.round(rectPressed);
/*Creating bitmap for color which will be used at normal state*/
Rect rectNormal = new Rect(0, 0, 1, 1);
Bitmap imageNormal = Bitmap.createBitmap(rectNormal.width(), rectNormal.height(), Config.ARGB_8888);
Canvas canvasNormal = new Canvas(imageNormal);
int colorNormal = Color.parseColor(normalColor);
Paint paintNormal = new Paint();
paintNormal.setColor(colorNormal);
canvasNormal.drawRect(rectNormal, paintNormal);
/*Now assigning states to StateListDrawable*/
StateListDrawable stateListDrawable= new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new BitmapDrawable(imagePressed));
stateListDrawable.addState(StateSet.WILD_CARD, new BitmapDrawable(imageNormal));
return stateListDrawable;
}
Now all you need is to set it as your textview or button background like below:现在您只需将其设置为 textview 或按钮背景,如下所示:
if(android.os.Build.VERSION.SDK_INT>=16){
yourbutton.setBackground(convertColorIntoBitmap("#CEF6CE00","#4C9D32"));
}else{
yourbutton.setBackgroundDrawable(convertColorIntoBitmap("#CEF6CE00","#4C9D32"));
}
Here you can see all you need to pass the colors dynamically and we're done.在这里,您可以看到动态传递 colors 所需的一切,我们就完成了。 hope this will help someone:) You can find it's gist too here :)
希望这会对某人有所帮助:)你也可以在这里找到它的要点:)
I have seen the previous answers, but came up with a much shorter and better solution using ColorDrawable
.我已经看到了以前的答案,但使用
ColorDrawable
提出了一个更短更好的解决方案。
/**
* Get {@link StateListDrawable} given the {@code normalColor} and {@code pressedColor}
* for dynamic button coloring
*
* @param normalColor The color in normal state.
* @param pressedColor The color in pressed state.
* @return
*/
public static StateListDrawable getStateListDrawable(int normalColor, int pressedColor) {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(pressedColor));
stateListDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(normalColor));
return stateListDrawable;
}
This accepts resolved colors as integer and uses ColorDrawable
to add them in a StateListDrawable
.这接受解析的 colors 作为 integer 并使用
ColorDrawable
将它们添加到StateListDrawable
中。
Once you have the drawable, you can use it simply like this,一旦你有了drawable,你可以像这样简单地使用它,
if (android.os.Build.VERSION.SDK_INT >= 16) {
mButton.setBackground(Utils.getStateListDrawable(ResourceUtils.getColor(R.color.white),
ResourceUtils.getColor(R.color.pomegranate)));
} else {
mButton.setBackgroundDrawable(Utils.getStateListDrawable(ResourceUtils.getColor(R.color.white),
ResourceUtils.getColor(R.color.pomegranate)));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.