12/08/2018, 14:42

Làm việc với SVG / vector drawables trong Android

Khi phát triển ứng dụng Android, hỗ trợ nhiều độ phân giải là đôi khi cơn ác mộng trong việc phát triển. Bao gồm nhiều hình ảnh cho độ phân giải khác nhau làm tăng dung lương dự án. Giải pháp là sử dụng Vector Graphics như hình ảnh SVG. Trong khi Android không hỗ trợ trực tiếp SVGs, với sự ra mắt ...

Khi phát triển ứng dụng Android, hỗ trợ nhiều độ phân giải là đôi khi cơn ác mộng trong việc phát triển. Bao gồm nhiều hình ảnh cho độ phân giải khác nhau làm tăng dung lương dự án. Giải pháp là sử dụng Vector Graphics như hình ảnh SVG. Trong khi Android không hỗ trợ trực tiếp SVGs, với sự ra mắt của Lollipop một class mới đã được giới thiệu tên là VectorDrawable (Scalable Vector Graphics), nó cho phép các nhà thiết kế, các nhà phát triển vẽ mà chỉ sử dụng mã

Đồ họa Vector là một cách để mô tả các yếu tố đồ họa sử dụng hình dạng hình học. Họ đặc biệt rất thích hợp với các yếu tố đồ họa tạo ra trong gói phần mềm như Adobe Illustrator hoặc Inkscape nơi hình dạng hình học đơn giản có thể được kết hợp trong các yếu tố phức tạp hơn nhiều.

Drawables vector dựa trên đồ họa vector, như trái ngược với đồ họa raster. Đồ họa vector là một cách để mô tả các yếu tố đồ họa sử dụng hình dạng hình học. Nó tương tự như một tập tin SVG. Trong Android Vector thể vẽ được tạo ra dưới dạng file XML. Bây giờ không cần thiết để tạo ra hình ảnh có kích thước khác nhau cho mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi. Chỉ cần một tập tin vector cho nhiều thiết bị kích thước màn hình. Ngoài ra đối với các phiên bản cũ của Android không hỗ trợ drawables vector, Vector Asset Studio có thể biến drawables vector của bạn thành các kích cỡ khác nhau cho mỗi bitmap mật độ màn hình khi chạy.

Dưới đây là thông tin chi tiết Vector Asset Studio.

Lưu ý: Đối với demo này sẽ sử dụng phiên bản gradle 2.2, suggession là sử dụng 2.0+.

Bước 1. Tạo một dự án mới trong Android Studio từ File ⇒ New Project và điền thông tin chi tiết của dự án. Bước 2. Mở build.gradle, thêm dòng code dưới đây trong defaultConfig.

vectorDrawables.useSupportLibrary = true

Khi hoàn thành file build.gradle giống như sau:

build.gradle
apply plugin: 'com.android.application'
 
android {
   compileSdkVersion 25
   buildToolsVersion "25.0.2"
   defaultConfig {
       applicationId "info.androidhive.vectordrawable"
       minSdkVersion 17
       targetSdkVersion 25
       versionCode 1
       versionName "1.0"
       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
       vectorDrawables.useSupportLibrary = true
   }
   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
       }
   }
}
 
dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
       exclude group: 'com.android.support', module: 'support-annotations'
   })
   compile 'com.android.support:appcompat-v7:25.1.0'
   testCompile 'junit:junit:4.12'
}

Nếu sử dụng phiên bản gradle dưới 2.0 thì làm như sau.

build.gradle
apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 24
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "info.androidhive.vectordrawable"
        minSdkVersion 17
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
        generatedDensities=[]
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    aaptOptions {
        additionalParameters "--no-version-vectors"
    }
}
 
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}

2.1. Tạo VectorDrawable từ Material Icons.

Chúng ta bắt đầu bằng cách tạo ra VectorDrawables từ Material Icons (Material Icons là biểu tượng chính thức thiết lập từ Google được thiết kế theo hướng dẫn theo material design, các biểu tượng này là mã nguồn mở và dễ dàng để sử dụng trong các trang web của bạn, dự án Android và iOS). Bước 3. Click chuột phải vào thư mục drawable

Bước 4. Chọn New ⇒ Vector Asset

Bước 5. Click chuột vào launcher icon để duyệt Material Icons

Bước 6. Chọn một icon và bấm vào ok

Bước 7. Xem lại tên của tập tin sau đó bấm vào next.

Bước 8. Bây giờ Vector Asset Studio sẽ hiển thị vị trí file được lưu, xem lại rồi bấm vào kết thúc.

Bước 9. Thư mục drawable bây giờ sẽ bao gồm một tập tin mới được tạo

