Android में ड्रा करने योग्य संसाधन ID सेट करें: Android में डेटा बाइंडिंग का उपयोग करके ImageView के लिए src


91

मैं android के लिए drawable resource ID सेट करने का प्रयास कर रहा हूँ: डेटा बाइंडिंग का उपयोग करके ImageView का src

यहाँ मेरी वस्तु है:

public class Recipe implements Parcelable {
    public final int imageResource; // resource ID (e.g. R.drawable.some_image)
    public final String title;
    // ...

    public Recipe(int imageResource, String title /* ... */) {
        this.imageResource = imageResource;
        this.title = title;
    }

    // ...
}

यहाँ मेरा लेआउट है:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="recipe"
            type="com.example.android.fivewaystocookeggs.Recipe" />
    </data>

    <!-- ... -->

    <ImageView
        android:id="@+id/recipe_image_view"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerCrop"
        android:src="@{recipe.imageResource}" />

    <!-- ... -->

</layout>

और अंत में, गतिविधि वर्ग:

// ...

public class RecipeActivity extends AppCompatActivity {

    public static final String RECIPE_PARCELABLE = "recipe_parcelable";
    private Recipe mRecipe;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mRecipe = getIntent().getParcelableExtra(RECIPE_PARCELABLE);
        ActivityRecipeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_recipe);
        binding.setRecipe(mRecipe);
    }

    // ...

}

यह छवि को बिल्कुल भी प्रदर्शित नहीं करता है। मैं क्या गलत कर रहा हूं?

BTW, यह पूरी तरह से मानक तरीके से काम कर रहा था:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recipe);

    final ImageView recipeImageView = (ImageView) findViewById(R.id.recipe_image_view);
    recipeImageView.setImageResource(mRecipe.imageResource);

}

जवाबों:


112

उत्तर 10 नवंबर 2016 तक

नीचे दिए गए स्पलैश की टिप्पणी ने यह उजागर किया है कि कस्टम संपत्ति प्रकार (जैसे imageResource) का उपयोग करना आवश्यक नहीं है , हम इसके बजाय कई तरीके बना सकते हैं android:srcजैसे:

public class DataBindingAdapters {

    @BindingAdapter("android:src")
    public static void setImageUri(ImageView view, String imageUri) {
        if (imageUri == null) {
            view.setImageURI(null);
        } else {
            view.setImageURI(Uri.parse(imageUri));
        }
    }

    @BindingAdapter("android:src")
    public static void setImageUri(ImageView view, Uri imageUri) {
        view.setImageURI(imageUri);
    }

    @BindingAdapter("android:src")
    public static void setImageDrawable(ImageView view, Drawable drawable) {
        view.setImageDrawable(drawable);
    }

    @BindingAdapter("android:src")
    public static void setImageResource(ImageView imageView, int resource){
        imageView.setImageResource(resource);
    }
}

पुराना उत्तर

आप हमेशा एक एडाप्टर का उपयोग करने की कोशिश कर सकते हैं:

public class DataBindingAdapters {

    @BindingAdapter("imageResource")
    public static void setImageResource(ImageView imageView, int resource){
        imageView.setImageResource(resource);
    }
}

आप तब अपने xml में एडेप्टर का उपयोग कर सकते हैं

<ImageView
    android:id="@+id/recipe_image_view"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:scaleType="centerCrop"
    imageResource="@{recipe.imageResource}" />

ध्यान रखें कि xml के भीतर का नाम BindingAdapter एनोटेशन (imageResource) से मेल खाता है

DataBindingAdapters वर्ग को विशेष रूप से कहीं भी घोषित करने की आवश्यकता नहीं है, DataBinding यांत्रिकी इसे कोई फर्क नहीं पड़ेगा (i)


यह उपयोग करके काम करता है @BindingAdapter। लेकिन, मूल्य होना चाहिए android:src, नहीं imageResource: @BindingAdapter("android:src")। धन्यवाद!
युरी सेरेडियुक

5
@YuriySeredyuk Nooooo! हाहा प्लीज। ऐसा करने से आपके संपूर्ण अनुप्रयोग में xml के भीतर "android: src" के हर एक उपयोग को ओवरराइड कर दिया जाएगा, जो आप निश्चित रूप से नहीं करना चाहते हैं। ImageResource पर काम करने के लिए आपको इमेज के लिए xml बदलना होगा जैसे मैंने ऊपर किया है, डेटाबाइंडिंग वहाँ क्या काम करेगी
जो मैहर

