Bài 24: Android Drawables - Lập trình Android cơ bản

Đăng bởi: Admin | Lượt xem: 2507 | Chuyên mục: Android


1. Giới thiệu

Trong Android, drawable được sử dụng khá nhiều ví dụ như background của view, src của ImageView, state (press, normal..) của view và nhiều chức năng các nữa. Nhưng thực sự khi mới bắt đầu không phải ai cũng hiểu được drawable là cái gì. Nhận thấy điều đó hôm nay tôi viết một bài từ cơ bản đến nâng cao về kiến thức drawable trong Android.

1.1 Khái niệm drawable

Drawable là khái niệm chung về graphics để chỉ những gì mà bạn có thể vẽ. Đơn giản là hình ảnh (Drawable hình ảnh trong android gọi là BitmapDrawable).
Drawable định nghĩa shape, color, gradient, border… mà bạn có thể sử dụng nó apply vào view trong Activity.

1.2 Các loại drawable trong Android

Trong Android có khá nhiều loại drawable. Sử dụng nhiều nhất là BitmapDrawable (sử dụng để set src cho ImageView). Và dưới đây là một số drawable trong Android.
  1. BimapDrawable
  2. ColorDrawable
  3. GradientDrawable
  4. ShapeDrawable
  5. RippleDrawable (Android 5.0)
  6. VectorDrawable
  7. AnimatedDrawable (Android 5.0)
  8. StateListDrawable
  9. 9 Paths Drawables
Ngoài những Drawable trên thì bạn cũng có thể tạo Drawable khác kế thừa từ các Drawable trên (Lớp cha của tất cả drawable là lớp Drawable).
Dưới đây chúng ta sẽ cùng đi qua 1 số Drawable được sử dụng phổ biến trong Android.

1.3 sử dụng Drawable cho View

Trong Android bạn có thể truy cập Drawable từ thư mục drawable của project như sau:
Trong file xml
Sử dụng @drawable/drawable_name
Trong java
Sử dụng R.drawable.drawable_name
Ví dụ sử dụng drawable để làm src cho ImageView trong xml
<ImageView
        android:src="@drawable/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Sử dụng trong java
ImageView imvAvatar = (ImageView)findViewById(R.id.imv_avatar);
imvAvatar.setImageResource(R.drawable.android);
Hoặc có thể tạo tạo Drawable Object trong Java và sử dụng các phương thức support set drawable như sau:
ColorDrawable colorDrawable = new ColorDrawable(Color.RED);
        imvAvatar.setImageDrawable(colorDrawable);
Drawable bitmapDrawable = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
           bitmapDrawable = getResources().getDrawable(R.drawable.android, getTheme());
        } else {
            bitmapDrawable = getResources().getDrawable(R.drawable.android);
        }
        if(bitmapDrawable != null){
            imvAvatar.setBackground(bitmapDrawable);
        }
Tuy nhiên method setBackground yêu cầu Android API 16. Nên mình khuyên các bạn sử dụng các phương thức setDrawable thông qua resource id ví dụ như phương thức setImageResouce (int resId) của ImageView.

2. Một số Drawable sử dụng phổ biến

2.1 BitmapDrawable

Thực chất Bitmap drawable là một bitmap nhưng drawable bạn có thể set nhiều thuộc tính trước khi vẽ hơn cho drawable như giá trị alpha, set kích thước width height trước khi vẽ.
Để sử dụng BitmapDrawable chúng ta dùng như sau:
Trong xml
Thêm hình ảnh vào thư mục drawable
Sau đó sử dụng @drawable/drawable_name để gán drawable cho view
Ví dụ
<TextView
        android:id="@+id/tv_title"
        android:drawableLeft="@drawable/facebook"
        android:text="facebook"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Trong java
