StateListDrawable and tiled bitmap - android

This is my custom selector (StateListDrawable)
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/common_cell_background" />
<item
android:state_pressed="true"
android:drawable="#drawable/common_cell_background_highlight" />
<item
android:state_focused="true"
android:drawable="#drawable/common_cell_background_highlight" />
<item
android:state_selected="true"
android:drawable="#drawable/common_cell_background_highlight" />
</selector>
Both, common_cell_background and common_cell_background_highlight are XML. Code below:
common_cell_background.xml
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/common_cell_background_bitmap"
android:tileMode="repeat"
android:dither="true">
</bitmap>
common_cell_background_highlight.xml
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/common_cell_background_bitmap_highlight"
android:tileMode="repeat"
android:dither="true">
</bitmap>
Bitmaps are also exactly the same. Highlight is just a little bit lighter and there is no other differences. Both bitmaps are PNG files.
Now I set
convertView.setBackgroundResource(R.drawable.list_item_background);
and here is the problem. My common_cell_background doesn't repeat, it's stretched. But what is suprising when I touch on cell of my list background changes to common_cell_background_highlight and guess what? Everything is fine, it's repeated like it should be. I have no idea where is the problem, why my background doesn't repeat while highlight does. Any thoughts?

This is the bug, it was fixed in ICS, see this answer: https://stackoverflow.com/a/7615120/1037294
Here is a workaround: https://stackoverflow.com/a/9500334/1037294
Note, that the workaround is only applicable for BitmapDrawable, for other types of drawables like StateListDrawable you'll need to do extra work. Here is what I use:
public static void fixBackgrndTileMode(View view, TileMode tileModeX, TileMode tileModeY) {
if (view != null) {
Drawable bg = view.getBackground();
if (bg instanceof BitmapDrawable) {
BitmapDrawable bmp = (BitmapDrawable) bg;
bmp.mutate(); // make sure that we aren't sharing state anymore
bmp.setTileModeXY(tileModeX, tileModeY);
}
else if (bg instanceof StateListDrawable) {
StateListDrawable stateDrwbl = (StateListDrawable) bg;
stateDrwbl.mutate(); // make sure that we aren't sharing state anymore
ConstantState constantState = stateDrwbl.getConstantState();
if (constantState instanceof DrawableContainerState) {
DrawableContainerState drwblContainerState = (DrawableContainerState)constantState;
final Drawable[] drawables = drwblContainerState.getChildren();
for (Drawable drwbl : drawables) {
if (drwbl instanceof BitmapDrawable)
((BitmapDrawable)drwbl).setTileModeXY(tileModeX, tileModeY);
}
}
}
}
}

Related

Android change drawable solid color programmatically

I have a drawable that is an oval shape with a with check mark inside.
Is it possible to change the oval color programmatically without changing the check mark color ?
Here's my drawable:
<item>
<shape
android:shape="oval">
<solid android:color="#color/black" />
</shape>
</item>
<item>
<bitmap
android:src="#drawable/check_mark"/>
</item>
What I would like to do is only change the solid black color to something else programmatically
It would be easier to just add a second drawables with other "oval"-color and then replace the drawable programmatically.
You can grammatically create a shape using below reference code.
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(24);
shape.setShape(GradientDrawable.OVAL);
shape.setColor(R.color.red);
imageView.setBackground(shape);
The drawable is an oval and is the background of an ImageView
Get the Drawable from imageView using getBackground():
Drawable background = imageView.getBackground();
Check against usual suspects:
if (background instanceof ShapeDrawable) {
// cast to 'ShapeDrawable'
ShapeDrawable shapeDrawable = (ShapeDrawable) background;
shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
// cast to 'GradientDrawable'
GradientDrawable gradientDrawable = (GradientDrawable) background;
gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
// alpha value may need to be set again after this call
ColorDrawable colorDrawable = (ColorDrawable) background;
colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Compact version:
Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

Android - imageview setBackground not applied after transition

MainActivity.java
transition = new TransitionDrawable(new Drawable[]{
new ColorDrawable(Color.TRANSPARENT),
new BitmapDrawable(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.face1))
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
imageView.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.default_image, null));
}
imageView.setImageDrawable(transition);
transition.startTransition(3000);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
imageView.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.iv1_selector, null));
Log.d("LOG", "CALLED");
}
}
}, 3000);
iv1_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="#android:integer/config_shortAnimTime"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item android:drawable="#drawable/iv_focused_drawable" android:state_focused="true" />
<item android:drawable="#drawable/iv_not_focused_drawable" android:state_focused="false" />
</selector>
I give a small animation, transition, to the imageView. After finishing the animation, imageView's background should be changed with a selector drawable inside a handler. However, for some reasons, its background is not applied, but when I click the imageView, it is applied. I have no idea on what's going on inside the handler. Any advice for this case?
This is how it looks like when the transition finished
But as you see this, I want to make it have the border around it. I don't understand why its background is not applied in the handler