ic_flight_takeoff.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:awidth="35dp"
        android:height="35dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FFe29069"
        android:pathData="M2.5,19h19v2h-19zM22.07,9.64c-0.21,-0.8 -1.04,-1.28 -1.84,-1.06L14.92,10l-6.9,-6.43 -1.93,0.51 4.14,7.17 -4.97,1.33 -1.97,-1.54 -1.45,0.39 1.82,3.16 0.77,1.33 1.6,-0.43 5.31,-1.42 4.35,-1.16L21,11.49c0.81,-0.23 1.28,-1.05 1.07,-1.85z"/>
</vector>

Chúng ta có thể thay đổi chiều rộng và chiều cao của các vector theo yêu cầu (theo mặc định nó vẫn là 24dp), một vector có thể bao gồm một hoặc nhiều đường dẫn. Một đường dẫn có thể có nhiều thuộc tính trong đó fillColor và pathData là quan trọng nhất. fillColor thuộc tính xác định màu sắc của đường dẫn, nó phải là một thuộc tính màu (mã băm trong #aarrggbb, hoặc cũng có thể trỏ đến một nguồn tài nguyên màu). pathData xác định hình dạng đường. Trong trường hợp này tôi đã sửa đổi chiều rộng vector, chiều cao và đường dẫn fillColor.

2.2. Tạo VectorDrawable từ SVG hoặc PSD.

Bây giờ chúng ta đã tạo vectorDrawable từ Material Icon, nếu chúng ta muốn có một icon riêng biệt? Chúng ta có thể tạo ra nó từ SVG hoặc PSD, dưới đây là những thủ tục, nhưng nó cũng có một số hạn chế, bạn có thể xem ở đây - https://developer.android.com/studio/write/vector-asset-studio.html#PSD ( mặc dù những hạn chế được liệt kê ở đây cho PSD, nócũng áp dụng cho SVG).

Bước 10. Click chuột phải vào drawable

Bước 11. Chọn New ⇒ Vector Asset

Bước 12. Click vào radio button “Local File (SVG, PSD)”

Bước 13. Click vào trình duyệt icon và điều hướng đến SVG của bạn hoặc tập tin PSD để chọn nó

Bước 14. Sau đó lựa chọn file

Bước 15. Xác minh hình ảnh xem trước và nhấn Next ⇒ Finish.

Dưới đây là mã tập tin được tạo từ svg

ic_light_bulb.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:awidth="100dp"
    android:height="100dp"
    android:viewportHeight="512.0"
    android:viewportWidth="512.0">
    <path
        android:fillColor="#273B7A"
        android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0" />
    <path
        android:fillColor="#121149"
        android:pathData="M506.4,309.5L300.1,103.3l-62.2,113.4l2.3,44.8l82.5,82.5l-3.4,3.4l-35.8,-35.8l-45.6,2.9h-64.7l-66.7,105.5l83.6,83.6C211.2,509 233.2,512 256,512C379,512 481.8,425.2 506.4,309.5z" />
    <path
        android:fillColor="#FFEDB5"
        android:pathData="M401.6,290.3c-3.3,-4.6 -9.3,-6.4 -14.6,-4.4c-0.1,0 -0.2,0.1 -0.2,0.1l-89.6,29.8c0,0.7 0,1.4 -0,2.2c-0.7,11.4 -9.6,20.6 -21,21.8l-54,5.6c-3.4,0.4 -6.5,-2.1 -6.8,-5.5c-0.4,-3.4 2.1,-6.6 5.5,-6.8l54,-5.6c5.3,-0.6 9.5,-4.9 9.8,-10.2c0.2,-2.9 -0.8,-5.8 -2.7,-8c-1.9,-2.2 -4.6,-3.5 -7.6,-3.7l-71.7,-4.7c-8.1,-0.5 -16,1.3 -23.1,5.1L85,358l25.6,51.6l23.8,-20.7c10.1,-8.8 23.5,-12.6 36.7,-10.4l79.4,13.2c14.6,1.9 29.1,-1.7 41.1,-10.2l108.1,-74.5C404.5,302.8 405.4,295.5 401.6,290.3z" />
    <path
        android:fillColor="#FEE187"
        android:pathData="M274.9,327.4c5.3,-0.6 9.5,-4.9 9.8,-10.2c0.2,-2.9 -0.8,-5.8 -2.7,-8c-1.9,-2.2 -4.6,-3.5 -7.6,-3.7l-15.9,-1v24.7L274.9,327.4z" />
    <path
        android:fillColor="#FEE187"
        android:pathData="M401.6,290.3c-3.3,-4.6 -9.3,-6.4 -14.6,-4.4c-0.1,0 -0.2,0.1 -0.2,0.1l-89.6,29.8c0,0.7 0,1.4 -0,2.2c-0.7,11.4 -9.6,20.6 -21,21.8l-17.7,1.8v50.6c11.8,-0.1 23.3,-3.8 33.1,-10.7l108.1,-74.5C404.5,302.8 405.4,295.5 401.6,290.3z" />
    <path
        android:fillColor="#FFC61B"
        android:pathData="M317.4,146c0,-34.7 -28.9,-62.8 -63.9,-61.4c-31.4,1.2 -57.1,26.5 -58.9,57.9c-1.2,21.6 8.7,40.9 24.6,52.7c10.1,7.6 16.3,19.2 16.3,31.9v21.3c0,11.3 9.2,20.5 20.5,20.5l0,0c11.3,0 20.5,-9.2 20.5,-20.5V227.4c0,-12.8 6.2,-24.6 16.5,-32.3C307.8,183.9 317.4,166 317.4,146z" />
    <path
        android:fillColor="#EAA22F"
        android:pathData="M255.4,84.6v184.2c0.2,0 0.4,0 0.6,0c11.3,0 20.5,-9.2 20.5,-20.5V227.4c0,-12.8 6.2,-24.6 16.5,-32.3c14.9,-11.2 24.5,-29 24.5,-49.1C317.4,111.9 289.6,84.3 255.4,84.6z" />
    <path
        android:fillColor="#A6A8AA"
        android:pathData="M235.5,227.9v20.5c0,11.3 9.2,20.5 20.5,20.5l0,0c11.3,0 20.5,-9.2 20.5,-20.5v-20.5L235.5,227.9z" />
    <path
        android:fillColor="#808183"
        android:pathData="M255.4,227.9v40.9c0.2,0 0.4,0 0.6,0c11.3,0 20.5,-9.2 20.5,-20.5v-20.5L255.4,227.9z" />
    <path
        android:fillColor="#FF5419"
        android:pathData="M244.2,183.8c-1.1,0 -2.3,-0.3 -3.3,-1.1c-2.5,-1.8 -3,-5.3 -1.2,-7.8l17.1,-23.4H244.2c-2.1,0 -4,-1.2 -5,-3.1c-1,-1.9 -0.8,-4.1 0.5,-5.8l23.6,-32.3c1.8,-2.5 5.3,-3 7.8,-1.2c2.5,1.8 3,5.3 1.2,7.8L255.2,140.4h12.6c2.1,0 4,1.2 5,3.1c1,1.9 0.8,4.1 -0.5,5.8l-23.6,32.3C247.6,183 245.9,183.8 244.2,183.8z" />
    <path
        android:fillColor="#C92F00"
        android:pathData="M272.3,117c1.8,-2.5 1.3,-6 -1.2,-7.8c-2.5,-1.8 -6,-1.3 -7.8,1.2l-7.9,10.8v18.9L272.3,117z" />
    <path
        android:fillColor="#C92F00"
        android:pathData="M267.8,140.4h-12.4v11.2h1.4l-1.4,1.9v18.9l16.9,-23.1c1.2,-1.7 1.4,-3.9 0.5,-5.8C271.8,141.6 269.9,140.4 267.8,140.4z" />
    <path
        android:fillColor="#D35933"
        android:pathData="M66.1,355.1l32.5,-22.2l40.5,64.7l-32.5,22.2z" />
    <path
        android:fillColor="#B54324"
        android:pathData="M139.1,397.6l-20.5,-32.8l-32.4,22.5l20.4,32.6z" />
</vector>

Bước 16. Mở file layout activity_main.xml và thêm đoạn mã xml dưới đây. Layout này có chứa chương trình làm thế nào để sử dụng VectorDrawable cùng với ImageView và các View khác như ở dưới.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="info.androidhive.vectordrawable.MainActivity">
 
    <ImageView android:id="@+id/ic_logo"
        android:layout_awidth="150dp"
        android:layout_height="150dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="30dp"
        android:layout_marginTop="30dp"
        app:srcCompat="@drawable/ic_light_bulb" />
 
    <TextView
        android:layout_awidth="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:gravity="center_horizontal"
        android:text="Tap on icon to change tint color" />
 
    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/ic_android"
        android:layout_awidth="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="30dp" />
 
    <android.support.v7.widget.AppCompatTextView
        android:layout_awidth="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="20dp"
        android:drawableLeft="@drawable/ic_flight_takeoff"
        android:gravity="center_horizontal"
        android:text="TextView with Vector Drawable" />
 
    <TextView
        android:layout_awidth="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Radio button with vector drawable icons" />
 
    <RadioGroup
        android:layout_awidth="match_parent"
        android:layout_height="wrap_content"
        android:showDividers="middle"
        android:orientation="horizontal"
        android:gravity="center">
 
        <android.support.v7.widget.AppCompatRadioButton
            android:id="@+id/radioBtn"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/radio_selector"
            android:button="@android:color/transparent" />
 
        <android.support.v7.widget.AppCompatRadioButton
            android:id="@+id/radioBtn2"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/radio_selector"
            android:button="@android:color/transparent" />
 
        <android.support.v7.widget.AppCompatRadioButton
            android:id="@+id/radioBtn3"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/radio_selector"
            android:button="@android:color/transparent" />
 
        <android.support.v7.widget.AppCompatRadioButton
            android:id="@+id/radioBtn4"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/radio_selector"
            android:button="@android:color/transparent" />
 
        <android.support.v7.widget.AppCompatRadioButton
            android:id="@+id/radioBtn5"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/radio_selector"
            android:button="@android:color/transparent" />
 
    </RadioGroup>
 
 
</LinearLayout>

Layout bên dưới được tạo như màn hình ở dưới

3.1. Sử dụng VectorDrawable cùng với ImageView từ xml

Chúng ta hãy bắt đầu với một ImageView đơn giản, bằng cách gán các VectorDrawable đến ImageView thông qua bố trí xml.

<ImageView
   android:layout_awidth="wrap_content"
   android:layout_height="wrap_content"
   app:srcCompat="@drawable/ic_light_bulb"/>

Chúng ta sử dụng ứng dụng: srcCompat thay vì android: src, để các thư viện hỗ trợ có thể làm phần còn lại để hiển thị các hình ảnh liền mạch trên tất cả các phiên bản của Android. (Các thư viện hỗ trợ chuyển đổi VectorDrawables đồ họa raster tự động trên các phiên bản Android dưới 5.0 - API 21, chi tiết ở đây).

3.2. Sử dụng VectorDrawable cùng với ImageView từ Java

Bây giờ chúng ta hãy làm điều tương tự với mã Java, nghĩa là gán VectorDrawable để ImageView qua mã code Java.

Bước 17. Thêm một Vector Drawabler khác(tên nó ic_android.xml) với các bước đề cập đến trong phần 2.1 hoặc 2.2, bạn cũng có thể tạo một tập tin với tên đó và dán mã dưới đây.

ic_android.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:awidth="50dp"
    android:height="50dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
    <path
        android:fillColor="@color/colorPrimaryDark"
        android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z" />
</vector>

Bước 18. Mở file MainActivity.java và paste đoạn mã dưới đây

MainActivity.java
package info.androidhive.vectordrawable;
 
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.AppCompatImageView;
import android.view.View;
 
import java.util.Random;
 
public class MainActivity extends AppCompatActivity {
 
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        final AppCompatImageView icAndroid = (AppCompatImageView) findViewById(R.id.ic_android);
        icAndroid.setImageResource(R.drawable.ic_android);
 
        icAndroid.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Random rnd = new Random();
                int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
                icAndroid.setColorFilter(color);
            }
        });
    }
}

