Android에서 데이터 바인딩을 사용하여 ImageView의 android : src에서 드로어 블 리소스 ID 설정


91

데이터 바인딩을 사용하여 드로어 블 리소스 ID를 android : src of ImageView로 설정하려고합니다.

내 물건은 다음과 같습니다.

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

2016 년 11 월 10 일 기준 답변

아래의 Splash의 주석은 사용자 정의 속성 유형 (예 :)을 사용할 필요가 없다는 점을 강조했습니다. 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 역학은 상관없이 찾을 수 있습니다.


사용하여 작동합니다 @BindingAdapter. 그러나, 값은해야 android:src하지 imageResource: @BindingAdapter("android:src"). 감사합니다!
YURIY Seredyuk

5
트윗 담아 가기 하하 제발. 그렇게하면 전체 애플리케이션에 걸쳐 xml 내에서 "android : src"의 모든 단일 사용이 무시되며 확실히 원하지 않는 작업이 수행됩니다. 제가 위에서했던 것처럼 당신이 이미지 뷰에 대한 XML을 변경해야 할 일을 imageResource을 얻으려면, 데이터 바인딩이 넣어 무엇을 작동합니다
조 마 헤르

1
좋아요, 아이디어를 이해했습니다. 이제 <ImageView imageResource="@{recipe.imageResource}" />@BindingAdapter("imageResource"). 나는 단지 놓친 imageResource="@{recipe.imageResource}"코드에서 일부는 :) 냈다
YURIY Seredyuk에게

1
필요하지 app:imageResource않습니까?
NameSpace

1
"그렇게하면 전체 애플리케이션에 걸쳐 xml 내에서"android : src "의 모든 단일 사용이 재정의됩니다."데이터 바인딩이 ImageView에만 해당 속성을 적용 할만큼 똑똑하지 않습니까? 이것이 함수에 정의 된 것이기 때문입니까? "android : src"가 더 좋을 것 같습니다 .... ImageView 바인딩 어댑터에 대해 Android 자체가 수행하는 작업을 고려하십시오. android.googlesource.com/platform/frameworks/data-binding/+/…
Splash

41

관습이 전혀 필요하지 않습니다 BindingAdapter. 그냥 사용

app:imageResource="@{yourResId}"

잘 작동합니다.

확인 어떻게 작동하는지에 대해.


2
2020 년 경에 좋은 답변이므로 더 많은
찬성 투표가 있어야합니다

확실히, 가장 좋고 가장 간단한 대답
luckyhandler

이것은 2020 년 말 현재 가장 적절하고 가장 적절한 답변 인 것 같습니다
mcy

나는 ImageView클래스를 살펴보고 setImageResource방법을 따르고 있으며 결국 해결되는 것처럼 보이며 resolveUri0이 아닌 경우 유효성 검사가 있습니다. 대한 그래서 일하는 것이 Int내가 일이 일어날 수 있는지 궁금합니다 Int?. 바인딩이 실행될 때 예를 들어 다른 호출이 있으면 executePendingBindingsnullable이 아닌 기본값은 0으로, nullables는 null로 기본 설정됩니다.
cutiko

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를 만들 수 있습니다.
qinmiao

12

당신이 직접 만들 때 표준 SDK 속성을 재정의하지 마십시오 @BindingAdapter!

이는 다음과 같은 여러 가지 이유로 좋은 접근 방식이 아닙니다. 해당 속성에 대한 Android SDK 업데이트에 대한 새로운 수정 사항의 이점을 얻지 못하게됩니다. 또한 개발자를 혼란스럽게 할 수 있으며 재사용 가능성을 위해 확실히 까다로울 수 있습니다 (재정의 될 것으로 예상되지 않기 때문에)

다음과 같은 다른 네임 스페이스를 사용할 수 있습니다.

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

또는

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

------ 업데이트 2 시작 2018 년 7 월

네임 스페이스는 사용하지 않는 것이 좋으므로 다음과 같이 접두사 또는 다른 이름을 사용하는 것이 좋습니다.

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

또는

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

------ 2018 년 7 월 2 일 업데이트 종료

그러나 다음과 같이 다른 솔루션을 권장합니다.

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

컨텍스트보기는 항상 바인딩 표현식 내에서 사용할 수 있습니다. @{ ... }


1
xml 내부의 코드는 가능한 한 피해야한다고 생각합니다. 테스트 할 수없고 쌓일 수 있으며 명확하지 않습니다. 그러나 표준 속성을 오버로딩하는 것이 혼란 스러울 수 있다는 데 동의합니다. 나는 가장 좋은 방법은이 경우 "srcResId"에 다르게 새로운 속성의 이름,하지만 여전히 BindingAdapter 사용하는 것입니다 생각
키릴 Starostin

7

