How to set property "android:drawableTop" of a button at runtime
Use
button.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
Sets the Drawables (if any) to appear to the left of, above, to the right of, and below the text. Use 0 if you do not want a Drawable there. The Drawables' bounds will be set to their intrinsic bounds.
If you use
button.setCompoundDrawables(left, top, right, bottom);
Sets the Drawables (if any) to appear to the left of, above, to the right of, and below the text. Use null if you do not want a Drawable there. The Drawables must already have had setBounds(Rect) called.
Drawable top = getResources().getDrawable(R.drawable.image);
button.setCompoundDrawablesWithIntrinsicBounds(null, top , null, null);
final Drawable drawableTop = getResources().getDrawable(R.drawable.btn_check_buttonless_on);
btnByCust.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
btnByCust.setCompoundDrawablesWithIntrinsicBounds(null, drawableTop , null, null);
}
});
Button button = (Button) findViewById(R.id.button);
button.setCompoundDrawables(left, top, right, bottom);
I use this code for use the "Theme.Holo" button with a "Custom image" at left and change it (the image)with a function that is called from various ways.
protected void app_dibujarLogojuego() {
if(bitmaplogojuego!=null){
bitmaplogojuego.recycle();
bitmaplogojuego=null;
}
Drawable LOGO = null;
if(verjuego.equals("COSA1")){ LOGO = getResources().getDrawable(R.drawable.img_logo_COSA1); }
if(verjuego.equals("COSA2")){ LOGO = getResources().getDrawable(R.drawable.img_logo_COSA2); }
if(verjuego.equals("COSA3")){ LOGO = getResources().getDrawable(R.drawable.img_logo_COSA3); }
if(verjuego.equals("COSA4")){ LOGO = getResources().getDrawable(R.drawable.img_logo_COSA4); }
BUTTON_DECLARED_ID.setCompoundDrawablesWithIntrinsicBounds(LOGO, null , null, null);
}
btn.setBackgroundResource(R.drawable.your_image_name_here);
If you are using Kotlin, you can use extension method to make things look elegant.
fun TextView.setDrawableTop(iconId: Int) {
val icon = this.context?.resources?.getDrawable(iconId)
this.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null)
}
Then you can use it like this:
// myTextView: TextView
myTextView.setDrawableTop(R.drawable.ic_happy)
Create an extension function like this and set top drawable like this
tvAccepted.setTopDrawable(R.drawable.ic_preparing_order_active)
fun TextView.setTopDrawable(icon: Int) {
this.setCompoundDrawablesRelativeWithIntrinsicBounds(0,icon,0,0)
}
where
setCompoundDrawablesRelativeWithIntrinsicBounds(left/start, top, right/end, bottom)
Related
How to use drawableLeft with an xml icon? I have the following button:
<Button
android:id="#+id/vitimas"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:drawableLeft="#drawable/ic_person_black_24dp"
android:drawableStart="#drawable/ic_person_black_24dp"
android:background="#drawable/botao_verde"
android:text="Vítimas"/>
In old APIs such as 16, the app stops working due to drawableLeft, I tried to use an ImageButton but the same happens, if I use app: srcCompat it works, however the icon is not stay in left, I need it to be stay in left and the text in the middle
The icon is from the Vector Asset package.
AppCompatTextView supports app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompat and app:drawableEndCompat compound drawables, supporting backported drawable types such as VectorDrawableCompat.
Include this in your gradle file
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.appcompat:appcompat-resources:1.1.0-rc01'
In your text view you can use
app:drawableLeftCompat
app:drawableStartCompat
Best way I've found:
static public void setLeftDrawable(View view, Context c, int drawable) {
Drawable leftDrawable = AppCompatResources.getDrawable(c, drawable);
if (view instanceof TextInputEditText) {
((TextInputEditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
} else if (view instanceof BootstrapEditText) {
((BootstrapEditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
} else if (view instanceof EditText) {
((EditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
} else if (view instanceof TextView) {
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}
}
Then just call passing the View, the Context and the Drawable, very easy!
add this in your gradle file
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
Older versions still do not support vector drawables in views such as TextView.
For that, you need to use the method setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) to add a drawable to a TextView, CheckboxView, and the like.
TextView tv = findViewById(R.id.tv);
tv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon, 0, 0, 0);
Do not nest views just to get this effect, it's bad for performance and unnecessary.
for a list of similar methods see the docs.
Here I added code for gradle:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
after adding this code to your application class:
#Override
public void onCreate() {
super.onCreate();
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
after this create one layer file for the vector drawable :
ic_person_black.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_person_black_24dp"/></layer-list>
and now you are able to add this file to drawable left.
android:drawableLeft="#drawable/ic_person_black.xml"
Im trying to change the color of a TextView Drawable in Xamarin.
In Java you can do it like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView txt = (TextView) findViewById(R.id.my_textview);
setTextViewDrawableColor(txt, R.color.my_color);
}
private void setTextViewDrawableColor(TextView textView, int color) {
for (Drawable drawable : textView.getCompoundDrawables()) {
if (drawable != null) {
drawable.setColorFilter(new PorterDuffColorFilter(getColor(color), PorterDuff.Mode.SRC_IN));
}
}
}
How i can do something like this in Xamarin.Android?
Try below solution
private void setTextViewDrawableColor(TextView textView, int color) {
for (Drawable drawable : textView.getCompoundDrawables()) {
if (drawable != null) {
drawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(textView.getContext(), color), PorterDuff.Mode.SRC_IN));
}
}
}
I am using this in kotlin:
tv.getCompoundDrawables()[0].setTint(//color)
Please, notice that if you set drawables in your layout file via android:drawableStart or android:drawableEnd instead of android:drawableLeft and android:drawableRight respectively you should use TextView.getCompoundDrawablesRelative(). Otherwise you can get empty array of drawables.
private void setTextViewDrawableColor(TextView textView, int color) {
for (Drawable drawable : textView.getCompoundDrawablesRelative()) {
if (drawable != null) {
drawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(textView.getContext(), color), PorterDuff.Mode.SRC_IN));
}
}
}
// index of drawable
val left = 0
val start = left
val top = 1
val right = 2
val end = right
val bottm = 3
// color int
val color = Color.RED
// apply tint for target drawable
textView.compoundDrawables.getOrNull(left)?.setTint(color)
// apply tint for all drawables
textView.compoundDrawables?.forEach { it?.setTint(color) }
NOTE!
if in XML layout you use android:stratDrawable or android:endDrawable you have to work with textView.compoundDrawablesRelative array, textView.compoundDrawables contains drawables when they have been added with android:leftDrawable or android:rightDrawable attributes.
I solve this problem adding in xml definition this line:
android:drawableTint="#color/red"
A complete example:
<TextView
android:id="#+id/tv_element"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignParentEnd="true"
android:drawableStart="#drawable/ic_icon"
android:drawableTint="#color/color"
android:visibility="visible" />
There's built in support for this through TextViewCompat.setCompoundDrawableTintList(textView, colors)
val color = ContextCompat.getColor(context, R.color.foo)
val colorList = ColorStateList.valueOf(color)
TextViewCompat.setCompoundDrawableTintList(textView, colorList)
If you want to change the tint color of the drawable of any view (tested on API 29) :
private fun setTintColor(textView: TextView, color: Int) {
DrawableCompat.setTint(DrawableCompat.wrap(textView.background).mutate(),
ContextCompat.getColor(this, color))
}
For Kotlin. Use the below extension for the TextView drawable. It supports below and above API level of 23.
private fun TextView.setTextViewDrawableColor(color: Int) {
for (drawable in this.compoundDrawablesRelative) {
drawable?.mutate()
drawable?.colorFilter = PorterDuffColorFilter(
color, PorterDuff.Mode.SRC_IN
)
}
}
Note: You can also use this function in the RecyclerView item as well, It will not override the same color for each item
I faced the problem where I am changing the color of the compound drawable and except one rest of all the colors are constant. Confusing for me.!!!
the solution that worked for me is
// Pass through the each drawable and update the tint if drawable is set.
textView.compoundDrawables.filterNotNull().forEach { drawable ->
drawable.mutate()
drawable.setTint(drawableColor)
}
Without the mutate(), the things were working partially. I got the more details here Drawable Mutations .
For the interest of the reader, I am providing a quick summery below.
Android Drawables are the drawing containers. Such as BitmapDrawable is used to display the images, ShapeDrawable is used to display the shapes and gradients.
Drawables are used extensively in the Android ecosystem thus they are optimized. So when views are created the different instances are spawned but the drawables associated with the view share the common state, called "Constant state". For example, if a drawable is a BitmapDrawable then the same bitmap is used with the all the corresponding copies or views. Advantage: It simply saves huge amount of memory.
Problem: As the same drawable is shared across the various views. Any change in the state of the drawable such as alpha, transformation etc. will impact all the places where it is used.
Solution: The mutate() method when called on a drawable, the constant state of the drawable is duplicated to allow you to change any property without affecting other drawables. Note: Bitmap is still shared.
I have a button and a text-view, text-view has a drawable-left.
After click on button the drawable-left should be removed and a plain text should be set to Text-view, but I don’t know how to remove drawable-left from code.
Thanks in advance.
The drawableLeft (or any of the similar attributes) XML attribute can be modified (removing a drawable in your case) via code using something like this:
yourTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
yourTextView.setText("The Text You Need In There");
The constructor for the method is in this order:
setCompoundDrawablesWithIntrinsicBounds (int left, int top, int right, int bottom)
Read more about the method setCompoundDrawablesWithIntrinsicBounds here
We can sets the Drawables (if any) to appear to the left of, above, to the
right of, and below the text.
Use 0 or null if you do not want a Drawable there.
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
The Drawables' bounds will be set to their intrinsic bounds.
Calling this method will overwrite any Drawables previously set using
{#link #setCompoundDrawablesRelative} or related methods.
And if we wants to set Drawables then we can use :
textView.setCompoundDrawablesWithIntrinsicBounds( R.drawable.smiley, 0, 0, 0);
The drawables of a TextView can be set programatically via the setCompoundDrawables method.
So you could try this:
textView.setCompoundDrawables(null, null, null, null);
Or
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
Add a Kotlin Extension
If you are going to be doing this frequently, adding an extension makes your code more readable
fun TextView.clearDrawables() {
this.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
}
To use the extension, simply call
view.clearDrawables()
How to do this and apply to any of the four drawables with DataBinding
#BindingAdapter(value = [
"leftDrawable",
"topDrawable",
"rightDrawable",
"bottomDrawable"], requireAll = false)
fun setCompoundDrawables(textView: TextView,
#DrawableRes left: Int?,
#DrawableRes top: Int?,
#DrawableRes right: Int?,
#DrawableRes bottom: Int?) {
textView.setCompoundDrawablesWithIntrinsicBounds(
left ?: 0,
top ?: 0,
right ?: 0,
bottom ?: 0
)}
Set All Position is Zero Your Drawable item is remove
Its Working Using This setOnFocusChangeListener method
et_feedback.setCompoundDrawablesWithIntrinsicBounds(0,0, 0, 0);
et_feedback.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
//TODO using this Drawable icon remomve onclick
et_feedback.setCompoundDrawablesWithIntrinsicBounds(0,0, 0, 0);
et_feedback.setTextColor(Color.BLACK);
}
});
In Android 2.3.x (and maybe previous versions?) when working with any scrollable Views, like a ListView or ScrollLayout, etc, when you reach the top or bottom of the list, a orange gradient appears to indicate that you are at the top or bottom of the list and can't scroll any farther. The gradient gets bigger as you try to scroll farther off the screen. I don't know what the name is of this type of widget in the SDK.
Anyways, how to do I alter it, change colors, get rid of it, etc?
ListView.setOverscrollHeader(Drawable drawable);
ListView.setOverscrollFooter(Drawable drawable);
Have a look at this
change gradient colour at end of ListView
Override setOverScrollMode method
#Override public void setOverScrollMode(int mode) {
if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
final Resources res = getContext().getResources();
final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
mEdgeGlowTop = new EdgeGlow(edge, glow);
mEdgeGlowBottom = new EdgeGlow(edge, glow);
}
} else {
mEdgeGlowTop = null;
mEdgeGlowBottom = null;
}
super.setOverScrollMode(mode); }
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();
}
}
}