Bước 19. Để sử dụng VectorDrawable từ java hoặc sử dụng xml

static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

Bước 20. Bất cứ khi nào bạn sử dụng VectorDrawable từ java hoặc sử dụng xml cũng nhớ để sử dụng AppCompatView thay vì xem bình thường, ở đây tôi đã sử dụng AppCompatImageView, vui lòng tham khảo layout, đã đc tạo ra trước.

Bước 21. Bây giờ giao cho VectorDrawable như src hoặc background như bạn làm nó bình thường, AppCompat sẽ quan tâm phần còn lại.

Bước 22. Chúng ta thực hiện OnClickListener trên ImageView để thiết lập bộ lọc màu sắc ngẫu nhiên vào nó, khi nhấp chuột.

3.3. Sử dụng VectorDrawable như là Drawable cùng với TextView

<android.support.v7.widget.AppCompatTextView
        android:layout_awidth="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="20dp"
        android:drawableLeft="@drawable/ic_flight_takeoff"
        android:gravity="center_horizontal"
        android:text="TextView with Vector Drawable" />

3.4. Sử dụng VectorDrawable để customise RadioButton

radio_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@drawable/ic_star"
        android:state_checked="true"
        android:state_pressed="true" />
    <item
        android:drawable="@drawable/ic_star"
        android:state_pressed="true" />
    <item
        android:drawable="@drawable/ic_star"
        android:state_checked="true" />
    <item
        android:drawable="@drawable/ic_star_border" />
</selector>

Source

0