Android에서 데이터 바인딩을 사용하여 ImageView의 android : src에서 드로어 블 리소스 ID 설정
드로어 블 리소스 ID를 데이터 바인딩을 사용하여 ImageView의 android : 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);
}
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"})
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}"/>
고유 한 속성을 만들 때 표준 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)}"
컨텍스트보기는 항상 바인딩 표현식 내에서 사용할 수 있습니다. @{ ... }
들어 코 틀린는 최고 수준의 유틸 파일이 넣어 정적 / 동반자 컨텍스트는 필요하지 않습니다 :
@BindingAdapter("android:src")
fun setImageViewResource(view: ImageView, resId : Int) {
view.setImageResource(resId)
}
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}"/>
할 수있는 일이 많을수록 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`}"
/>
모든 유형을 테스트했습니다.
단일 바인딩 어댑터로 가능합니다. 이 메소드 프로젝트를 복사하십시오.
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
방법 을 변경할 수 있습니다 .
당신은 다음을 할 수 있습니다
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"
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));
}
}
}
저는 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
예제에서는 또는 클래스 에 있을 필요가 없습니다 ! 평범한 수업이 할 것입니다! 이것은 나중에 설명 될 것입니다.ViewModel
BaseObservable
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);
}
}
보기 상태 또는보기 모델 클래스에서;
fun getSource(context: Context): Drawable? {
return ContextCompat.getDrawable(context, R.drawable.your_source)
}
XML에서;
<androidx.appcompat.widget.AppCompatImageButton
.
.
.
android:src="@{viewState.getSource(context)}"
'Program Tip' 카테고리의 다른 글
CSV 파일을 Pandas DataFrame으로 가져 오기 (0) | 2020.11.04 |
---|---|
이 경우 bool과 not bool이 모두 true를 반환하는 이유는 무엇입니까? (0) | 2020.11.04 |
Bitmap.Clone ()과 새 Bitmap (Bitmap)의 차이점은 무엇입니까? (0) | 2020.11.03 |
OWIN HttpListener를 찾을 수 없습니다. (0) | 2020.11.03 |
Pandas 및 matplotlib를 사용하여 범주 형 데이터 플로팅 (0) | 2020.11.03 |