본문 바로가기

Programming/Android

Glide 여러 작업 원하는 순서대로 apply() 하기 - Glide의 MultiTransformation

(부제 : 아니 CenterCrop을 하고 Radius 적용해 달라고!!!!!)

슬픈 서론...


나 : 글라이드 최고최고! 옵션만 주면 알아서 모서리 깎아줌 ㅋ
QA : 결함 - 어떤 이미지 뷰는 라운드 처리 되었으나 또 어떤 이미지 뷰는 라운드 처리 되지 않음.
나 : 아니, 절대 그럴 리가 없어.
QA : (사진 첨부)
나 : 사람은 누구나 실수를 하지. 🙂

 

며칠 전 QA 결과를 보고 이런 자잘한 실수를 했을 리가 없다고 현실 부정을 했지만 캡쳐본에는... 어떤 것은 덜 깎여있고, 어떤 것은 안 깎여있는 그런 이미지가 바인딩 되어 있었다.

ImageView의 scaleType을 정확하게 줬다고!!!!! 진짜로!!!!!😫 라고 하지 말고 제대로 살펴보자.







재현 되었던 환경


나는 해당 ImageView scaleType을 centerCrop으로 설정했다.
서버에서 보내주는 이미지의 크기가 일정하지 않기 때문에 내 이미지 뷰에 꽉 차길 바랐고, fitXY 사용 시 ImageView의 비율이 조정되기 때문에 (찌그러진다) ImageView에 공백 없이 들어찬 후 crop 되길 바랐다.
그 다음 Glide의 transform을 이용하여 radius를 적용했으나, 위에 언급한 결함이 발생하였다.







이러한 결함이 재현 되는 이유?


정확한 자료를 찾을 수는 없었지만 (링크 제보 받아요🙌) 현상이 나타난 이미지의 형태들로 추측해 봤다.

  1. 이미지 url을 전달 받음
  2. RequestOptions으로 받은 옵션들을 apply함.
  3. into() 메서드에서 받은 타겟으로 ImageView에 바인드 함

위 과정에서 3번에 ImageView의 scaleType이 bind 될 때에서야 적용되는 것이므로 이미 2번에서 가공이 완료된 사진을 넣을 때 다시 한 번 ImageView의 scaleType 값에 의해서 가공이 되는 것이라는 생각이 들었다. width와 height가 다양한 이미지가 내가 옵션을 준 대로 radius 가공이 되고, 그 후에 ImageView의 제한된 크기에 맞춰지면서 한 번 더 가공이 되어 radius 가공된 부분이 잘려져 나간 것으로 생각됐다. 그래서 ImageView의 scaleType 값을 사용하지 않고 Glide 라이브러리의 transform을 이용하여 centerCrop과 radius를 둘 다 transform을 할 수 있도록 만들었다.

Glide.with(context)
   .load(url)
   .apply(new RequestOptions().transforms(new CenterCrop(),
          new RoundedCorners(20)))
   .into(imageView);

위와 같은 소스로 변경을 하였으나 문제가 되는 현상은 여전했고 순서대로 가공할 수 있는 방법을 찾았다.







해결 방법 - MultiTransformation


MultiTransformation 은 여러 개의 Transformation을 파라미터로 받아 순서대로 transform 해준다.
아래는 Glide의 github 페이지에서 가져온 MultiTransformation 코드의 한 부분이다.

library/src/main/java/com/bumptech/glide/load/MultiTransformation.java

/**
 * A transformation that applies one or more transformations in iteration order to a resource.
 *
 * @param <T> The type of {@link com.bumptech.glide.load.engine.Resource} that will be transformed.
 */
public class MultiTransformation<T> implements Transformation<T> {
  private final Collection<? extends Transformation<T>> transformations;

  @SafeVarargs
  @SuppressWarnings("varargs")
  public MultiTransformation(@NonNull Transformation<T>... transformations) {
    if (transformations.length == 0) {
      throw new IllegalArgumentException(
          "MultiTransformation must contain at least one Transformation");
    }
    this.transformations = Arrays.asList(transformations);
  }

@NonNull
  @Override
  public Resource<T> transform(
      @NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
    Resource<T> previous = resource;

    for (Transformation<T> transformation : transformations) {
      Resource<T> transformed = transformation.transform(context, previous, outWidth, outHeight);
      if (previous != null && !previous.equals(resource) && !previous.equals(transformed)) {
        previous.recycle();
      }
      previous = transformed;
    }
    return previous;
  }

MultiTransformation 은 파라미터로 넘어온 Option들을 ArrayList에 저장해 반환한다.
이 ArrayList는 for문을 돌면서 차례대로 transform이 되고 변환이 완료된 사진을 반환한다.
따라서 아래와 같은 소스로 내가 원하는 선crop 후radius를 구현할 수 있었다.

MultiTransformation multiOption = new MultiTransformation(
                new CenterCrop(),
                new RoundedCorners(20)
        );
Glide.with(mContext)
     .load(star.getProfileImage())
     .apply(RequestOptions.bitmapTransform(multiOption))
     .into(imageView);  





참조 문헌