벡터 드로어 블 크기 조정이 예상대로되지 않는 이유는 무엇입니까?


97

Android 앱에서 벡터 드로어 블을 사용하려고합니다. 에서 http://developer.android.com/training/material/drawables.html (강조 광산) :

Android 5.0 (API 레벨 21) 이상에서는 정의 를 잃지 않고 확장되는 벡터 드로어 블을 정의 할 수 있습니다 .

이 드로어 블 사용 :

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="@color/colorPrimary" android:pathData="M14,20A2,2 0 0,1 12,22A2,2 0 0,1 10,20H14M12,2A1,1 0 0,1 13,3V4.08C15.84,4.56 18,7.03 18,10V16L21,19H3L6,16V10C6,7.03 8.16,4.56 11,4.08V3A1,1 0 0,1 12,2Z" />

그리고이 ImageView :

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:src="@drawable/icon_bell"/>

아이콘을 400dp로 표시하려고 할 때이 흐릿한 이미지를 생성합니다 (롤리팝을 실행하는 2015 년 경의 거대한 고해상도 모바일 장치에서).

blurryBellIcon

벡터 드로어 블 정의에서 너비와 높이를 200dp로 변경하면 400dp 렌더링 크기에서 상황이 크게 개선됩니다. 그러나이를 TextView 요소 (예 : 텍스트 왼쪽의 아이콘)에 대한 드로어 블로 설정하면 이제 거대한 아이콘이 생성됩니다.

내 질문 :

1) 벡터 드로어 블에 너비 / 높이 사양이있는 이유는 무엇입니까? 나는 이것들의 전체 요점은 그들이 정의에서 너비와 높이를 무의미하게 만드는 무손실로 확장 및 축소된다는 것이라고 생각했습니다.

2) TextView에서 24dp 드로어 블로 작동하지만 훨씬 더 큰 이미지를 사용하기 위해 잘 확장되는 단일 벡터 드로어 블을 사용할 수 있습니까? 예를 들어 크기가 다른 여러 벡터 드로어 블을 만드는 것을 피하고 대신 렌더링 된 요구 사항에 맞게 조정되는 것을 사용하는 방법은 무엇입니까?

3) 너비 / 높이 속성을 효과적으로 사용하는 방법과 viewportWidth / Height의 차이점은 무엇입니까?

추가 세부 사항:

  • 장치가 API 22를 실행 중입니다.
  • Gradle 버전 1.5.0과 함께 Android Studio v1.5.1 사용
  • 매니페스트는 컴파일 및 목표 레벨 23, 최소 레벨 15입니다. 또한 최소 레벨을 21로 이동하려고 시도했지만 차이가 없습니다.
  • APK를 디 컴파일하면 (최소 레벨이 21로 설정 됨) 드로어 블 폴더에 단일 XML 리소스가 표시됩니다. 래스터 화 된 이미지는 생성되지 않습니다.

명확하게. Android 스튜디오를 사용하고 계십니까? Android Studio의 버전과 Gradle 플러그인의 버전은 무엇인가요? Android Studio에서 드로어 블 폴더를 마우스 오른쪽 버튼으로 클릭하고 선택하면 드로어 블 폴더에 New -> Vector Asset벡터 이미지 XML이 드롭됩니다. 그러나 apktool을 사용하여 빌드 된 APK의 압축을 풀면 XML 파일이 drawable-anydpi-v21API 21+ 기기에서 올바르게 확장되고 있음을 알 수 있습니다. 래스터 파일은 drawable-<mdpi/hdpi/etc>-v4폴더에 배치되고 API 21+ 장치에서는 사용되지 않습니다 (올바르게 확장된다는 사실을 기반으로 함)
Cory Charlton

@Cory Charlton. 궁금한. Gradle 1.5.0과 함께 Studio 1.5.1을 사용하고 있습니다. 최소 레벨을 21로 변경 한 후 APK에 이미지가 나타나는 유일한 위치는 drawable폴더입니다. 벡터 드로어 블 xml 파일의 너비 / 높이는 24dp입니다. 400dp 높이 / 너비의 ImageView를 지정하면 확실히 잘못된 크기의 이미지가 생성됩니다.
Chris Knight

