SVG_및_VectorDrawable_파싱_및_Path_적용 - boostcampwm-2024/and04-Nature-Album GitHub Wiki

💥 SVG 및 VectorDrawable 파싱 및 Path 적용

SVG 파일과 VectorDrawable XML 파일을 파싱하여 Android Compose의 UI에서 사용할 수 있도록 한 과정을 정리하고자 한다.

문제 정의

프로젝트 초기에는 SVG 파일에서 path를 추출하지 못해 일단 하드코딩으로 path 데이터를 지정하였으나, 이후 path를 직접 추출하는 방식으로 변경을 시도하였다. 초기에 res/drawable 경로가 잘 되지 않아서 잠시 쉬는 시간을 갖고, assets 경로에 있는 SVG 파일과 res/drawable 경로에 있는 VectorDrawable XML 파일을 모두 활용할 수 있도록 두 경로의 파일을 파싱하는 작업에 도전하였다. 이 과정에서 발생한 문제와 해결 과정을 기록하였다.

image

문제 1: VectorDrawable XML 파일의 파싱 문제

문제 상황

처음 SVG 파일은 assets 경로에서 불러오는 데 성공하였으나, res/drawable 경로에 있는 VectorDrawable XML 파일에서는 width, height, viewportWidth, viewportHeight 값이 모두 0으로 출력되는 문제가 발생하였다.

원인 분석

해당 문제의 원인은 VectorDrawable XML 파일의 속성을 가져올 때 namespace가 지정되지 않아서 발생한 것으로 파악되었다. Android에서 widthheight 등 중요한 속성은 http://schemas.android.com/apk/res/android라는 네임스페이스를 통해 접근해야 한다.

해결 방법

namespace를 지정하여 width, height, viewportWidth, viewportHeight 속성을 올바르게 파싱할 수 있도록 수정하였다. 코드 내에서 ANDROID_NAMESPACE 상수를 추가하고 이를 사용하여 getAttributeValue 호출 시 namespace를 지정하여 중복 코드를 줄였다.

코드 수정 예시

private const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"

parser.getAttributeValue(ANDROID_NAMESPACE, "width")

문제 2: dpdip 단위 처리 문제

문제 상황

위 문제를 해결한 후에도 widthheight 값이 여전히 0으로 출력되는 상황이 발생하였다. 로그를 확인한 결과, VectorDrawable XML 파일의 속성 값이 dp가 아닌 dip로 출력되는 것을 확인하였다.

원인 분석

안드로이드 XML에서 dp는 때때로 dip으로 저장될 수 있다. 하지만 Float로 변환하는 과정에서 dpdip를 제거해야 하는데, 코드에서 dpreplace 처리하고 있어서 dip이 그대로 남아 Float로 변환할 수 없는 문제가 있었다.

해결 방법

해결책으로 widthheightreplace 메서드에서 dpdip를 모두 제거하도록 수정하였다.

코드 수정 예시

width = rawWidth.replace("dp", "").replace("dip", "").toFloatOrNull() ?: 0f

문제 3: 파싱한 데이터를 ClippingButton에 적용하여 표시

문제 상황

파싱한 pathData, viewportWidth, viewportHeight 데이터를 사용하여 ClippingButton을 구현할 때, 다양한 SVG 파일을 제대로 렌더링하지 못하는 상황이 발생하였다. 특히 세로 비율이 다른 SVG 파일을 화면에 맞게 표시하는 데 어려움이 있었다.

해결 방법

viewportWidthviewportHeight 값을 사용하여 비율을 동적으로 설정하도록 하였다. 이를 통해 세로 비율이 다른 파일도 화면에 맞게 표시할 수 있도록 하였다.

구현 코드 예시

Box(
    modifier = modifier
        .fillMaxWidth()
        .aspectRatio(viewportWidth / viewportHeight)
        .clip(CustomShape(path, viewportWidth, viewportHeight))
)

image

SVG 파일과 VectorDrawable 파일 중 선택

문제 상황

SVG 파일과 VectorDrawable 파일 중 어느 쪽이 더 효율적인지 결정하기 위해 용량을 비교하였다.

해결 방법

image

용량 비교 결과, SVG 파일이 VectorDrawable 파일보다 용량이 더 작았다. 따라서 파일 용량을 줄이기 위해 SVG 파일을 사용하는 것으로 결정하였다.

에셋 파일과 Drawable 파일 파싱 차이점 정리

