I am using DataBinding to tint vector drawable of ImageView on basic of an boolean flag. This code works well for >=21 version. But fails in <21 version.
<androidx.appcompat.widget.AppCompatImageView
android:tint="#{model.nextEnabled ? #color/primary : #color/silver}"
app:srcCompat="#drawable/ic_right_blue_24dp"
/>
Here ic_right_blue_24dp is a vector drawable.
After checking binding class, I could see that code for <21 version is not getting generated.
if(getBuildSdkInt() >= 21) {
this.mboundView1.setImageTintList(androidx.databinding.adapters.Converters.convertColorToColorStateList(modelBackEnabledMboundView1AndroidColorPrimaryMboundView1AndroidColorSilver));
}
I have tried all things I could think, and could find.
AppCompatImageView
ImageView
app:srcCompat
android:src
app:tint
vectorDrawables.useSupportLibrary = true
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
Here I must tell you that all things work using regular tint without binding.
there still is custom data-binding. even exactly the method, as requested:
#BindingMethods({
#BindingMethod(
type = "androidx.appcompat.widget.AppCompatImageView",
attribute = "android:tint",
method = "setImageTintList"
)
})
This BindingAdapter will set tint programmatically...and it worked for me
#BindingAdapter("android:tint")
fun AppCompatImageView.setImageTint(#ColorInt color: Int) {
setColorFilter(color)
}
Usage
<androidx.appcompat.widget.AppCompatImageView
android:tint="#color/primary"
...
/>
Related
I have a MvxListView with custom template defined. The binding in general works well. I see labels bound. However not BackgroundColor property when binding:
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="Text Name;BackgroundColor
NativeColor(HexColor(Color))">
The Color property I tried to have as stringn as
This is the most "sophisticated" version I tried the last (HexColor is my custom ValueConverter). As there was like 20 different ones before and none of them worked. Color is I tried Color(Color) and NativeColor(Color) (accordingly to this), and without the Converter, and background, Background, backgroundColor, but nothing helps.
I also checked and it looks like the plugin is setup well for Color.
So, any ideas? Thanks!
In order the Color plugin to work make sure you have the Bootstrap class ColorPluginBootstrap in the Bootstrap folder of your native project:
using MvvmCross.Platform.Plugins;
namespace MyProject.Mobile.Droid.Bootstrap
{
public class ColorPluginBootstrap
: MvxPluginBootstrapAction<MvvmCross.Plugins.Color.PluginLoader>
{
}
}
If you have that setup correctly then you can make your own color converters based on MvxColorValueConverter<T>, e.g.:
public class BooleanToBicolorConverter : MvxColorValueConverter<bool>
{
protected override MvxColor Convert (bool value, object parameter, System.Globalization.CultureInfo culture)
{
// returns gray or white depending whether value is true or false.
return value ? new MvxColor (215, 215, 215) : new MvxColor (255, 255, 255);
}
}
And you use that like this:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
local:MvxBind="Text Name; BackgroundColor BooleanToBicolor(MyBoolProperty)">
If you want to just bind an MvxColor of your ViewModel to your View you can use MvxNativeColorValueConverter like this:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
local:MvxBind="Text Name; BackgroundColor NativeColor(MyMvxColorProperty)">
You can find the other Mvx base color converters here
HIH
I want to run the code below in order to tint a button's drawable on pre-lollipop devices, however button.getCompoundDrawables() is returning null for all 4 elements of the array when called inside of the Fragment's onCreateView method.
If I inspect the same Drawable[] array at a later point in time - say upon a button click event - I can see the drawable value has been correctly assigned (3 are null, 1 is valid).
Is there some button life cycle or fragment life cycle that I can rely on the compound drawables array to have been already properly initialized?
Drawable[] drawables = button.getCompoundDrawables();
if( drawables[2] != null){
Drawable wrapDrawable = DrawableCompat.wrap(drawables[2]);
DrawableCompat.setTint(wrapDrawable, color);
button.invalidate();
}
Here's the lib versions I'm using:
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.android.support:support-v4:24.1.1'
compile 'com.android.support:design:24.2.0'
At request, I'm including also some xml code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
[...] >
<Button
android:id="#+id/bt1"
android:background="#android:color/transparent"
android:textAppearance="#style/ConfigButtonTheme"
android:text="Sincronizar Música"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:drawableEnd="#drawable/ic_chevron_right_white_24dp"
android:textAlignment="textStart"
android:layout_width="match_parent"
android:layout_height="60dp" />
</LinearLayout>
for android:drawableRight, you should use getCompoundDrawables(), where as for android:drawableEnd, you should use getCompoundDrawablesRelative().
getCompoundDrawablesRelative()
Change android:drawableEnd to android:drawableRight. Not sure why but drawableEnd returns null in onCreate() method and drawableRight works fine.
You could configure the drawable programmatically and then set it into the text view like so.
val textDrawable = resources.getDrawable(R.drawable.ic_arrow_upward_24dp, null)
val color = ResourcesCompat.getColor(resources, R.color.colorAccent, null)
textDrawable.setTint(color)
//setCompoundDrawablesRelativeWithIntrinsicBounds(left, top, right, bottom)
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, textDrawable, null, null)
Change android:drawableEnd to android:drawableRight. Not sure why but drawableEnd returns null in onCreate() method and drawableRight works fine.
OR
Another way to do without changing android:drawableEnd to android:drawableRight.
It will work 100%
just write your code as follow:
onCreate(){
//your all statement
//at the end
findViewById(android.R.id.content).post(new Runnable() {
#Override
public void run() {
//write your code here you will get all the drawables
}
});
}
In Kotlin returns a list of drawables:
val drawables = (compoundDrawables zip compoundDrawablesRelative).map {
it.first ?: it.second
}
My guess is that the drawable hasn't been created/inflated yet. Try putting that code in either onActivityCreated, onStart or onResume within the Fragment. These are in order of when they will be called within the lifecycle, ideally you want to do this as soon as possible.
It doesn't load your drawables within TextView at the beginning. You should use
TextView.post({
// get your drawables here.
})
this function to get your drawables when it's loaded.
I am using Design Support Library version 23.4.0. I have enabled the gradle flag:
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
I am using build tools version 23.0.2, but still, I am getting Resources$NotFoundException on KitKat or lower.
It is occurring when I use android:drawableLeft or imageView.setImageResource(R.drawable.drawable_image).
And yes, I am putting this on every activity where I am using drawables
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Is this a bug of the support library?
It took 3 separate things for me to get this to work using support library 23.4.0:
Add this to build.gradle
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
Add the following to onCreate of your Application class
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
(From the reference of this link - "https://stackoverflow.com/a/45582033/10752962")
In API less then 21,use this line before setContentView();
For all XML views in which you are setting a vector drawable replace
android:src
with
app:srcCompat
and in the code replace this:
imageView.setImageResource(...);
with
imageView.setImageDrawable(...);
To complement some of the answers here: backward-compatible support for VectorDrawables comes with a price and doesn't work in all cases.
In which cases does it work? I've made this diagram to help (valid for Support Library 23.4.0 to at least 25.1.0).
Try using:
imageView.setImageDrawable(VectorDrawableCompat.create(getResources(), drawableRes, null));
You don't have to add AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
this way.
Just inflate your vector drawables using VectorDrawableCompat and you're all set.
We had the same issue. Vector drawables were not visible on Kitkat. I solved this issue by adding AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); to the onCreate method of Activities.
Before that dont forget to add:
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
and call setImageResource for the view that you use the vector drawable. My view is ImageButton. I have Android SDK build tools version 23.0.3
Sorry for being late to the party but this answer may help users who want to enable the flag AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); for all activities.
1. Create a class which extends to Application (android.app.Application)
public class MyApplicationClass extends Application
{
#Override
public void onCreate()
{
super.onCreate();
}
}
2. Head over to Manifest.xml and add the following line to your tag
<application
android:name=".MyApplicationClass"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
...
</application>
3. Add the following code above onCreate in MyApplicationClass.java
// This flag should be set to true to enable VectorDrawable support for API < 21
static
{
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Complete code for MyApplicationClass.java
import android.app.Application;
import android.support.v7.app.AppCompatDelegate;
/**
* Created by Gaurav Lonkar on 23-Dec-17.
*/
public class MyApplicationClass extends Application
{
// This flag should be set to true to enable VectorDrawable support for API < 21
static
{
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
#Override
public void onCreate()
{
super.onCreate();
}
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
use this in app.gradle
Then use AppCompatDrawableManager to setDrawable and getDrawable. Works for me
Support for vector drawables in places like android:drawableLeft was disabled in support library 23.3. It was announced on Google+:
we’ve decided to remove the functionality which let you use vector
drawables from resources on pre-Lollipop devices due to issues found
in the implementation in version 23.2.0/23.2.1. Using app:srcCompat and setImageResource()
continues to work.
Links to issues:
https://code.google.com/p/android/issues/detail?id=205236
https://code.google.com/p/android/issues/detail?id=204708
However, if you can live with those issues, in 23.4 you can re-enable this functionality using AppCompatDelegate.setCompatVectorFromResourcesEnabled().
If you're curious how this works, the best person to learn from is Chris Banes, who authored this functionality. He explains in detail on his blog.
change
imageView.setImageResource(R.drawable.drawable_image)
to
imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.drawable_image));
if you want to use vectordrawable in xml, use this:
app:srcCompat="#drawable/drawable_image"
I had a similar problem long ago, it did not work by setting
vectorDrawables.useSupportLibrary = true
only worked when I created the "mipmap" folder, and the code used
imageView.setImageResource (R.mipmap.drawable_image)
It has more Info here
Inflating Drawable's
`VectorDrawable` and `AnimatedVectorDrawable` in this support library can be inflated in this way:
Calling static getDrawable() methods:
//This will only inflate a drawable with <vector> as the root element
VectorDrawable.getDrawable(context, R.drawable.ic_arrow_vector);
//This will only inflate a drawable with <animated-vector> as the root element
AnimatedVectorDrawable.getDrawable(context, R.drawable.ic_arrow_to_menu_animated_vector);
// This will inflate any drawable and will auto-fallback to the lollipop implementation on api 21+ devices
ResourcesCompat.getDrawable(context, R.drawable.any_drawable);
If inflating the Drawable in java code, it is recommended to always use ResourcesCompat.getDrawable() as this handles Lollipop fallback when applicable. This allows the system to cache Drawable ConstantState and hence is more efficient.
The library has the following morph (bi-directional) animations :
Play-Pause morph animation
Play-Stop morph animation
Arrow-Hamburger menu morph animation
As you can see, I produced the above image on my API 16 phone:
import com.wnafee.vector.compat.AnimatedVectorDrawable;
mdrawable = (AnimatedVectorDrawable) AnimatedVectorDrawable.getDrawable(this.getApplicationContext(), R.drawable.consolidated_animated_vector);
Look at the github README for vector-compat here: https://github.com/wnafee/vector-compat
This will fix your problem (down to API 14) if you merge it with your app module's build.gradle dependencies (usually at the end of file):
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Trying to FIX Binary XML file line #2: invalid drawable tag animated-vector
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
//not needed
// compile 'com.android.support:support-vector-drawable:25.0.0'
compile 'com.wnafee:vector-compat:1.0.5'//*******holy grail *******https://github.com/wnafee/vector-compat
// Failed to resolve: com.android.support:support-animated-vector-drawable:25.0.0
//not needed
// compile 'com.android.support:support-animated-vector-drawable:25.0.0'
}
Do not put your vectors in drawable-anydpi
, old devices does not support that
put them in drawable
In my particular case, I had this problem because I was using a drawable selector as the image resource with several vectors in the selector, as in:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#drawable/vector_select_blue"/>
<item android:state_pressed="true" android:drawable="#drawable/vector_select_black"/>
.
.
etc
</selector>
Yes, pretty bad, but didn't know better at the time.
So, the right way of doing this is using the tint property in your vector file, as in:
<vector ..vector properties..
android:tint="#color/vector_color_selector">
<path ..path properties../>
</vector>
(You can also use the app:tint attribute in the AppCompatImageView)
And now, your vector_color_selector file should have the colors you want, as in:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#color/blue"/>
<item android:state_pressed="true" android:color="#color/black"/>
.
.
etc
</selector>
I hope this helps someone if previous answers didn't work for you. Stating the obvious, but I must say that you still need to set vectorDrawables.useSupportLibrary = true in gradle, use AppCompatImageView and use app:srcCompat or setImageDrawable + AppCompatResources.getDrawable to avoid any troubles with the vector compat library.
Use AppCompatImageView instead of ImageView as said by Harish Gyanani in comments , it works fine with this for me.
Official docs
I had the same problem and actually what was missing is I was using app:srcCompat on AppCompatTextView except of AppCompatImageView.
The way I have found the problematic part:
My error looks like:
Fatal Exception: android.content.res.Resources$NotFoundException
Resource ID #0x7f0700d1
Here are the steps I followed the resource id of the mentioned drawable :
APK Analyzer -> classesXXX.dex
In this dex file I opened the directory of my apps package name and went to R$drawable file
R$drawable -> Show as byte code.
Search for ID [0x7f0700d1] (check your own ID)
Find the image and check for all the usages (CMD + F7) of the resource
Fix
Hope it will help somebody.
I'm using this link (http://robobinding.github.io/RoboBinding/old_binding_attributes.html) to check which attributes are available.
I'm trying to use the "enable" attribute in a button like this:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start"
android:id="#+id/start_button"
bind:enable="{canStart}" />
But whenever I run the application, I'm getting the following error:
enabled: Unrecognized attribute 'enabled'
-------------------------The first error stack trace-----------------------
enabled: Unrecognized attribute 'enabled'
at org.robobinding.PendingAttributesForViewImpl.getResolutionErrors(PendingAttributesForViewImpl.java:43)
at org.robobinding.binder.BindingAttributeResolver.resolve(BindingAttributeResolver.java:39)
at org.robobinding.binder.BindingViewInflater.resolveAndAddViewBindingAttributes(BindingViewInflater.java:90)
at org.robobinding.binder.BindingViewInflater.onViewCreated(BindingViewInflater.java:85)
at org.robobinding.ViewFactory.notifyViewCreatedIfNotNull(ViewFactory.java:65)
at org.robobinding.ViewFactory.onCreateView(ViewFactory.java:58)
at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:177)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725)
......
If I change to "visibility" attribute it works fine.
Is the "enabled" attribute supported in buttons?
You should use new 'API and Binding Attributes JavaDocs' link from RoboBinding home page.
All simpleOneWayProperties are removed from RoboBinding framework, as they can be declared when required. The following example can be found from RoboBinding Gallery project.
#ViewBinding(simpleOneWayProperties = {"enabled"})
public class ViewBindingForView extends CustomViewBinding< View> {
}
register it:
reusableBinderFactory = new BinderFactoryBuilder()
.add(new ViewBindingForView().extend(View.class))
.build();
View Visibility is an OneWayMultiTypeProperty, as it support Boolean and Integer. Source code here - https://github.com/RoboBinding/RoboBinding/blob/develop/framework/src/main/java/org/robobinding/widget/view/ViewBindingForView.java
For supported attribute bindings for a widget, except for looking into javadoc, you can also find the implemented binding information in ViewBinding implementation, e.g., RatingBar - https://github.com/RoboBinding/RoboBinding/blob/develop/framework/src/main/java/org/robobinding/widget/ratingbar/RatingBarBinding.java
I'm having a tough time getting a basic MvvmCross Android example working where the BackgroundColor of the RelativeLayout is bound to the ViewModel.
The app runs, some text appears, and I'm expecting my background to turn Yellow. The background color, however, remains unchanged.
I have included the Hot Tuna starter pack in both my Core and Droid projects as well as the MvvmCross - Color Plugin. My Droid project was automatically given ColorPluginBootstrap.cs
Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="BackgroundColor NativeColor(BackgroundColor)">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="20sp"
android:gravity="center"
android:text="Text to make sure the layout inflates" />
</RelativeLayout>
ViewModel
public class ViewModel : MvxViewModel
{
RGBAColorConverter _rgbaConverter;
public ViewModel()
{
var color = "#ffedff00";
_rgbaConverter = new RGBAColorConverter();
BackgroundColor = _rgbaConverter.Convert(color);
}
private MvxColor _backgroundColor;
public MvxColor BackgroundColor
{
get { return _backgroundColor; }
set
{
_backgroundColor = value;
RaisePropertyChanged(() => BackgroundColor);
}
}
}
Binding works - I've tried making other ViewModel properties that were string to do simple text binding. All of that seems just fine.
I've placed debugging break points on the getter of the BackgroundColor ViewModel property and I can see the MvxColor as expected.
What am I missing for my color binding scenario?
I haven't done anything extra in the Setup.cs
I haven't created any other wiring up classes in my Droid project
I haven't created any Android-specific color converter implementations
I've just written a test app and it seems to work for me - using 3.0.14 nuget binaries.
Also, the ValueConverters test app seemed to work OK - https://github.com/MvvmCross/MvvmCross-Tutorials/tree/master/ValueConversion
Looking at your sample, the only thing I can think of is that maybe you are only testing transparent colours (RGBA #ffedff00 has Alpha=0)
If that isn't it, can you post more - perhaps a full sample somewhere?