Glide 동작을 테스트하면서 아래와 같은 상황이 발생하였다.
기존에 사용하던 로딩이미지의 ScaleType은 CENTER를 사용해야 한다.
Glide로 로드한 이미지는 로딩이미지와는 다른 각자의 ScaleType을 가지고 있다.
따라서 loadingImage와 loadedImage의 ScaleType을 외부에서 설정만 해주면 내부에서 자동으로 바꿔서 보여주도록 만들고자 했다.
이 작업을 위해 Glide에서는 이미지 로딩 중 placeholder 노출, 리소스 로드 등의 동작을 확장 구현할 수 있도록 Target을 제공한다는 점을 먼저 말해두겠다. 이 Target은 into()를 통해 전달할 수 있다.
1 2 3 4 5 6 Target<Drawable> target = Glide.with(fragment) .load(url) .into(new Target<Drawable>() { ... });
이러한 Target를 상속받는 클래스를 만들어서 placeholder는 onLoadStarted, error는 onLoadFailed에 각각 정의하려고 한다. 이때 로딩이미지는 drawable 리소스로 앱에 저장되어있기 때문에 DrawableImageViewTarget을 상속받아 만든 게 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class ScaleLoadingImageViewTarget extends DrawableImageViewTarget { private ImageView.ScaleType mLoadingScaleType; private ImageView.ScaleType mReadyScaleType; public ScaleLoadingImageViewTarget (ImageView view, ImageView.ScaleType scaleType) { super (view); mLoadingScaleType = scaleType; mReadyScaleType = view.getScaleType(); } @Override public void onLoadStarted (@Nullable Drawable placeholder) { ImageView imageView = getView(); imageView.setScaleType(mLoadingScaleType); super .onLoadStarted(placeholder); } @Override public void onLoadFailed (@Nullable Drawable errorDrawable) { ImageView imageView = getView(); imageView.setScaleType(mLoadingScaleType); super .onLoadFailed(errorDrawable); } @Override public void onResourceReady (@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) { ImageView imageView = getView(); imageView.setImageResource(0 ); imageView.setScaleType(mReadyScaleType); super .onResourceReady(resource, transition); } @NonNull public static ScaleLoadingImageViewTarget loadingCenter (ImageView imageView) { return new ScaleLoadingImageViewTarget(imageView, ImageView.ScaleType.CENTER); } }
loadingCenter
메소드를 통해 위에 새롭게 정의된 Target에 접근할 수 있도록 한다.
1 2 3 4 5 Glide.with(context) .load(url) .listener(listener) .apply(options) .into(ScaleLoadingImageViewTarget.loadingCenter(imageView));
참고링크
그러나 이 방식을 적용한 ImageView가 담긴 RecyclerView를 구현하게 되면, RecyclerView 각 아이템이 재사용되면서 ScaleLoadingImageViewTarget의 생성자에서 호출하는 view.getScaleType()
의 값이 기대한 대로 나오지 않는 경우가 있어 문제가 될 수 있다.
따라서 이를 아래와 같이 view의 ScaleType을 명시적으로 받도록 변경하였다.
1 2 3 4 5 Glide.with(context) .load(url) .listener(listener) .apply(options) .into(ScaleLoadingImageViewTarget.loadingCenter(imageView, ScaleType.FIT_CENTER));
1 2 3 4 5 6 7 8 9 10 public ScaleLoadingImageViewTarget (ImageView view, ImageView.ScaleType originScaleType, ImageView.ScaleType loadingScaleType) { super (view); mLoadingScaleType = loadingScaleType; mReadyScaleType = originScaleType; } @NonNull public static ScaleLoadingImageViewTarget loadingCenter (ImageView imageView, ImageView.ScaleType originScaleType) { return new ScaleLoadingImageViewTarget(imageView, originScaleType, ImageView.ScaleType.CENTER); }