//set bitmapdrawable left for textview
        BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
                BitmapFactory.decodeResource(getResources(), R.drawable.facebook));
        ((TextView)findViewById(R.id.tv_title)).setCompoundDrawablesWithIntrinsicBounds(bitmapDrawable, nu

2.2 ShapeDrawable

ShapeDrawable cho phép vẽ các hình học cơ bản trong android
Chuột phải vào thư mục drawable để tạo drawable resource
Nhập tên drawable để hoàn thành
Tôi tạo file có tên là circle_drawable với nội dung file như dưới đây.
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#2980b9"/>
</shape>
Và sử dụng trong xml
<View
    android:background="@drawable/circle_drawable"
    android:layout_width="300dp"
    android:layout_height="300dp"/>
Bây giờ tôi tạo một tiếp drawable có hình dạng như một row chat của messenger facebook như sau:
facebook_chat_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:topLeftRadius="20dp" android:bottomRightRadius="20dp" android:bottomLeftRadius="5dp" android:topRightRadius="5dp"/>
    <padding android:left="5dp" android:right="5dp" android:top="10dp" android:bottom="10dp"/>
    <solid android:color="#2980b9" />
</shape>
Set Drawable là background cho TextView
<TextView
        android:layout_margin="20dp"
        android:id="@+id/tv_message_chat"
        android:text="This is message"
        android:textColor="@android:color/white"
        android:background="@drawable/facebook_drawable_chat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Trong java bạn có thể làm như sau:
findViewById(R.id.tv_message_chat).setBackgroundResource(R.drawable.facebook_drawable_chat);
Kết quả
Thử sửa lại một số thông tin trong file facebook_chat_drawable.xml run và chạy xem lại kết quả
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="20dp"
        android:topLeftRadius="20dp"
        android:topRightRadius="5dp" />
    <padding
        android:bottom="10dp"
        android:left="5dp"
        android:right="5dp"
        android:top="10dp" />
    <gradient
        android:angle="90"
        android:centerColor="#3498db"
        android:endColor="#16a085"
        android:startColor="#1abc9c" />
</shape>
Đến đây chắc bạn đã cảm nhận được sức mạnh của drawable là như thế nào rồi nhỉ. Drawable bạn có thể làm cho view trở đẹp mắt hơn nhiều. Tiếp theo, chúng ta hãy cùng nhau tìm hiểu những drawable còn lại để khám phá những sức mạnh của drawable trong Android nào.

2.3 StateListDrawable

Đọc qua tên thì chúng ta cũng hình dung ra rằng Drawable này dùng để mô tả những state (normal, focus, press, disable…) của view. Đúng vậy, drawable này dùng để vẽ những state trên. Và thường xuyên sử dụng cho button, và các item trên ListView hay RecyclerView.
Hình ảnh dưới đây mô tả những state của Button.
Để tạo StateListDrawable cũng hoàn toàn tương tự như ShapeDrawable. Tôi tiến hành tạo drawable trong thư mục drawable có tên là button_selector.xml với nội dung như sau:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false" >
        <color android:color="#3498db"/>
    </item>
        <item android:state_pressed="true">
            <color android:color="#2980b9"/>
        </item>
</selector>
Sử dụng drawable cho button
<Button
    android:background="@drawable/button_selector"
    android:text="Save Change"
    android:textColor="@android:color/white"
    android:layout_centerInParent="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
Các bạn hãy làm thử và xem kết quả.
Bây tôi muốn làm một button như dưới đây:
Tôi sẽ có các file như sau:
button_state_normal.xml định nghĩa trạng trái normal của button
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="30dp" />
    <padding
        android:bottom="5dp"
        android:left="10dp"
        android:right="10dp"
        android:top="5dp" />
    <solid android:color="#1abc9c" />
</shape>
button_state_pressed.xml định nghĩa trạng thái khi button được nhấn.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="30dp" />
    <padding
        android:bottom="5dp"
        android:left="10dp"
        android:right="10dp"
        android:top="5dp" />
    <solid android:color="#16a085" />
</shape>
và file button_selector_save_change.xml định nghĩa selector của button gồm 2 state đó là normal và pressed.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/button_state_normal" android:state_pressed="false" />
    <item android:drawable="@drawable/button_state_pressed" android:state_pressed="true" />
</selector>
Button sử dụng selector
<Button
    android:text="Save Change"
    android:background="@drawable/selector_button_save_change"
    android:textColor="@android:color/white"
    android:layout_centerInParent="true"
    android:layout_width="200dp"
    android:layout_height="wrap_content" />
Sau đó các bạn thử chạy và run chương trình xem kết quả có sự khác biệt gì không.
Ngoài hai state normal và pressed trong android còn có nhiều state khác nữa.
Đa số các view trong Android đều có thể những state này. StateListDrawale khá nhiều nên tôi chỉ giới thiệu từng này. 

2.4 VectorDrawable

VectorDrawable được giới thiệu ở Android 5.0 (API 21). VectorDrawable có nhiều lợi thế đó là kích thước của file nhỏ (so với việc chúng ta copy 1 hình ảnh vào project). Tự động scale theo tỉ lệ màn hình trên từng thiết bị.
Trước tiên cần enable supportVecDrawable trong file build.gradle như sau:
apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 24
    buildToolsVersion "24.0.0"
 
    defaultConfig {
        applicationId "com.example.nguyennghia.vectordrawable"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
 
//        enable for using vector drawables
        vectorDrawables.useSupportLibrary = true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
 
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile 'com.android.support:design:24.0.0'
}
Tiếp theo để tạo VectorDrawable chúng ta right click vào thư mục drawable > New -> chọn Vector Asset
Hội thoại Vector Asset Studio hiện lên, nhấn choose để chọn icon mà bạn muốn xuất ra vector drawable. Sau đó nhấn ok để Android Studo tạo file drawable cho chúng ta.
File vector được generate có nội dung như sau:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FF000000"
        android:pathData="M22,5.72l-4.6,-3.86 -1.29,1.53 4.6,3.86L22,5.72zM7.88,3.39L6.6,1.86 2,5.71l1.29,1.53 4.59,-3.85zM12.5,8L11,8v6l4.75,2.85 0.75,-1.23 -4,-2.37L12.5,8zM12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
Để gán vector drawale cho View trong xml chúng ta sử dụng thuộc tính srcCompat.
<ImageView
        android:layout_alignParentRight="true"
        app:srcCompat="@drawable/ic_access_alarm_black_24dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Các bạn làm lại và chạy thử để xem kết quả.

2.5 CustomDrawable

Trên trên tôi đã giới thiệu những Drawable được giới thiệu trong Android SDK. Tiếp theo mình sẽ tạo drawable cho riêng mình để giúp các bạn hiểu sâu hơn Drawable trong Android.
Tôi tạo class ArcDrawable kế thừa từ Drawable như sau:
public class ArcDrawable extends Drawable {
    private Paint mPaint;
    private RectF mRect;
 
    public ArcDrawable(int color) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(10);
    }
 
    @Override
    public void draw(Canvas canvas) {
        if (mRect == null)
            mRect = new RectF();
 
        mRect.left = getBounds().left + mPaint.getStrokeWidth() / 2;
        mRect.top = getBounds().top + mPaint.getStrokeWidth() / 2;
        mRect.right = getBounds().right - mPaint.getStrokeWidth() / 2;
        mRect.bottom = getBounds().bottom - mPaint.getStrokeWidth() - 2;
        canvas.drawArc(mRect, 45, 270, false, mPaint);
    }
 
    @Override
    public void setAlpha(int alpha) {
        if (mPaint != null)
            mPaint.setAlpha(alpha);
    }
 
    @Override
    public void setColorFilter(ColorFilter cf) {
        mPaint.setColorFilter(cf);
    }
 
    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
 
}
Và sử dụng Drawable này như sau:
ImageView imvAvatar = (ImageView)findViewById(R.id.imv_avatar);
        ArcDrawable arcDrawable = new ArcDrawable(Color.parseColor("#16a085"));
        imvAvatar.setImageDrawable(arcDrawable);
Kết quả ta thấy như sau:
Và dưới đây là hình ảnh của drawale đã sử dụng trong bài viết từ đầu tới cuối
Tài liệu được tham khảo từ : http://eitguide.net/drawable-trong-android/
Bài tiếp theo: Room trong Android >>
vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!