Transformations
원문보기:링크
Transformations 란
Glide 의 Transformations 는 리소스를 가져와 변형 한 다음, 변형 된 리소스를 리턴 합니다. 일반적으로 transformations 는 이미지를 자르거나 비트맵에 필터를 적용하는데 사용되나, 움직이는 GIF 나 사용자 정의 커스텀 리소스 타입을 변환하는데 사용 할 수도 있습니다.
기본 제공 타입
Glide 에는 다음과 같이 몇가지 기본 transformations 을 포함하고 있습니다. :
적용
RequestOptions 를 사용해서 transformations 을 적용 할 수 있습니다. :
디폴트 Transformations
Glide.with(fragment)
.load(url)
.fitCenter()
.into(imageView);
혹은 RequestOptions 을 사용하는 경우,
RequestOptions options = new RequestOptions();
options.centerCrop();
Glide.with(fragment)
.load(url)
.apply(options)
.into(imageView);
RequestOption 사용에 대한 자세한 내용은 Options 페이지를 참조하시기 바랍니다.
import static com.bumptech.glide.request.RequestOptions.fitCenterTransform;
Glide.with(fragment)
.load(url)
.apply(fitCenterTransform())
.into(imageView);
만약 Generated API 를 사용한다면 transfomrations 는 inline 되어 있기 때문에 더 사용하기 쉽습니다.
GlideApp.with(fragment)
.load(url)
.fitCenter()
.into(imageView);
RequestOption 에 대해 더 알고 싶으시다면 Options 페이지를 참고 하세요.
다중 Transformations
기본적으로 transform() 을 하나의 로드에 여러개를 하나씩 적용하게 된다면 (fitCenter(), centerCrop(), bitmapTransform() etc) 이전의 적용된 것을 덮어쓰게 됩니다.
따라서 하나의 로드에 여러개의 Transformation 을 사용하기 보다는 MultiTransformation 나 숏컷 메소드인 .transforms() 메소를 사용하는 것이 좋습니다.
generated API 에서 사용할 경우 :
Glide.with(fragment)
.load(url)
.transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
.into(imageView);
generated API 의 숏컷 메소드를 사용 하는 경우 :
GlideApp.with(fragment)
.load(url)
.transforms(new FitCenter(), new YourCustomTransformation())
.into(imageView);
MultiTransformation 의 생성자에 전달하는 Transformations 의 순서대로 각각의 Transformations 이 순차적으로 적용 됩니다.
사용자 정의 Transformations
비록 Glide 에서 다양한 기본 Transformation 를 제공하고즌 있지만 경우에 따라 추가 기능을 위해 사용자 정의의 Transformation 가 필요한 경우도 있을 것 입니다.
BitmapTransformation
Bitmap 만 변환하고 싶다면 BitmapTransformation 클래스를 확장하는 것을 추천 드립니다. BitmapTransformation 은 수정된 Bitmap 을 반환하고 난 후 원래의 Bitmap 을 재활용 하는 등 몇가지 기본적인 사항을 처리 합니다.
간단하게 구현된 모습은 아래와 같습니다. :
public class FillSpace extends BitmapTransformation {
private static final String ID = "com.bumptech.glide.transformations.FillSpace";
private static final String ID_BYTES = ID.getBytes(STRING_CHARSET_NAME);
@Override
public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
if (toTransform.getWidth() == outWidth && toTransform.getHeight() == outHeight) {
return toTransform;
}
return Bitmap.createScaledBitmap(toTransform, outWidth, outHeight, /*filter=*/ true);
}
@Override
public void equals(Object o) {
return o instanceof FillSpace;
}
@Override
public int hashCode() {
return ID.hashCode();
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest)
throws UnsupportedEncodingException {
messageDigest.update(ID_BYTES);
}
}
여러분이 작성할 Transformation 이 위의 예제보다 분명 더 복잡할 테지만, 기본적인 부분과 메소드 오버라이드는 꼭 포함해야 합니다.
필수 메소드
특히, BitmapTransformation 포함 어떠한 ``Transformation` 서브 클래스들은 디스크나 메모리 캐싱이 올바르게 동작하기 위해서는 3가지 필수 메소드를 *필히** 구현하여야 합니다.:
equals()hashCode()updateDiskCacheKey
만약 Transformation 이 별도의 아규먼트(arguments) 를 가지지 않는다면, static final String 의 전체 패키지명의 ID 를 hashCode() 에 사용하고, updateDiskCacheKey() 에는 MessageDigest 를 사용하는 것이 좋습니다. 만약 Transformation 이 Bitmap 변환에 영향을 미치는 아규먼트(argments) 를 가지는 상황에서도 위 3가지 메소드는 포함하고 있어야 합니다.
예를 들의 Glide 의 RoundedCorners 는 라운드 코너의 반경(radius) 을 정하는 int 값을 가지는데, 이에 해당하는 equals(), hashCode(), updateDiskCacheKey 의 구현은 아래와 같습니다. :
@Override
public boolean equals(Object o) {
if (o instanceof RoundedCorners) {
RoundedCorners other = (RoundedCorners) o;
return roundingRadius == other.roundingRadius;
}
return false;
}
@Override
public int hashCode() {
return Util.hashCode(ID.hashCode(),
Util.hashCode(roundingRadius));
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
byte[] radiusData = ByteBuffer.allocate(4).putInt(roundingRadius).array();
messageDigest.update(radiusData);
}
본래의 String id 와 함께 roundingRadius 가 3개의 모든 메소드에 포함된 것을 확인할 수 있습니다. updateDiskCacheKey 를 보면 어떻게 ByteBuffer 를 사용해 기본 아규먼트를 updateDiskCacheKey를 구현에 사용 하는지 보여주고 있습니다.
equals() / hashCode() 을 잊지 마세요!
equals() / hashCode() 에 대해서 한번 더 언급할 가치가 있어 보입니다. equals() 와 hashCode() 는 메모리 캐싱을 위해 꼭 구현하셔야 합니다. 안타깝게도 BitmapTransformation 와 Transformation 는 위 두 함수가 오버라이드가 되어 있지 않더라도 컴파일이 될 것 입니다. 컴파일이 된다는 말이 올바르게 동작할 것을 보장한다는 말이 아닙니다. Glide 추후 버전에서는 기본 equals() 나 hashCode 만 있을 경우 컴파일 타임 에러를 발생시키는 옵션을 추가할 예정 입니다.
Glide 특수 동작
Transformations 재사용
Transformations 는 비상태기반(stateless) 이기에, Transformation을 다수의 로드에서 사용할 경우 인스턴스를 재사용 하는 것이 안전 합니다. 대개 하나의 Transformation 을 만들고 이를 다수의 로드에 패스하는 것이 좋은 사용법이라 할 수 있습니다.
ImageView 자동 변환
Glide 를 사용해서 ImageView 에 로드 할 경우 Glide 는 자동적으로 FitCenter 나 CenterCrop 을 view 의 ScaleType 에 맞추어 적용해 줍니다. 만약 scaleType 이 CENTER_CROP 이라면, Glide 는 자동적으로 CenterCrop 을 적용 할 것이며, scaleType 이 FIT_CENTER 나 CENTER_INSIDE 라면 FitCenter 를 적용 합니다.
RequestOptions 을 사용할 경우 Transformation 셋(set)으로 기본 변환을 오버라이드 할 수 있습니다. 추가적으로 dontTransform() 사용하면 Transformation 이 자동 적용 되지 않도록 할 수 있습니다.
커스텀 리소스
Glide 4.0 은 디코딩 하고자 하는 리소스의 super 타입을 지정할 수 있기에 정확하게 어떤 타입의 transfromation 을 적용해야할지 모르는 경우가 있을 수 있습니다. 예를 들어, asDrawable() (혹은 asDrawable() 이 기본이기에 with()) 를 Drawable 요청에 사용할 경우 BitmapDrawable 이나 GifDrawable 서브 클래스를 얻게 될 수 있습니다.
RequestOptions 에 추가되는 어떠한 Transformation 도 사용 가능하다록 하기 위해, Glide 는 transform() 에 제공하는 리소스를 키로 사용하는 Map 에 Transformation 을 추가합니다. 리소스가 성공적으로 디코드 되면, Glide 는 이 Map 을 탐색하여 해당 리소스에 맞는 Transformation 을 반환하게 됩니다.
Glide 는 Bitmap Transformation을 BitmapDrawable , GifDrawable , Bitmap 리소스에 사용 할 수 있습니다. 따라서 일반적으로 Bitmap Transformation 만 사용하시면 됩니다. 하지만 별도 리소스 타입을 추가할 경우 RequestOptions 의 서브 클래스를 만들고 항상 사용자 지정 타입을 위한 Transformation 을 Bitmap Transformations 과 함께 사용해야 합니다.