그것이 내가 기대하는 것입니다. 내가으로 끝나는 유일한 이유는 내 나이 가 21 세 미만 drawable-anydpi-v21이기 때문 minSdkVersion입니다. 21 미만으로 설정하면 행동에 변화가 minSdkVersion있습니까? XML을 이동하는 것은 drawable-anydpi어떻습니까? 나는 변화가 기대하지 않을 것이다 그러나 나는 또한 벡터 이미지가 ... 제대로 확장 될 기대
코리 찰튼

최소 버전을 다시 15로 변경하면 사용자와 동일한 결과가 생성됩니다. drawable-anydpi-v21mdi / hdpi / etc에서 다양한 래스터 화 된 이미지가있는 단일 xml 파일 . 폴더. 그래도 최종 렌더링 결과에는 변경이 없습니다.
Chris Knight

매우 이상합니다 ... 귀하의 이미지를 사용하여 내 앱 중 하나를 수정
Cory Charlton

답변:


100

여기에이 문제에 대한 새로운 정보가 있습니다.

https://code.google.com/p/android/issues/detail?id=202019

사용 android:scaleType="fitXY"하면 Lollipop에서 올바르게 확장되는 것 같습니다 .

Google 엔지니어로부터 :

안녕하세요, 이미지를 선명하게 보이게하려면 scaleType = 'fitXY'가 해결 방법이 될 수 있는지 알려주세요.

마시멜로 대 롤리팝은 마시멜로에 추가 된 특별한 스케일링 처리 때문입니다.

또한 귀하의 의견 : "올바른 동작 : 벡터 드로어 블은 품질 손실없이 확장되어야합니다. 따라서 응용 프로그램에서 3 가지 다른 크기의 동일한 자산을 사용하려는 경우 vector_drawable.xml을 다른 파일로 3 번 복제 할 필요가 없습니다. 하드 코딩 된 크기. "

이것이 사실이어야한다는 데 전적으로 동의하지만, 실제로 Android 플랫폼은 아직 이상적인 세계에 도달하지 못할 정도로 성능 문제가 있습니다. 따라서 실제로 화면에 3 개의 다른 크기를 동시에 그리려는 경우 성능 향상을 위해 3 개의 다른 vector_drawable.xml을 사용하는 것이 좋습니다.

기술적 세부 사항은 기본적으로 복잡한 경로 렌더링을 캐시하기 위해 후크 아래에 비트 맵을 사용하여 비트 맵 드로어 블을 다시 그리는 것과 동등한 수준으로 최상의 다시 그리기 성능을 얻을 수 있다는 것입니다.


27
좋아요 Google, 크기 만 다른 동일한 뷰포트와 경로 를 사용 하여 동일한 드로어 블을 복사하여 붙여 넣어야한다는 것은 정말 끔찍 합니다.
Miha_x64

이것은 내 로고가 픽셀 화 된 장치에서 수정되었지만 이전에 모든 것이 정상이었던 다른 장치에서는 이제 잘못된 종횡비입니다. 나는 이것이 왜 문제인지 이해하지 못한다. 그것은 벡터 다! 픽셀이 아닙니다! : P
tplive

@Harish Gyanani, android : scaleType = "fitXY"는 문제를 해결하지만 사각형이 아닌 동적 아이콘은 어떻습니까?
Manuela

28

1) 벡터 드로어 블에 너비 / 높이 사양이있는 이유는 무엇입니까? 나는 이것들의 전체 요점은 그들이 정의에서 너비와 높이를 무의미하게 만드는 무손실로 확장 및 축소된다는 것이라고 생각했습니다.

빌드 시스템이 래스터 이미지를 생성해야하는 21 미만의 SDK 버전의 경우 너비 / 높이를 지정하지 않은 경우 기본 크기로 사용합니다.