Palette colour overrides Outline

I'm making an app just to check out some of the new L APIs, and I'm particularly interested in the FloatingActionButton and the Palette colour generator. So I set a full screen ImageView to display an HTC wallpaper, I then extract one of the colours with Palette and set it as the background colour of my FAB. However, doing this removes the Outline from my FAB, so it's no longer circular.
I would like to know how, if possible, to stop the Palette overriding the Outline.
The Palette AsyncListener:
MyActivity.java
Palette.generateAsync(BitmapFactory.decodeResource(getResources(),R.drawable.wallpapers_07),
new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette palette) {
PaletteItem item = palette.getLightVibrantColor();
ImageButton button = (ImageButton) findViewById(R.id.fab);
if (item != null) {
button.setBackgroundColor(item.getRgb());
}
}
});
Outline in MyActivity.java
int size = getResources().getDimensionPixelSize(R.dimen.fab_size);
Outline outline = new Outline();
outline.setOval(0, 0, size, size);
findViewById(R.id.fab).setOutline(outline);
FAB background drawable
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item>
<shape android:shape="oval">
<solid android:color="?android:colorAccent"/>
</shape>
</item>
You are replacing the background drawable (RippleDrawable) with a color (ColorDrawable). Instead, you want to change the color of the shape (GradientDrawable) contained with the background drawable.
Try changing the color filter instead:
findViewById(R.id.fab).getBackgroundDrawable().setColorFilter(
new PorterDuffColorFilter(item.getRgb(), Mode.SRC_IN));
If you're changing the color often, you can just cache the color filter object and use setColor(int) followed by findViewById(R.id.fab).invalidate() to update the view.

Android Background image is deformed in repeat

I use android:tileMode="repeat" for my textview backgrnound. It is about 1px height image,but in repeat is deformed on left,right side..
thanks for help!
screen: http://i.stack.imgur.com/yCXSQ.png
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/chat_rep"
android:dither="true"
android:tileMode="repeat" />
Call this function with each view that has the background:
public static void fixBackgroundRepeat(View view) {
Drawable bg = view.getBackground();
if (bg != null) {
if (bg instanceof BitmapDrawable) {
BitmapDrawable bmp = (BitmapDrawable) bg;
bmp.mutate(); // make sure that we aren't sharing state anymore
bmp.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
}
}
}
This was an answer posted on this question:
"Tiled drawable sometimes stretches"

Set android shape color programmatically