1
ठीक है, मैं समझ गया। अब का उपयोग कर <ImageView imageResource="@{recipe.imageResource}" />और @BindingAdapter("imageResource")। मैं सिर्फ imageResource="@{recipe.imageResource}"आपके कोड से भाग छूटा :)
यूरी सेरेडियुक

1
यह होने की जरूरत नहीं है app:imageResource?
नेमस्पेस

1
"ऐसा करना जो आपके संपूर्ण अनुप्रयोग में xml के भीतर" android: src "के हर एक उपयोग को ओवरराइड करेगा" क्या केवल स्मार्टबाय को डेटाबाइंड करना नहीं है, जो केवल उस विशेषता को ImageView में लागू कर सकता है, क्योंकि वह फ़ंक्शन में परिभाषित है? मुझे लगता है कि "एंड्रॉइड: src" बेहतर होगा .... विचार करें कि एंड्रॉइड खुद इमेज व्यू बाइंडिंग एडेप्टर के लिए क्या करता है
स्पलैश

40

किसी रिवाज BindingAdapterकी बिल्कुल भी जरूरत नहीं है । महज प्रयोग करें

app:imageResource="@{yourResId}"

और यह ठीक काम करेगा।

यह कैसे काम करता है, इसकी जांच करें


2
यह अधिक उत्तोलन होना चाहिए क्योंकि यह एक महान उत्तर है
सर्का

निश्चित रूप से, सबसे अच्छा और सबसे सरल जवाब
लखिंदर

यह सबसे अच्छा और सबसे उपयुक्त उत्तर के रूप में 2020 के अंत में
दिखता है

मैं ImageViewकक्षा पर एक नज़र डाल रहा हूं और setImageResourceविधि का पालन ​​कर रहा हूं , ऐसा लगता है कि अंततः हल हो गया है resolveUriऔर शून्य सत्यापन नहीं है। ताकि Intमुझे आश्चर्य हो कि क्या हो सकता है Int?। जब बाइंडिंग निष्पादित की जाती है, उदाहरण के लिए यदि कुछ और कॉल करता है, executePendingBindingsतो शून्य से शून्य करने के लिए अशक्त नहीं हैं, अशक्त करने के लिए।
कटिको

25

निर्धारित करें:

@BindingAdapter({"android:src"})
public static void setImageViewResource(ImageView imageView, int resource) {
    imageView.setImageResource(resource);
}

उपयोग:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:scaleType="center"
    android:src="@{viewModel.imageRes, default=@drawable/guide_1}"/>

मैं उस विधि को कहाँ जोड़ता हूँ
myatmins

समर्थन इसे किसी भी वर्ग में जोड़ सकते हैं, शायद आप एक ImageDataBindingAdapter.class बना सकते हैं।
किनमियाओ

12

जब आप अपना स्वयं का मानक एसडीके विशेषताओं को ओवरराइड नहीं करते हैं @BindingAdapter!

यह कई कारणों से एक अच्छा दृष्टिकोण नहीं है जैसे: यह उस विशेषता पर एंड्रॉइड एसडीके अपडेट पर नए फ़िक्सेस के लाभों को प्राप्त करने से रोकता है। इसके अलावा यह डेवलपर्स को भ्रमित कर सकता है और पुन: प्रयोज्यता के लिए निश्चित रूप से मुश्किल हो सकता है (क्योंकि यह अतिरंजित होने की संभावना नहीं है)

आप विभिन्न नामस्थानों का उपयोग कर सकते हैं जैसे:

custom:src="@{recipe.imageResource}"

या

mybind:src="@{recipe.imageResource}"

------ प्रारंभ अद्यतन २.जूल २०१J

नाम स्थान का उपयोग करने की अनुशंसा नहीं की जाती है, इसलिए उपसर्ग या अलग नाम पर भरोसा करना बेहतर है:

app:custom_src="@{recipe.imageResource}"

या

app:customSrc="@{recipe.imageResource}"

------ अंतिम अद्यतन २.जूल २०१J

हालाँकि, मैं विभिन्न समाधानों की सिफारिश करूंगा:

android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"

संदर्भ दृश्य हमेशा बाध्यकारी अभिव्यक्ति के अंदर उपलब्ध होता है @{ ... }