2) TextView에서 24dp 드로어 블과 큰 화면 너비 이미지로 작동하는 단일 벡터 드로어 블을 사용할 수 있습니까?

21 미만의 SDK를 타겟팅해야하는 경우에도 이것이 가능하다고 생각하지 않습니다.

3) 너비 / 높이 속성을 효과적으로 사용하는 방법과 viewportWidth / Height의 차이점은 무엇입니까?

문서 : (실제로 다시 읽었으니별로 유용하지 않습니다 ...)

android:width

드로어 블의 기본 너비를 정의하는 데 사용됩니다. 이는 일반적으로 dp로 지정된 모든 차원 단위를 지원합니다.

android:height

드로어 블의 고유 높이를 정의하는 데 사용됩니다. 이는 일반적으로 dp로 지정된 모든 차원 단위를 지원합니다.

android:viewportWidth

뷰포트 공간의 너비를 정의하는 데 사용됩니다. 뷰포트는 기본적으로 경로가 그려지는 가상 캔버스입니다.

android:viewportHeight

뷰포트 공간의 높이를 정의하는 데 사용됩니다. 뷰포트는 기본적으로 경로가 그려지는 가상 캔버스입니다.

추가 문서 :

Android 4.4 (API 레벨 20) 이하는 벡터 드로어 블을 지원하지 않습니다. 최소 API 수준이 이러한 API 수준 중 하나로 설정된 경우 Vector Asset Studio는 이전 버전과의 호환성을 위해 벡터 드로어 블의 래스터 이미지를 생성하도록 Gradle에 지시합니다. DrawableJava 코드 또는 @drawableXML 코드에서 와 같이 벡터 자산을 참조 할 수 있습니다 . 앱이 실행되면 해당 벡터 또는 래스터 이미지가 API 수준에 따라 자동으로 표시됩니다.


편집 : 이상한 일이 벌어지고 있습니다. 에뮬레이터 SDK 버전 23의 결과는 다음과 같습니다 (Lollipop + 테스트 장치가 지금 죽었습니다 ...).

6.x에서 좋은 종소리

에뮬레이터 SDK 버전 21에서 :

5.x의 크 래피 벨


1
고마워요 Cory, 나는 그 문서를 보았고 그다지 유용하지 않다는 것을 알았습니다. 내 장치는 Lollipop (v22)이지만 높이 / 무게가 ImageView에 정확히 지정되었는지 여부에 관계없이 벡터 드로어 블에 지정된 24dp 이상으로 그래픽 크기를 잘 조정할 수 없습니다. 대상 및 컴파일 수준 23 및 최소 수준 21로 매니페스트를 테스트했지만 드로어 블 자체의 너비 / 높이를 변경하지 않고는 벡터 드로어 블을 부드럽게 업 스케일하지 않습니다. 높이 / 너비 만 다른 드로어 블을 여러 개 만들고 싶지는 않습니다!
Chris Knight

1
확인에 감사 드리며 도움을 주셔서 감사합니다. 시연했듯이 예상대로 작동해야합니다. 정확한 코드를 사용하면 원래와 동일한 결과가 생성됩니다. 실망!
Chris Knight

1
업데이트 : API 22를 사용하여 에뮬레이터에 대해 내 코드를 실행했는데 여전히 동일한 결과를 얻습니다. API 23을 사용하여 에뮬레이터에 대해 내 코드를 실행하면 작동합니다. 업 스케일링은 API 23+ 기기에서만 작동하는 것 같습니다. 대상 SDK 버전 변경을 시도했지만 차이가 없습니다.
Chris Knight

이 문제에 대한 해결책을 찾았습니까?
dazza5000

@corycharlton이 제거 괜찮 width height viewport heightwidth에서 xml?
VINNUSAURUS

9

AppCompat 23.2는 Android 2.1 이상을 실행하는 모든 기기를위한 벡터 드로어 블을 도입했습니다. 벡터 드로어 블의 XML 파일에 지정된 너비 / 높이에 관계없이 이미지 크기가 올바르게 조정됩니다. 안타깝게도이 구현은 API 레벨 21 이상에서 사용되지 않습니다 (기본 구현에 유리함).