Maher Abuthraa의 답변을 바탕으로 XML에서 다음을 사용하게되었습니다.

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

context변수를 볼 수 있는 수입하지 않고 표현을 결합한다. 또한 사용자 정의가 BindingAdapter필요 하지 않습니다. 주의 사항 :이 메서드 getDrawable는 API 21 이후에만 사용할 수 있습니다.


6

들어 코 틀린는 최고 수준의 유틸 파일이 넣어 정적 / 동반자 컨텍스트는 필요하지 않습니다 :

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

5

할 수있는 일이 많을수록 DataBindingAdapter

  • 데이터 바인딩을 통해 Image Url , File , Bitmap , Byte Array , Drawable , Drawable Id 무엇이든 설정할 수 있습니다 .
  • 바인딩 어댑터에 여러 매개 변수를 전달 하여 오류 이미지 / 자리 표시 자 이미지도 설정할 수 있습니다 .

다음 유형 중 하나를 설정하십시오.

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`}"
    />

모든 유형을 테스트했습니다.

SC

단일 바인딩 어댑터로 가능합니다. 이 메소드 프로젝트를 복사하십시오.

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);
    }
}

Glide를 사용하여 모든 개체를로드 한 이유

드로어 블 / 리소스 ID를로드하기 위해 Glide를 사용하는 이유를 묻는다면 대신 imageView.setImageBitmap();또는 imageView.setImageResource();. 그래서 그 이유는

  • Glide는 미디어 디코딩, 메모리 및 디스크 캐싱을 래핑하는 효율적인 이미지 로딩 프레임 워크입니다. 따라서 큰 크기의 이미지와 캐시에 대해 걱정할 필요가 없습니다.
  • 이미지를로드하는 동안 일관성을 유지합니다. 이제 모든 유형의 이미지 리소스가 Glide에 의해로드됩니다.

Piccaso, Fresso 또는 기타 이미지 로딩 라이브러리를 사용하는 경우 loadImageWithGlide방법 을 변경할 수 있습니다 .


`errorImage = "@ {@ drawable / ic_launcher}"`. 이건 저를 위해 컴파일되지도 않습니다
Vivek Mishra 2018

@VivekMishra 아마도 귀하의 ic_launcher가 mipmap에 있습니까? @ mipmap / ic_launcher를 사용해보십시오.
Khemraj

@VivekMishra 관련 오류 로그를 붙여 넣을 수 있습니까? 바인딩 유틸리티 클래스에이 메서드를 추가 했습니까?
Khemraj

**** / 데이터 바인딩 오류 **** msg : com.zuowei.circleimageview.CircleImageView에서 값 유형이 java.lang.String 인 속성 'app : src'에 대한 getter를 찾을 수 없습니다. 나는 안드로이드와 앱 네임 스페이스를 모두 시도했지만 둘 다 나를 위해 작동하지 않았습니다. 나는 또한 매개 변수에 circleImageView와 기본 이미지 뷰를 교체 한
비벡 미 쉬라에게

또한 별도의 클래스에서 바인딩 어댑터를 만들었습니다
Vivek Mishra

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

저는 Android 전문가는 아니지만 기존 솔루션을 해독하려고 몇 시간을 보냈습니다. 좋은 점은 데이터 바인딩의 전체 아이디어를 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>

그래서 여기서는 중요한 것만 유지합니다.

  • SomeViewModel내이다 ViewModel데이터 바인딩 I 사용. 확장 BaseObservable하고 사용 하는 클래스를 사용할 수도 있습니다 @Bindable. 그러나이 BindingAdapter예제에서는 또는 클래스 에 있을 필요가 없습니다 ! 평범한 수업이 할 것입니다! 이것은 나중에 설명 될 것입니다.ViewModelBaseObservable
  • app:appIconDrawable="@{model.packageName}". 예 ... 이건 정말 두통을 일으켰습니다! 그것을 분해 해보자 :
    • app:appIconDrawable: 이것은 무엇이든 될 수 있습니다 : app:iCanBeAnything! 정말. 당신은 또한 유지할 수 있습니다 "android:src"! 그러나 선택 사항을 메모 해 두십시오. 나중에 사용하겠습니다!
    • "@ {model.packageName}": 데이터 바인딩을 사용 했다면 익숙한 것입니다. 나중에 어떻게 사용되는지 보여 드리겠습니다.

이 간단한 Observable 클래스를 사용한다고 가정 해 보겠습니다.

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해당하는 getter / setter를 사용하여 어댑터를 다음과 같이 선택할 수도 있습니다 .

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)}"

그리고 그게 다야


하지만 컨텍스트를 가져와야한다는 언급을 잊었습니다. 답변을 업데이트 할 수 있습니까?
deadfish

1

Fresco (facebook 이미지 라이브러리) 사용

 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" />
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.