1
मुझे लगता है कि xml के अंदर कोड को जितना संभव हो उतना टाला जाना चाहिए - यह परीक्षण करने योग्य नहीं है, यह ढेर कर सकता है और यह स्पष्ट नहीं है। लेकिन मैं मानता हूं कि ओवरलोडिंग मानक विशेषताओं को भ्रमित करने वाला हो सकता है। मुझे लगता है कि सबसे अच्छा तरीका है कि नई विशेषता को अलग तरह से नाम दिया जाए, इस मामले में "srcResId", लेकिन फिर भी एक बाइंडिंग अडैप्टर का उपयोग करें
Kirill Starostin

7

Maher Abuthraa के उत्तर पर निर्माण, यह वही है जो मैंने XML में उपयोग किया है:

android:src="@{context.getDrawable(recipe.imageResource)}"

contextचर उपलब्ध है किसी भी आयात के बिना अभिव्यक्ति बंधन में। इसके अलावा, कोई कस्टम BindingAdapterआवश्यक नहीं है। केवल चेतावनी: विधि getDrawableकेवल एपीआई 21 के बाद से उपलब्ध है।


6

के लिए Kotlin एक शीर्ष स्तर utils फ़ाइल को यह कहें, कोई स्थिर / साथी संदर्भ की जरूरत:

@BindingAdapter("android:src")
fun setImageViewResource(view: ImageView, resId : Int) {
    view.setImageResource(resId)
}

5

जितना अधिक आप कर सकते हैं DataBindingAdapter

इनमें से कोई भी प्रकार सेट करें:

android:src="@{model.profileImage}"

android:src="@{roundIcon ? @drawable/ic_launcher_round : @drawable/ic_launcher_round}"

android:src="@{bitmap}"

android:src="@{model.drawableId}"

android:src="@{@drawable/ic_launcher}"

android:src="@{file}"

android:src="@{`https://placekitten.com/200/200`}"

त्रुटि छवि / प्लेसहोल्डर छवि सेट करें

placeholderImage="@{@drawable/img_placeholder}"
errorImage="@{@drawable/img_error}"


<ImageView
    placeholderImage="@{@drawable/ic_launcher}"
    errorImage="@{@drawable/ic_launcher}"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:src="@{`https://placekitten.com/2000/2000`}"
    />

सभी प्रकार का परीक्षण किया

अनुसूचित जाति

ताकि सिंगल बाइंडिंग एडॉप्टर से यह संभव हो जाए। बस इस विधि परियोजना की प्रतिलिपि बनाएँ।

public class BindingAdapters {
    @BindingAdapter(value = {"android:src", "placeholderImage", "errorImage"}, requireAll = false)
    public static void loadImageWithGlide(ImageView imageView, Object obj, Object placeholder, Object errorImage) {
        RequestOptions options = new RequestOptions();
        if (placeholder instanceof Drawable) options.placeholder((Drawable) placeholder);
        if (placeholder instanceof Integer) options.placeholder((Integer) placeholder);

        if (errorImage instanceof Drawable) options.error((Drawable) errorImage);
        if (errorImage instanceof Integer) options.error((Integer) errorImage);

        RequestManager manager = Glide.with(App.getInstance()).
                applyDefaultRequestOptions(options);
        RequestBuilder<Drawable> builder;

        if (obj instanceof String) {
            builder = manager.load((String) obj);
        } else if (obj instanceof Uri)
            builder = manager.load((Uri) obj);
        else if (obj instanceof Drawable)
            builder = manager.load((Drawable) obj);
        else if (obj instanceof Bitmap)
            builder = manager.load((Bitmap) obj);
        else if (obj instanceof Integer)
            builder = manager.load((Integer) obj);
        else if (obj instanceof File)
            builder = manager.load((File) obj);
        else if (obj instanceof Byte[])
            builder = manager.load((Byte[]) obj);
        else builder = manager.load(obj);
        builder.into(imageView);
    }
}

कारण मैंने सभी वस्तुओं को लोड करने के लिए ग्लाइड का उपयोग किया

यदि आप मुझसे पूछते हैं कि मैंने ड्राएबल / संसाधन आईडी को लोड करने के लिए ग्लाइड का उपयोग क्यों किया, तो इसके बजाय मैं उपयोग imageView.setImageBitmap();कर सकता था या imageView.setImageResource();। तो इसका कारण है

  • ग्लाइड एक कुशल छवि लोडिंग फ्रेमवर्क है जो मीडिया डिकोडिंग, मेमोरी और डिस्क कैशिंग को लपेटता है। इसलिए आपको बड़े आकार की छवियों और कैश के बारे में चिंता करने की आवश्यकता नहीं है।
  • छवि लोड करते समय निरंतरता बनाने के लिए। अब सभी प्रकार के छवि संसाधन ग्लाइड द्वारा लोड किए गए हैं।