좋은 소식은 AppCompat가 API 레벨 21과 22에서 구현을 사용하도록 강제 할 수 있다는 것입니다. 나쁜 소식은 리플렉션을 사용하여이를 수행해야한다는 것입니다.

먼저 AppCompat의 최신 버전을 사용하고 있는지, 새로운 벡터 구현을 활성화했는지 확인하십시오.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.2.0'
}

그런 다음 useCompatVectorIfNeeded();애플리케이션의 onCreate ()를 호출 합니다.

private void useCompatVectorIfNeeded() {
    int sdkInt = Build.VERSION.SDK_INT;
    if (sdkInt == 21 || sdkInt == 22) { //vector drawables scale correctly in API level 23
        try {
            AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
            Class<?> inflateDelegateClass = Class.forName("android.support.v7.widget.AppCompatDrawableManager$InflateDelegate");
            Class<?> vdcInflateDelegateClass = Class.forName("android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate");

            Constructor<?> constructor = vdcInflateDelegateClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object vdcInflateDelegate = constructor.newInstance();

            Class<?> args[] = {String.class, inflateDelegateClass};
            Method addDelegate = AppCompatDrawableManager.class.getDeclaredMethod("addDelegate", args);
            addDelegate.setAccessible(true);
            addDelegate.invoke(drawableManager, "vector", vdcInflateDelegate);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

마지막으로 ImageView의 이미지를 설정 하는 app:srcCompat대신 사용하고 있는지 확인하십시오 android:src.

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    app:srcCompat="@drawable/icon_bell"/>

이제 벡터 드로어 블의 크기가 올바르게 조정됩니다!


좋은 접근 방식이지만 AppCompat 25.4 (및 이전 버전)에서는 "동일한 라이브러리 그룹에서만 호출 할 수 있습니다"라는 lint 오류가 발생합니다. 내가 사용하는 빌드 도구는 여전히 빌드 할 수 있지만 런타임 결과가 있는지 확실하지 않습니다. 테스트하려고합니다.
androidguy

동일한 라이브러리 그룹에서만 호출 할 수 있습니다. 다음을 추가하여이 오류를 제거하십시오. lintOptions {disable 'RestrictedApi'}
Usama Saeed US

6

1) 벡터 드로어 블에 너비 / 높이 사양이있는 이유는 무엇입니까? 나는 이것들의 전체 요점은 그들이 정의에서 너비와 높이를 무의미하게 만드는 무손실로 확장 및 축소된다는 것이라고 생각했습니다.

레이아웃보기에서 정의하지 않은 경우 벡터의 기본 크기입니다. (즉, 이미지 뷰의 높이와 너비에 랩 콘텐츠를 사용합니다)

2) TextView에서 24dp 드로어 블과 큰 화면 너비 이미지로 작동하는 단일 벡터 드로어 블을 사용할 수 있습니까?

예, 가능하며 실행중인 장치가 롤리팝 이상을 사용하는 한 크기 조정에 문제가 없었습니다. 이전 API에서 벡터는 앱을 빌드 할 때 다양한 화면 크기에 대해 png로 변환됩니다.

3) 너비 / 높이 속성을 효과적으로 사용하는 방법과 viewportWidth / Height의 차이점은 무엇입니까?

이것은 벡터 주변의 공간이 사용되는 방식에 영향을 미칩니다. 즉, 뷰포트 내부에서 벡터의 "중력"을 변경하고, 벡터에 기본 여백을 지정하고, 벡터의 특정 부분을 뷰포트에서 제외하는 등의 작업을 수행하는 데 사용할 수 있습니다. 일반적으로 동일한 값으로 설정합니다. 크기.


