Vector Drawable과 하위호환

Vector Drawable

VectorDrawable은 API 21이상에서만 지원

getDrawable(R.drawable.vector)는 VectorDrawable을 반환한다.

API 21 이전 버전에서 Vector 지원

  • 하위 호환을 위한 PNG 생성

    • build.gradle에 android { defaulConfig { vectorDrawables.useSupportLibrary = true }} 옵션을 주지 않는 경우 빌드 중 하위 호환을 위한 PNG를 생성하며 pre-21에서 getDrawable(R.drawable.vector)는 BitmapDrawable를 반환한다.
  • vectorDrawables.useSupportLibrary = true

    • pre-21에서 getDrawable(R.drawable.vector)는 VectorDrawableCompat을 반환한다.
    • 모든 theme가 AppCompat를 상속해야 한다.
    • XML에서 vector 참조시 ImageView와 ImageButton은 app:srcCompat 속성을 사용해야 한다.

21 이전 버전에서 Issue

  • pre-21에서 벡터 이미지와 동일한 이름으로 png 파일을 등록하면 실행시 이미지 리소스를 제대로 찾지 못해서 crash 발생

  • ImageView에 android:tint 사용하시면 pre-21에서 크래시 발생. 대안으로

    • AppCompatImageView에 app:tint와 app:tintMode 사용
    • Vector xml 파일에 android:tint, android:tintMode 사용
    • java 코드에서 적용
  • Context의 Resources로 Drawable를 얻으려면
    • AppCompatResources.getDrawable 사용해야 함.

    • ContextCompat.getDrawable 사용시 pre-21에서 crash

svg

그리는 옵션은 두 가지 non-zero, even-odd

even-odd는 API 24이상만 지원. 이하에서는 의도와 다르게 표시될 가능성이 있음.

AppCompatDelegate.setCompatVectorFromResourcesEnabled 옵션 적용

  • SDK 21 버전 부터 true, 이전은 false

  • 21 이하 버전에서 selector에서 vector 이미지 사용 가능하도록 처리하기 위하여 옵션을 true로 해야함.​

하위 호환을 위해 주의할 점

  • 옵션을 true로 설정하고 selector에 vector 이미지를 사용하는 경우에는 compat 속성를 사용하지 않아도 되지만 되도록이면 모두 compat속성을 사용을 하는 것이 좋음.

  • AppCompatImageView, VectorDrawableTextView, VectorDrawableCheckedTextView 등에서 제공되는 compat 속성 사용

  • 만일 compat 속성이 없는 경우에는 selector를 사용하여 회피하거나 compat 속성을 추가한 커스텀 뷰 개발

  • 일반적인 background 속성인 경우에는 selector를 사용하여 회피 가능

AppCompatDelegate.setCompatVectorFromResourcesEnabled 옵션 참고 사항

  • 작동 방식

  • TypedArray에서 drawable을 로딩할때는 Resources.loadDrawable을 사용함. 이 메서드는 package scope이기 때문에 재정의가 불가능함.

  • StateListDrawable은 Resources.getDrawable을 사용함. 이 메서드는 public이기 때문에 재정의가 가능

  • setCompatVectorFromResourcesEnabled을 true로 켜도 TypedArray에서 drawable을 가져올 경우에는 21버전 이하에서 VectorEnabledTintResources.getDrawble을 사용 할 수 없기 때문에 android 기본 속성에서는 백터 이미지를 사용할 수 없지만 selector는 사용 가능

  • 즉, selector에 벡터 이미지를 쓰고 싶어도 true로 설정해야 하고 이를 역 이용하여 selector에 무조건 백터 이미지를 포함시켜서 srcCompat을 안 써도 사용할 수 있는 것임.

  • 메모리 이슈

  • api 문서에서 언급하는 메모리 이슈는 모든 벡터 이미지에 대해서 selector를 사용해야 하기 때문에 메모리 이슈가 있을 수 있다는 것으로 해석됨.

  • selector를 사용 안하는 경우에 대해서는 compat 속성을 사용하면 되기 때문에 옵션을 적용해서 생기는 메모리 이슈는 없을 것으로 예상됨.​

추가적으로 발견된 이슈

  • sdk 21 이전 버전에서 벡터 이미지와 동일한 이름으로 png 파일을 등록하면 실행시 이미지 리소스를 제대로 찾지 못해서 crash 발생
  • ImageView에 android:tint 사용하시면 하위버전(21 미만)에서 크래시 발생합니다.

    확인하시고 수정 부탁드립니다.

    • 참고 : 아래 방법으로 해결 하시면 될 듯 합니다.

    • AppCompatImageView에 app:tint와 app:tintMode 사용

    • Vector xml 파일에 android:tint, android:tintMode 사용

    • java 코드에서 적용

  • minSdk 17로 설정하기