यदि आप पिकासो, फ्रेसो या किसी अन्य छवि लोडिंग लाइब्रेरी का उपयोग करते हैं, तो आप loadImageWithGlideविधि में बदलाव कर सकते हैं


`errorImage =" @ {@ drawable / ic_launcher} "`। यह बात मेरे लिए भी संकलित नहीं है
विवेक मिश्रा

@VivekMishra शायद आपका ic_launcher mipmap में है ?, @ mipmap / ic_launcher आज़माएं।
खेमराज

@VivekMishra क्या आप अपनी प्रासंगिक त्रुटि लॉग पेस्ट कर सकते हैं? क्या आपने इस विधि को अपने बाध्यकारी उपयोग वर्ग में जोड़ा है?
खेमराज

**** / डेटा बाइंडिंग त्रुटि **** संदेश: विशेषता प्रकार के लिए गेट्टर नहीं ढूँढ सकता: 'src' मान प्रकार के साथ java.lang.String पर com.zuowei.circleimageview.CircleImageView। मैंने दोनों एंड्रॉइड के साथ-साथ ऐप नेमस्पेस के साथ प्रयास किया और दोनों ने मेरे लिए काम नहीं किया। मैंने पैरामीटर में डिफ़ॉल्ट इमेजव्यू को सर्कलआईएमएज व्यू के साथ बदल दिया है
विवेक मिश्रा

इसके अलावा मैंने एक अलग वर्ग में बाइंडिंग एडेप्टर बनाया है
विवेक मिश्रा

3
public Drawable getImageRes() {
        return mContext.getResources().getDrawable(R.drawable.icon);
    }

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="center"
    android:src="@{viewModel.imageRes}"/>


2

मैं एंड्रॉइड का विशेषज्ञ नहीं हूं, लेकिन मैंने मौजूदा समाधानों को समझने के लिए घंटों बिताए। अच्छी बात यह है कि मैंने डेटा बाइंडिंग के पूरे विचार को BindingAdapterथोड़ा बेहतर इस्तेमाल करते हुए समझ लिया । उसके लिए, मैं मौजूदा जवाबों के लिए कम से कम आभारी हूं (हालांकि भारी रूप से अपूर्ण)। यहाँ दृष्टिकोण का एक पूर्ण टूटने:

मैं BindingAdapterइस उदाहरण में भी उपयोग करूंगा । तैयारी करना xml:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="model"
            type="blahblah.SomeViewModel"/>
    </data>

    <!-- blah blah -->

    <ImageView
        android:id="@+id/ImageView"
        app:appIconDrawable="@{model.packageName}"/>

    <!-- blah blah -->
</layout>

इसलिए यहाँ मैं केवल महत्वपूर्ण सामान रख रहा हूँ:

  • SomeViewModelViewModelडेटा बाइंडिंग के लिए मेरा उपयोग है आप एक वर्ग का उपयोग भी कर सकते हैं जो विस्तार BaseObservableऔर उपयोग करता है @Bindable। हालाँकि, BindingAdapterइस उदाहरण में, कक्षा या कक्षा में होना आवश्यक नहीं है ! एक सादा वर्ग करेगा! इसका चित्रण बाद में किया जाएगा।ViewModelBaseObservable
  • app:appIconDrawable="@{model.packageName}"। हाँ ... यह वास्तव में मुझे सिरदर्द पैदा कर रहा था! चलो इसे तोड़ दो:
    • app:appIconDrawable: यह कुछ भी हो सकता है app:iCanBeAnything:! वास्तव में। आप भी रख सकते हैं "android:src"! हालाँकि, अपनी पसंद पर ध्यान दें, हम इसे बाद में उपयोग करेंगे!
    • "@ @ model.packageName}": यदि आपने डेटा बाइंडिंग के साथ काम किया है , तो यह परिचित है। मैं दिखाता हूँ कि यह बाद में कैसे उपयोग किया जाता है।

चलिए मान लेते हैं कि हम इस सरल वेधशाला का उपयोग करते हैं:

public class SomeViewModel extends BaseObservable {
   private String packageName; // this is what @{model.packageName}
                               // access via the getPackageName() !!!
                               // Of course this needs to be set at some
                               // point in your program, before it makes
                               // sense to use it in the BindingAdapter.