감사합니다 Emiura. 동일한 드로어 블을 사용하여 여러 렌더링 된 크기를 달성 한 방법에 관심이 있습니다. 테스트 목적으로 24dp 드로어 블을 사용하여 ImageView를 지정된 너비와 높이 400dp로 변경하고 Lollipop 장치 (v22)에서 실행했지만 벡터 이미지가 아닌 래스터 된 업 스케일 된 이미지처럼 여전히 제대로 렌더링되지 않습니다. 또한 내 매니페스트를 대상으로 변경하고 v23 및 최소 버전 21에 대해 컴파일합니다. 차이가 없습니다.
크리스 나이트

이 경우 벡터 드로어 블에서 가장 큰 크기를 사용한 다음 텍스트보기에서 24dp 크기를 지정하기 만하면됩니다.
emirua

벡터 드로어 블의 크기와 Lollipop의 레이아웃 크기 사이에 매우 큰 차이로 확대 할 때 이미지가 흐릿 해집니다. 그러나 화면 크기가 다른 파일을 여러 개 갖는 것보다 가장 큰 크기를 설정하는 것이 훨씬 더 깔끔합니다.
emirua

4

벡터 이미지의 크기를 변경하여 문제를 해결합니다. 처음부터 다음과 같은 리소스였습니다.

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="300"
    android:viewportWidth="300">

그리고 다음과 같이 150dp (이 벡터 리소스가있는 레이아웃의 ImageView 크기)로 변경했습니다.

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="150dp"
    android:height="150dp"
    android:viewportHeight="300"
    android:viewportWidth="300">

그것은 나를 위해 일하고 있습니다.


감사합니다. 이것은 내 태블릿에서 픽셀로 표시된 문제를 해결하기에 충분합니다.
user2342558 dec.

3

나는 이러한 방법을 시도해야하지만 불행히도 그들 중 어느 것도 작동하지 않았습니다. 나는 시도 fitXY하고 ImageView, 나는 그것을 시도 app:srcCompat하지만 그것을 사용할 수 없습니다. 하지만 트릭 방법을 찾았습니다.

로 드로어 블을 설정 background하여의 ImageView.

그러나 이러한 방식의 요점은 뷰 치수입니다. ImageView치수가 잘못된 경우 드로어 블이 스트레치됩니다. 롤리팝 이전 버전 또는 일부보기 사용에서 제어해야합니다 PercentRelativeLayout.

도움이 되었기를 바랍니다.


2

먼저 : svg를 드로 블로 가져 오기 : (( https://www.learn2crack.com/2016/02/android-studio-svg.html ))

1- 드로어 블 폴더를 마우스 오른쪽 버튼으로 클릭하고 새로 만들기-> 벡터 자산을 선택합니다.

여기에 이미지 설명 입력

2- Vector Asset Studio는 내장 머티리얼 아이콘이나 자체 로컬 svg 파일을 선택할 수있는 옵션을 제공합니다. 필요한 경우 기본 크기를 재정의 할 수 있습니다.

여기에 이미지 설명 입력

둘째 : Android API 7+에서 지원을 원하면 Android 지원 라이브러리를 사용해야합니다 (( https://stackoverflow.com/a/44713221/1140304 )).

1- 추가

vectorDrawables.useSupportLibrary = true

build.gradle 파일에.

2-imageView가있는 레이아웃에서 네임 스페이스 사용 :

xmlns:app="http://schemas.android.com/apk/res-auto"

세 번째 : android : scaleType = "fitXY"로 imageView를 설정하고 app : srcCompat 사용

 <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        app:srcCompat="@drawable/ic_menu" />

넷째 : 자바 코드에서 svg를 설정하려면 oncreate 방법에 아래 줄을 추가해야합니다.

 @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

솔루션이 API 21 이상에서 작동합니까? 위의 user3210008은 구현이 API 21 이상에서 사용되지 않는다고 언급합니다.
AJW

2

나에게 벡터가 png로 변환되는 이유는 android:fillType="evenodd"벡터 드로어 블의 속성 이었습니다 . 드로어 블에서이 속성의 모든 항목을 제거 했을 때 ( nonzero벡터에 적용된 기본 채우기 유형이 있음) 다음에 앱을 빌드 할 때 모든 것이 정상이었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.