I've a requirement in which an ImageView's enabled state is changed.
I have 2 images: one for the enabled state & another for the disabled state.
Without using a selector, how can I change the Image src when the setEnabled(true/false) is changed?
That is:
imageView.setEnabled(true);
imageView - use image imgEnabled.png
imageView.setEnabled(false);
imageView - use image imgDisabled.png
Thank You
Try this
if(imageView.isEnabled())
{
imageView.setBackgroundResource(R.drawable.imgEnabled);
}
else
{
imageView.setBackgroundResource(R.drawable.imgDisabled);
}
You can do it by setting the image yourself using setImageResource.
But this may not be appropriate, since your view's state may be changed from your code anywhere.
imageView.setEnabled(true);
imageView.setImageResource(R.drawable.imgEnabled);
imageView.setEnabled(false);
imageView.setImageResource(R.drawable.imgDisabled);
You can also write your own class that extends ImageView
and override the following method
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if(isEnabled())
{
//set drawable for enabled state here
}
else
{
//set drawable for disabled state here
}
}
you can use this to change image resource-
imageView.setBackgroundResource(R.drawable.image);
Related
I am using this class to draw TriangleShapeView over ImageView that changes its color and drawable image upon user click event.
in RecyclerView onBindViewHolder method, i check against
feedModel.isSubscribed() then set TriangleShapeView color and drawable image accordingly:
public void onBindViewHolder(FeedViewHolder holder, final int position) {
final FeedModel feedModel =this.feedCollection.get(position);
if (feedModel.isSubscribed()) {
holder.mTrView.setBackgroundColor(Color.RED);
holder.mTrView.setDrawable(holder.mTrView.getContext().getResources().getDrawable(R.drawable.ic_check));
} else {
holder.mTrView.setBackgroundColor(Color.BLACK);
holder.mTrView.setDrawable(holder.mTrView.getContext().getResources().getDrawable(R.drawable.ic_plus));
}
in setOnClickListener:
holder.itemView.setOnClickListener(v -> {
if (FeedAdapter.this.onItemClieckListener != null){
FeedAdapter.this.onItemClieckListener.onFeedItemClicked(feedModel);
if (feedModel.isSubscribed()) {
feedModel.setIsSubscribed(false);
notifyItemChanged(position);
} else {
feedModel.setIsSubscribed(true);
notifyItemChanged(position);
}
}
});
this works fine when items get loaded for first time but when user clickes:
- 1st & 2nd time: drawable image got changes as desired but the color
remains same.
- 3rd time both drawable image and color gets changes
i am using the following xml layout to inflate this custom view:
<cardView
<RelativeLayout
....
<com.xxx.TriangleShapeView
android:id="#+id/trView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:elevation="15dp"
TriangleShapeView:imgPadding="5dp"
TriangleShapeView:triangleBackground="#color/cardview_dark_background"
TriangleShapeView:img="#drawable/ic_plus"/>
i believe, the FeedModel gets updated once OnClick is called and checks are fine in onBindViewHoldr method. so i think the problem is in the class mentioned in the above link
What i am looking to achieve is:
if feedModel.isSubscribed then change the color to red and drawable to check-sign icon. else, keep the initial values as in the layout xml.
also react upon onClick and change the color and image
I think you're right and the error in this method.
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
invalidate();
}
the paint color get assigned in the constructor and onDraw method.
try to add to this method before invalidate() the line with paint.setColor(backgroundColor);
The following line is throwing an OutOfMemoryException
if (null == myImage.getDrawable()){
//...
}
Is there another way to check if an ImageView has a Drawable/Bitmap?
This would be work around. Call imageview.getWidth() or getHeight(). If the value is 0 then no image is loaded
In this case, what i would do is make use of setTag and getTag on ImageView. First time in xml set the tag as empty and whenever you bind any drawable, set some value to the tag using setTag().
If tag has some value, assume that imageview is having a drawable and if the value is empty then the imageview is not having drawable.
Hope this helps you
You have to watch your memory usage though, here's a quick and dirty solution
try {
if (myImage.getDrawable() == null)
doFoo();
else
doBar();
} catch (OutOfMemoryError e) {
//the ImageView definetely had some large content
doBar();
}
You can overwrite ImageView class and fill some boolean value when setDrawable method called.
public class CustomImageView extends ImageView {
public boolean isImageSet = false;
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if(bm != null)
isImageSet = true;
}
}
This might only address the symptoms, but you could try adding android:largeHeap="true" in your androidmanifest application tag
I have a seek bar and I am setting the thumb drawable in code. When the activity is starting I can see the changed drawable for the thumb but if I start a new activity from the seekbar activity and come back, the seekbar's thumb gets invisible (only if I set it's drawable again). This is happening only if I come back from other activity to the seekbar activity.
I need to change the drawable of the thumb in onRestart() because the other activityes may change the color or shape of the thumb and I need to refresh it's drawable.
I tried invalidate() on the seekbar but no use...
EDIT:
I tried to make 3 static Drawable objects and load the images in onCreate() and I noticed that after coming back on the SeekBar activity, if I set the thumb drawable to the one that is already set, the thumb is visible but if I change the drawable, the thumb becomes invisible.
EDIT 2:
In this case I set the loaded drawables to the thumb:
String gender = getGender();
if (gender.equals(Profile.GENDER_1)) {
mSeekBar.setThumb(mDrawable1);
} else if (gender.equals(Profile.GENDER_2)) {
mSeekBar.setThumb(mDrawable2);
} else {
mSeekBar.setThumb(mDrawable3);
}
And this is if I try to get the drawables from the resources
String gender = getGender();
if (gender.equals(Profile.GENDER_1)) {
mDrawable = mSeekBar.getContext().getResources().getDrawable(R.drawable.slider_thumb_1);
} else if (gender.equals(Profile.GENDER_2)) {
mDrawable = mSeekBar.getContext().getResources().getDrawable(R.drawable.slider_thumb_2);
} else {
mDrawable = mSeekBar.getContext().getResources().getDrawable(R.drawable.slider_thumb_3);
}
mSeekBar.setThumb(mDrawable);
In both cases the thumb is getting invisible..
What can be the problem? does somebody know the answer?
Thank you!
You are not setting the drawable's bounds before using it.
Try adding this line before the setThumb() call:
mDrawable.setBounds(0,0,
mDrawable.getIntrinsicWidth(),
mDrawable.getIntrinsicHeight()
);
I have an ImageButton which is disabled (non clickable or set as disabled). I want to give an UI feel to the user that it is disabled without using any other image.
Is there any way to do this?
Unlike a regular Button, an ImageButton or a Button that has an image background is not grayed when disabled. You actually have to use another image or to process it in a way it appears grayed.
Should using another image be ok, you can do this by using a <selector> (here associated to a regular Button but this amongs to the same):
/drawable/my_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:drawable="#drawable/button_gray" /> ***button_gray is a Drawable image***
<item android:state_pressed="true"
android:drawable="#drawable/button_gray" />
<item android:drawable="#drawable/button_red" /> ***button_red is a Drawable image***
</selector>
Please note that in a selector the logic applies a sequential way, item per item. Here, button_red is used all the time but when the button is disabled or being pushed.
Your layout.xml:
<Button android:id="#+id/myButton"
android:background="#drawable/my_selector" ***this is a reference to the selector above ***
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
And should using another image be a problem, other answers (such as #Tronman's or #southerton's) give you ways to programmatically process the image in a way it appears grayed.
#Oleg Vaskevich gave a different solution to the problem here: Disable an ImageButton
His solution allows you to gray-out an ImageButton without creating additional images or using a <selector>.
/**
* Sets the image button to the given state and grays-out the icon.
*
* #param ctxt The context
* #param enabled The state of the button
* #param item The button item to modify
* #param iconResId The button's icon ID
*/
public static void setImageButtonEnabled(Context ctxt, boolean enabled,
ImageButton item, int iconResId) {
item.setEnabled(enabled);
Drawable originalIcon = ctxt.getResources().getDrawable(iconResId);
Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
item.setImageDrawable(icon);
}
/**
* Mutates and applies a filter that converts the given drawable to a Gray
* image. This method may be used to simulate the color of disable icons in
* Honeycomb's ActionBar.
*
* #return a mutated version of the given drawable with a color filter applied.
*/
public static Drawable convertDrawableToGrayScale(Drawable drawable) {
if (drawable == null)
return null;
Drawable res = drawable.mutate();
res.setColorFilter(Color.GRAY, Mode.SRC_IN);
return res;
}
I preferred overriding the setEnabled() method in the ImageButton to change the image's alpha property accordingly. So when the button is disabled, the image will be partially transparent and more disabled-looking.
public class CustomImageButton extends ImageButton {
//...
#Override
public void setEnabled(boolean enabled) {
if(this.isEnabled() != enabled) {
this.setImageAlpha(enabled ? 0xFF : 0x3F);
}
super.setEnabled(enabled);
}
}
Elaborating on #tronman answer you can also compose a function that will gray out dynamically loaded drawables (i.e. not from resource, - for example loaded from raw svg files and converted to BitmapDrawables on the fly).
/**
* Sets the specified image buttonto the given state, while modifying or
* "graying-out" the icon as well
*
* #param enabled The state of the menu item
* #param item The menu item to modify
* #param originalIcon The drawable
*/
public static void setImageButtonEnabled(Context ctxt, boolean enabled, ImageButton item, Drawable originalIcon) {
item.setEnabled(enabled);
Drawable res = originalIcon.mutate();
if (enabled)
res.setColorFilter(null);
else
res.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
}
If you also have a non-transparent drawable on background (set with android:background) refer to selectors Android: How to Make A Drawable Selector to also modify background.
Using setImageAlpha on the ImageButton, this can be done
While Enabling,
((ImageButton) findViewById(R.id.btnImageButton1)).setEnabled(true);
((ImageButton) findViewById(R.id.btnImageButton1)).setImageAlpha(0xFF);
while disabling,
((ImageButton) findViewById(R.id.btnImageButton1)).setEnabled(false);
((ImageButton) findViewById(R.id.btnImageButton1)).setImageAlpha(0x3F);
As #SnoopDougg suggested a custom ImageButton class might be a nice idea extending the ImageButton and setting the ImageAlpha inside; haven't tried yet but.
You can set it to non clickable and also set the alpha to show that feeling that you mention.
Solution using only xml resource files:
<ImageButton
style="#style/your-style"
android:tint="#color/but_color"
android:src="#drawable/button" />
and color resource but_color (in res/color folder):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#888" />
<item android:color="?android:attr/colorAccent" />
</selector>
That is, we set color tint of the button (works fine on each Android version if using AndroidX support library). The tint itself is color-state-list. Set colors as you need, here is grey for disabled state, and accent color from theme for enabled state.
We change only color, and only need one image drawable. But note that entire color of button will be changed.
In Kotlin you can utilize Extension functions.
fun ImageButton.enable() {
this.isEnabled = true
this.imageAlpha = 0xFF
}
fun ImageButton.disable() {
this.isEnabled = false
this.imageAlpha = 0x3F
}
myButton.enable()
myButton.disable()
public static void setImageButtonEnabled(#NonNull final ImageView imageView,
final boolean enabled) {
imageView.setEnabled(enabled);
imageView.setAlpha(enabled ? 1.0f : 0.3f);
final Drawable originalIcon = imageView.getDrawable();
final Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
imageView.setImageDrawable(icon);
}
private static Drawable convertDrawableToGrayScale(#NonNull Drawable drawable) {
final ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
final Drawable mutated = drawable.mutate();
mutated.setColorFilter(filter);
return mutated;
}
If you use Kotlin, you can create an Extension Function instead, so it looks more elegant:
fun ImageView.setImageButtonEnabled(enabled: Boolean){
//Above implementation here
}
and call it using:
yourImageView.setImageButtonEnabled(true/false)
Kotlin extension function to enable/disable an ImageView/ImageButton without IconResId
fun ImageView.setImageViewEnabled(enabled: Boolean) = if(enabled) {
drawable.clearColorFilter()
isEnabled = true
} else {
drawable.colorFilter = PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN)
isEnabled = false
}
Nope, your image is the differentiating factor.. so if you don't want to change the image then you cannot tell whether the image button is disabled, enabled, pressed.
I have an ImageView with a source image set in the xml using the following syntax:
<ImageView
android:id="#+id/articleImg"
style="#style/articleImgSmall_2"
android:src="#drawable/default_m" />
Now I need to change this image programmatically. What I need to do is delete the old image and add a new one though. What I have done is this:
myImgView.setBackgroundResource(R.drawable.monkey);
It works but I noticed android stacks the new image on top of the old one (dont ask me how I found out it's not relevant for the discussion :). I definitely need to get rid of the old one before setting the new image.
How can I achieve that?
Changing ImageView source:
Using setBackgroundResource() method:
myImgView.setBackgroundResource(R.drawable.monkey);
you are putting that monkey in the background.
I suggest the use of setImageResource() method:
myImgView.setImageResource(R.drawable.monkey);
or with setImageDrawable() method:
myImgView.setImageDrawable(getResources().getDrawable(R.drawable.monkey));
*** With new android API 22 getResources().getDrawable() is now deprecated. This is an example how to use now:
myImgView.setImageDrawable(getResources().getDrawable(R.drawable.monkey, getApplicationContext().getTheme()));
and how to validate for old API versions:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
myImgView.setImageDrawable(getResources().getDrawable(R.drawable.monkey, getApplicationContext().getTheme()));
} else {
myImgView.setImageDrawable(getResources().getDrawable(R.drawable.monkey));
}
You're supposed to use setImageResource instead of setBackgroundResource.
myImgView.setImageResource(R.drawable.monkey);
is used for setting image in the current image view, but if want to delete this image
then you can use this code like:
((ImageView) v.findViewById(R.id.ImageView1)).setImageResource(0);
now this will delete the image from your image view, because it has set the resources value to zero.
get ID of ImageView as
ImageView imgFp = (ImageView) findViewById(R.id.imgFp);
then Use
imgFp.setImageResource(R.drawable.fpscan);
to set source image programatically instead from XML.
Supplemental visual answer
ImageView: setImageResource() (standard method, aspect ratio is kept)
View: setBackgroundResource() (image is stretched)
Both
My fuller answer is here.
Or try this one. For me it's working fine:
imageView.setImageDrawable(ContextCompat.getDrawable(this, image));
If you want to set in imageview an image that is inside the mipmap dirs you can do it like this:
myImageView.setImageDrawable(getResources().getDrawable(R.mipmap.my_picture)
Just write a method for changing imageview
public void setImage(final Context mContext, final ImageView imageView, int picture)
{
if (mContext != null && imageView != null)
{
try
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
imageView.setImageDrawable(mContext.getResources().getDrawable(picture, mContext.getApplicationContext().getTheme()));
} else
{
imageView.setImageDrawable(mContext.getResources().getDrawable(picture));
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}