   @Bindable
   public String getPackageName() {
       return packageName;
   }

   public void setPackageName(String packageName) {
       this.packageName = packageName;
       notifyPropertyChanged(BR.packageName);
   }

   // The "appIconDrawable" is what we defined above! 
   // Remember, they have to align!! As we said, we can choose whatever "app:WHATEVER".
   // The BindingAdapter and the xml need to be aligned, that's it! :)
   //
   // The name of the function, i.e. setImageViewDrawable, can also be 
   // whatever we want! Doesn't matter.
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }
}

जैसा कि वादा किया गया है, आप इसे public static void setImageViewDrawable()किसी अन्य वर्ग में भी स्थानांतरित कर सकते हैं , उदाहरण के लिए, आपके पास एक वर्ग हो सकता है BindingAdapters:

public class BindingAdapterCollection {
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }
}

एक और महत्वपूर्ण टिप्पणी यह ​​है कि मेरी Observableकक्षा में मैं String packageNameअतिरिक्त जानकारी पास करता था setImageViewDrawable। आप उदाहरण के लिए चुन सकते हैं int resourceId, संगत गेटर्स / सेटर्स के लिए, जिसके लिए एडेप्टर बन जाता है:

public class SomeViewModel extends BaseObservable {
   private String packageName; // this is what @{model.packageName}
                               // access via the getPackageName() !!!
   private int resourceId;     // if you use this, don't forget to update
                               // your xml with: @{model.resourceId}

   @Bindable
   public String getPackageName() {
       return packageName;
   }

   public void setPackageName(String packageName) {
       this.packageName = packageName;
       notifyPropertyChanged(BR.packageName);
   }

   @Bindable
   public int getResourceId() {
       return packageName;
   }

   public void setResourceId(int resourceId) {
       this.resourceId = resourceId;
       notifyPropertyChanged(BR.resourceId);
   }

   // For this you use: app:appIconDrawable="@{model.packageName}" (passes String)
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }

   // for this you use: app:appIconResourceId="@{model.resourceId}" (passes int)
   @BindingAdapter({"appIconResourceId"})
   public static void setImageViewResourceId(ImageView imageView, int resource) {
       imageView.setImageResource(resource);
   }
}

2

यह मेरे लिए काम करता है। मैंने इसे टिप्पणी के रूप में @hqzxzwb उत्तर में जोड़ा होगा लेकिन प्रतिष्ठा सीमाओं के कारण।

मेरे विचार में यह मॉडल है

var passport = R.drawable.passport

फिर मेरे xml में, मेरे पास है

android:src="@{context.getDrawable(model.passort)}"

और बस


ठीक है, लेकिन आप उल्लेख करना भूल जाते हैं कि आपको संदर्भ आयात करना होगा। क्या आप अपना उत्तर अपडेट कर सकते हैं?
डेडफिश

1

फ्रेस्को (फेसबुक इमेज लाइब्रेरी) का उपयोग करना

 public class YourCustomBindingAdapters {

    //app:imageUrl="@{data.imgUri}"
    @BindingAdapter("bind:imageUrl")
    public static void loadImage(SimpleDraweeView imageView, String url) {
        if (url == null) {
            imageView.setImageURI(Uri.EMPTY);
        } else {
            if (url.length() == 0)
                imageView.setImageURI(Uri.EMPTY);
            else
                imageView.setImageURI(Uri.parse(url));
        }
    }
}

0

आपके विचार में राज्य या दृश्य मॉडल वर्ग;

 fun getSource(context: Context): Drawable? {
        return ContextCompat.getDrawable(context, R.drawable.your_source)
    }

अपने XML में;

<androidx.appcompat.widget.AppCompatImageButton
   .
   .
   .
   android:src="@{viewState.getSource(context)}"

0
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
           name="model"
           type="YourViewModel"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:background="?android:attr/selectableItemBackground"
          android:paddingStart="@dimen/dp16"
          android:paddingTop="@dimen/dp8"
          android:paddingEnd="@dimen/dp8"
          android:paddingBottom="@dimen/dp8">

          <ImageView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" 
              android:src="@{model.selected ? @drawable/check_fill : @drawable/check_empty}"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

0

चित्र को इस तरह सेट करें,

  <ImageView
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:src="@{model.isActive ? @drawable/white_activated_icon :@drawable/activated_icon}"
        tools:src="@mipmap/white_activated_icon" />
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.