I am editing to make the question simpler, hoping that helps towards an accurate answer.
Say I have the following oval shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:angle="270"
android:color="#FFFF0000"/>
<stroke android:width="3dp"
android:color="#FFAA0055"/>
</shape>
How do I set the color programmatically, from within an activity class?
Note: Answer has been updated to cover the scenario where background is an instance of ColorDrawable. Thanks Tyler Pfaff, for pointing this out.
The drawable is an oval and is the background of an ImageView
Get the Drawable from imageView using getBackground():
Drawable background = imageView.getBackground();
Check against usual suspects:
if (background instanceof ShapeDrawable) {
// cast to 'ShapeDrawable'
ShapeDrawable shapeDrawable = (ShapeDrawable) background;
shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
// cast to 'GradientDrawable'
GradientDrawable gradientDrawable = (GradientDrawable) background;
gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
// alpha value may need to be set again after this call
ColorDrawable colorDrawable = (ColorDrawable) background;
colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Compact version:
Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Note that null-checking is not required.
However, you should use mutate() on the drawables before modifying them if they are used elsewhere. (By default, drawables loaded from XML share the same state.)
A simpler solution nowadays would be to use your shape as a background and then programmatically change its color via:
view.background.setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP)
See PorterDuff.Mode for the available options.
UPDATE (API 29):
The above method is deprecated since API 29 and replaced by the following:
view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP)
See BlendMode for the available options.
Do like this:
ImageView imgIcon = findViewById(R.id.imgIcon);
GradientDrawable backgroundGradient = (GradientDrawable)imgIcon.getBackground();
backgroundGradient.setColor(getResources().getColor(R.color.yellow));
This question was answered a while back, but it can modernized by rewriting as a kotlin extension function.
fun Drawable.overrideColor(#ColorInt colorInt: Int) {
when (this) {
is GradientDrawable -> setColor(colorInt)
is ShapeDrawable -> paint.color = colorInt
is ColorDrawable -> color = colorInt
}
}
Try this:
public void setGradientColors(int bottomColor, int topColor) {
GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[]
{bottomColor, topColor});
gradient.setShape(GradientDrawable.RECTANGLE);
gradient.setCornerRadius(10.f);
this.setBackgroundDrawable(gradient);
}
for more detail check this link this
hope help.
hope this will help someone with the same issue
GradientDrawable gd = (GradientDrawable) YourImageView.getBackground();
//To shange the solid color
gd.setColor(yourColor)
//To change the stroke color
int width_px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, youStrokeWidth, getResources().getDisplayMetrics());
gd.setStroke(width_px, yourColor);
Expanding on Vikram's answer, if you are coloring dynamic views, like recycler view items, etc.... Then you probably want to call mutate() before you set the color. If you don't do this, any views that have a common drawable (i.e a background) will also have their drawable changed/colored.
public static void setBackgroundColorAndRetainShape(final int color, final Drawable background) {
if (background instanceof ShapeDrawable) {
((ShapeDrawable) background.mutate()).getPaint().setColor(color);
} else if (background instanceof GradientDrawable) {
((GradientDrawable) background.mutate()).setColor(color);
} else if (background instanceof ColorDrawable) {
((ColorDrawable) background.mutate()).setColor(color);
}else{
Log.w(TAG,"Not a valid background type");
}
}
this is the solution that works for me...wrote it in another question as well:
How to change shape color dynamically?
//get the image button by id
ImageButton myImg = (ImageButton) findViewById(R.id.some_id);
//get drawable from image button
GradientDrawable drawable = (GradientDrawable) myImg.getDrawable();
//set color as integer
//can use Color.parseColor(color) if color is a string
drawable.setColor(color)
Nothing work for me but when i set tint color it works on Shape Drawable
Drawable background = imageView.getBackground();
background.setTint(getRandomColor())
require android 5.0 API 21
My Kotlin extension function version based on answers above with Compat:
fun Drawable.overrideColor_Ext(context: Context, colorInt: Int) {
val muted = this.mutate()
when (muted) {
is GradientDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
is ShapeDrawable -> muted.paint.setColor(ContextCompat.getColor(context, colorInt))
is ColorDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
else -> Log.d("Tag", "Not a valid background type")
}
}
The simple way to fill the shape with the Radius is:
(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
May be I am too late.But if you are using Kotlin. There is way like this
var gd = layoutMain.background as GradientDrawable
//gd.setCornerRadius(10)
gd.setColor(ContextCompat.getColor(ctx , R.color.lightblue))
gd.setStroke(1, ContextCompat.getColor(ctx , R.color.colorPrimary)) // (Strokewidth,colorId)
Enjoy....
This might help
1.Set the shape color initially to transparent
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:angle="270"
android:color="#android:color/transparent"/>
<stroke android:width="3dp"
android:color="#FFAA0055"/>
</shape>
Set the shape as a background to the view
Set your preferred color as follows:
Drawable bg = view.getBackground();
bg.setColorFilter(Color.parseColor("#Color"), PorterDuff.Mode.ADD);
I needed to do this in my adapter but the solutions above were either not working or required >= android version 10. The code below worked for me!
val drawable = DrawableCompat.wrap(holder.courseName.background)
DrawableCompat.setTint(drawable, Color.parseColor("#4a1f60"))
For anyone using C# Xamarin, here is a method based on Vikram's snippet:
private void SetDrawableColor(Drawable drawable, Android.Graphics.Color color)
{
switch (drawable)
{
case ShapeDrawable sd:
sd.Paint.Color = color;
break;
case GradientDrawable gd:
gd.SetColor(color);
break;
case ColorDrawable cd:
cd.Color = color;
break;
}
}
The Best way to change Solid color of custom drawable is
For Kotlin.
(findViewById<TextView>(R.id.testing1).getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
We can create this kotlin function.
fun View.updateViewBGSolidColor(colorString: String) {
when (val background: Drawable = this.background) {
is ShapeDrawable -> {
background.paint.color = Color.parseColor(colorString)
}
is GradientDrawable -> {
background.setColor(Color.parseColor(colorString))
}
is ColorDrawable -> {
background.color = Color.parseColor(colorString)
}
}
}
And use it like the below:
yourTextView.updateViewBGSolidColor("#FFFFFF")
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[] {0xFF616261,0xFF131313});
gd.setCornerRadius(0f);
layout.setBackgroundDrawable(gd);

Categories

Resources