assets 파일과 drawable 파일에서 SVGVectorDrawable 파일을 각각 불러와서 파싱하는 과정에서 차이점이 존재한다. 두 경로에서 파일을 불러오는 방식과 주의사항, 각각의 특성을 비교하여 아래에 정리하였다.

1. 파일 접근 방식

  • Assets 폴더 (assets)
    • assets 폴더는 안드로이드 앱의 정적 리소스를 담는 디렉토리로, 일반적으로 XML이 아닌 정적 파일(예: .svg, .txt, .json)을 포함한다.
    • assets 파일을 접근하기 위해서는 Contextassets.open(fileName) 메서드를 사용하여 InputStream 형태로 파일을 읽어온 후 XmlPullParser를 이용해 파싱해야 한다.
  • Drawable 폴더 (res/drawable)
    • drawable 폴더는 주로 XML 리소스 파일과 Bitmap 파일을 포함하여 Android 컴포넌트에서 바로 접근할 수 있는 경로다. 여기에는 VectorDrawable로 변환된 .xml 파일이 주로 위치하며, resources.getXml(resId) 메서드를 통해 XmlPullParser 객체를 바로 얻을 수 있다.
    • drawable 파일은 리소스 ID를 통해 쉽게 접근할 수 있으므로, 코드에서 파일 이름 대신 리소스 ID를 사용하여 호출하는 것이 일반적이다.

2. 네임스페이스 필요 여부

  • Assets 폴더
    • assets의 SVG 파일을 파싱할 때는 네임스페이스가 필요하지 않다. 파일 내 속성에 직접 접근하여 파싱할 수 있다.
  • Drawable 폴더
    • drawable의 VectorDrawable 파일에서는 네임스페이스가 반드시 필요하다. 속성(width, height, viewportWidth, viewportHeight)에 접근하기 위해서는 http://schemas.android.com/apk/res/android 네임스페이스를 지정해야 한다.

3. 단위 처리 (dp, dip 차이)

  • Assets 폴더
    • assets에서 불러온 SVG 파일에는 dpdip 단위가 포함되어 있지 않다. 따라서 추가적인 단위 변환이나 제거 작업이 필요 없다.
  • Drawable 폴더
    • drawable의 VectorDrawable 파일에서는 widthheight 등의 속성값에 dp 또는 dip 단위가 붙어 있어 Float으로 변환하기 전 이를 replace로 제거해주어야 한다. dpdip 모두를 고려하여 변환 코드를 작성해야 한다.

4. 파일 용량 차이

  • Assets 폴더의 SVG 파일
    • SVG 파일은 상대적으로 파일 용량이 작으며, 주로 벡터 그래픽으로 표현되므로 용량 측면에서 효율적이다.
  • Drawable 폴더의 VectorDrawable XML 파일
    • VectorDrawable 파일은 Android 스튜디오에서 생성된 XML 포맷으로, SVG 파일을 변환하면서 용량이 더 커지는 경향이 있다. 동일한 그래픽이라도 SVG보다 더 많은 용량을 차지할 수 있다.

요약

구분 Assets 폴더 (SVG 파일) Drawable 폴더 (VectorDrawable 파일)
접근 방식 assets.open(fileName) 사용, InputStream으로 접근 resources.getXml(resId) 사용, 리소스 ID로 접근
네임스페이스 필요 여부 필요 없음 필수(http://schemas.android.com/apk/res/android)
단위 처리 단위 없음 dp 및 dip 단위 제거 필요
파일 용량 상대적으로 작음 상대적으로 큼

assets 경로의 SVG 파일은 네임스페이스와 단위 제거가 필요 없으며 용량도 작아, 최적화를 위해 가능하면Path 추출 관련은 SVG 파일을 사용하는 방향으로 프로젝트를 진행하게 되었다.

결론

본 트러블 슈팅 과정에서는 VectorDrawable 파일과 SVG 파일을 파싱하고 Android Compose에서 사용하는 과정에서 발생한 여러 문제를 해결하였다. 이를 통해 namespace 문제 해결, 단위 처리, 동적 비율 설정 등을 성공적으로 구현하였고, 최종적으로 SVG 파일을 사용하는 방향으로 결정하였다. 이번 과정을 통해 얻은 경험은 추후 유사한 파일 파싱 및 렌더링 문제 해결에 유용하게 활용될 수 있을 것이다.

⚠️ **GitHub.com Fallback** ⚠️