호환 안 되는 drawable 관련 api 사용으로 하위 버전에서 크래시가 발생합니다. 17로 켜서 테스트 하시는게 좋을 것 같습니다.

​

  1. DrawableCompat.setTintMode, setTint 사용하기

​

drawable은 하위 api에서 setTint가 동작 하지 않습니다. DrawableCompat.setTint나 ApiCompatUtils.setTint를 사용하시고요.

​

Mode를 바꿔서 쓰시려면 DrawableCompat.setTintMode, setTint 조합을 사용하십시오. 이때는 mutate()를 사용해서 drawable 상태 변수를 복사하여 사용하세요.

​

  1. ContextCompat.getDrawable 사용하지 마세요.

ContextCompat.getDrawable을 사용하지 마십시오. AppCompatResources.getDrawable을 사용하세요. 테스트 해보니 하위 버전에서 크래시 납니다.

​

  1. srcCompat 적용 안된 부분 확인하기

벡터 이미지 적용만 하고 srcCompat을 적용 안한 곳이 있습니다. 수정 바랍니다.

​

  1. VectorDrawable로 형변환을 하지 마세요.

하위 버전에는 해당 클래스가 없습니다. 형변환은 하지 마세요.

​

  1. TypeArray에서 getDrawable을 사용하지 마세요.

커스텀 뷰에서 사용할 수 있는데요. 이미지를 벡터로 바꿨다면 AppCompatResources를 사용하세요.

​

  1. background에 vector를 사용할 경우에는 아래와 같이 변경하십시오.

background에 벡터를 사용하시면 다음과 같이 대응하시면 됩니다.

​

  • TextView_background를 사용할 경우에는 VectorDrawableTextView에 backgroundCompat 속성을 추가하였습니다. 이것을 사용하십시오.

  • Button_background 속성을 사용할 경우에는 ImageView를 사용하시고 srcCompat을 사용하시면 될것 같습니다.

​

기타 다른 상황에서 크래시가 발생하면 공유 부탁드립니다.

​

* Vector 사용 옵션 변경 테스트 상황 공유

​

해외 포럼에나 국내 블로그에서 찾아 봤을때는 StateListDrawable을 사용하면 안전하게 vector를 사용할 수 있다고 했으나...

​

sdk

<

= 19 이하에서 state list drawable 생성시에 벡터 이미지를 제대로 로딩하지 못하고 크래시가 발생해서.. 결국에는...

if 
(Build.VERSION.
SDK_INT 
<
= Build.VERSION_CODES.
KITKAT
) {


   AppCompatDelegate.
setCompatVectorFromResourcesEnabled
(
true
)
;


}

​

이 옵션을 켜고 테스트 하려고 합니다. AppCompatActivity를 context로 사용하게 되면 Resources를 Vector를 사용가능하게 만들어주는 옵션인데요.

​

@Override


public 
Resources 
getResources
() {


if 
(
mResources 
== 
null 
&
&
 VectorEnabledTintResources.shouldBeUsed()) {


mResources 
= 
new 
VectorEnabledTintResources(
this, super
.getResources())
;


}


return 
mResources 
== 
null 
? 
super
.getResources() : 
mResources
;


}

​

이렇게 하면 AppCompatActivity 내부의 뷰는 모두 VectorEnabledTintResources를 사용해야 하는데 문제는 TypedArray만 기본 Resources를 사용하는 것으로 보입니다.

​

결국에는 위 옵셥을 켜면 일단 state list drawable을 사용하는데는 무리는 없으나 srcCompat을 적용한 곳에서만 크래시 없이 사용할 수 있습니다.

​

19 버전 이하에만 옵션을 켜놨고 위에 공유해드린 수정 사항을 17 버전에서 수정하고 테스트 하시면 됩니다. 더 자세한 내용은 정확하게 파악하고 나서 추가 공유드릴게요.

​

각 서비스에서도 하위 버전에서 위와 같이 테스트 하시고 메모리나 성능 이슈가 없는 확인 부탁드립니다.

​

설날이네요... ^^;; 연휴 잘 보내시고 새해 복많이 받으세요~

​

감사합니다.

  • ​

results matching ""

    No results matching ""