天天看點

Android中Drawable

**Lroid是一款基于Anddroid平台開發的app, 是一款旨在提高剛想要入行Android系統開發(但已經具備Java語言基礎)或者已經開始工作一段時間(但已經具備Java語言基礎)想要進一步提高自己能力的app。lroid是以當下流行的MVP為架構,網絡通信子產品采用retrofit 2.0。裡面還包括了RxJava,Dagger2等很熱門的應用架構。為了更加接近現實常用的app,而不是一味的講解Android開發知識點,本軟體整合了一些内容來填充架構。

https://item.taobao.com/item.htm?id=541493148052**

在Android中有這樣一個類它有點像Bitmap,但卻和Bitmap有着本質的差別,那就是——Drawable。我們先來看一下官方文檔對它的描述吧。

A Drawable is a general abstraction for “something that can be drawn.”

Most often you will deal with Drawable as the type of resource

retrieved for drawing things to the screen; the Drawable class

provides a generic API for dealing with an underlying visual resource

that may take a variety of forms. Unlike a {@link android.view.View},

a Drawable does not have any facility to receive events or otherwise

interact with the user.

大體意思就是,可以用來畫一些東東的東西。

好,讓我們看看今天主要學習它哪些地方吧:

  1. Drawable和Bitmap的差別以及兩者的互相轉換。
  2. Drawable的基本用法。
  3. Drawable的進階用法。

一、Drawable和Bitmap的差別以及兩者的互相轉換。

Bitmap大家應該都挺熟悉的,描述的是位圖,用于圖的處理。

我們先來看看Bitmap如何轉換成Drawable,這個轉換還是比較簡單的,Google給我們提供了一個很友善的類——BitmapDrawable。我們隻需将一個Bitmap封裝到BitmapDrawable就可以得到Drawable對象,具體代碼:

public Drawable bitmapToDrawable(Bitmap bitmap){
        Drawable drawable = new BitmapDrawable(getResources(),bitmap);
        return drawable;
    }
           

下面看看如何将一個Drawable對象轉換成Bitmap對象,這個有點複雜,具體代碼如下:

public Bitmap drawableToBitmap(Drawable drawable){
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(width,height,drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(,,width,height);
        drawable.draw(canvas);
        return bitmap;
    }
           

代碼其實還是挺好了解的,建立一個畫布,通過Drawable的draw()方法,把圖像資訊封裝到Bitmap中,就可以得到Bitmap對象。

然後就可以通過ImageView的setImageBitmap(Bitmap bitmap)方法和setImageDrawable(Drawable drawable)方法來展示圖檔。

好,明白了Drawable和Bitmap的關系,下面讓我來看看Drawable的基本用法。

二、Drawable的基本用法。

先來看一張圖:

Android中Drawable

是不是有很多我們經常通過XML用到的标簽。是的,每一個标簽都對應了一個Drawable類,以我們最常用的Shape來說,通過XML我們會這樣書寫:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:bottomLeftRadius="8dp"
        android:bottomRightRadius="8dp"
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp" />
    <stroke
        android:width="1dp"
        android:color="#f00" />

    <solid android:color="#f00"/>
</shape>
           

效果如下:

Android中Drawable

好,我們通過代碼來實作上述效果:

注:标簽Shape對于的Java類不是ShapeDrawable,而是GradientDrawable類,千萬不要搞錯了

GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setCornerRadius(f);
        gradientDrawable.setColor(Color.RED);
        gradientDrawable.setStroke(,Color.RED);
           

效果和上面是一樣的,是不是覺得用代碼控制更簡單呢,短短幾行代碼,就可以實作相同的效果。

好,其他的Drawable類型,大家可以自己親自動手嘗試用代碼如何現實XML現實的效果,我就不一一在這介紹了。

下面我們來看一個比較綜合的效果,也是開發中一個常見的效果,在iOS比較常見,效果圖如下:

Android中Drawable

仿照QQ首頁頂部欄。

先來說一下我們的實作思路,方案還是有很多種的:

1,RadioGroup+RadioButton的方式

2,普通布局(LinearLayout或者RelativeLayout)+Button的方式

在這裡我們用第一方案,原因是第二中方法我們得自己判斷互斥邏輯,比較麻煩,通過第一中方案,就可以直接使用系統已經實作好的邏輯。我們隻需要關心的就是如何改變背景而已。

好,具體布局如下:

<RadioGroup
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:padding="10dp"
        android:background="#990000ff"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/id_left_radio"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@null"
            android:background="@drawable/left_radio_bg"
            android:textColor="#f00"
            android:padding="8dp"
            android:text="消息"/>

        <RadioButton
            android:id="@+id/id_right_radio"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@null"
            android:background="@drawable/right_radio_bg"
            android:textColor="#f00"
            android:padding="8dp"
            android:text="語音"/>

    </RadioGroup>
           

左邊RadioButton的背景實作如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_checked="true" android:drawable="@drawable/left_checked_bg"></item>

    <item android:state_checked="false" android:drawable="@drawable/left_unchecked_bg"></item>

</selector>
           

checked狀态背景:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <corners android:topLeftRadius="5dp" android:bottomLeftRadius="5dp"></corners>

    <solid android:color="#fff"></solid>

    <stroke android:width="1dp" android:color="#fff"></stroke>

</shape>
           

unchecked狀态背景如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:topLeftRadius="5dp" android:bottomLeftRadius="5dp"></corners>

    <solid android:color="@android:color/transparent"></solid>

    <stroke android:width="1dp" android:color="#fff"></stroke>
</shape>
           

右邊的就不具體把代碼貼出來了,就是left換成right而已。

這樣我們就實作了上圖的效果,效果還是挺贊的。是不是很簡單呢,嘿嘿,我們來看看用代碼如何實作這樣的效果。

還是左邊效果:

StateListDrawable stateListDrawable = new StateListDrawable();
        GradientDrawable checkedDrawable = new GradientDrawable();
        checkedDrawable.setColor(Color.WHITE);
        checkedDrawable.setStroke(,Color.WHITE);
        checkedDrawable.setCornerRadii(new float[]{
                //1、2表示左上角,3、4表示右上角,5、6表示右下角,7、8表示左下角
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                
        });
        stateListDrawable.addState(new int[]{android.R.attr.state_checked},checkedDrawable);
        GradientDrawable unCheckedDrawable = new GradientDrawable();
        unCheckedDrawable.setColor(Color.TRANSPARENT);
        unCheckedDrawable.setStroke(,Color.WHITE);
        unCheckedDrawable.setCornerRadii(new float[]{
                //1、2表示左上角,3、4表示右上角,5、6表示右下角,7、8表示左下角
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                
        });
        stateListDrawable.addState(new int[]{ - android.R.attr.state_checked },unCheckedDrawable);
           

這樣我們也就實作了XML實作的效果。需要注意幾點:

1,setCornerRadii()方法中各個參數代表的含義。代碼中已經标明。

2,checked狀态和unchecked狀态如何用代碼實作。

至此,我們這個小例子就通過兩種不同的方式實作了,在實際開發中,你可以根據個人喜好自由選擇,各有利弊,我喜好代碼~

下面我們再來看一個小例子,也是開發中比較常用的,就是數量訓示器,效果如下:

Android中Drawable

一般我們看着這樣的效果都會找美工要一個背景圖,或者自己自定義一個View來實作這樣的效果,下面我們就通過Drawable來看看如何實作這樣的效果,同樣,我們先來看一下通過XML如何實作具體代碼如下:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#f00" />
    <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="1dp" />
    <solid android:color="#f00" />
    <stroke
        android:width="1dp"
        android:color="@android:color/white" />
    <size
        android:width="15dp"
        android:height="15dp" />

</shape>
           

需要注意幾點:

1、android:shape=”oval”屬性值,預設為rectangle。

2、size标簽

其他的都是平常用的,沒什麼好說的,再來看一下通過代碼如何實作:

GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setShape(GradientDrawable.OVAL);
        gradientDrawable.setStroke(,Color.WHITE);
        gradientDrawable.setColor(Color.RED);
        gradientDrawable.setSize(,);
           

效果和XML一樣。

三、 Drawable的進階用法。

接觸過Android開發的人,都知道我們可以自定義一個View來實作一些特效,那麼我們可不可以自定義一個Drawable呢,答案當然是可以的,下面我們來看看如何自定義一個Drawable。還是以執行個體為主我們來實作一個圓形圖檔,要想實作圓形圖檔方法有幾種一般都是自定義ImageView重寫onDraw,其實用Drawable也可以的。先看效果圖:

Android中Drawable

代碼:

public class CircleDrawable extends Drawable {

    private Paint mPaint;
    private int mRadius;

    public CircleDrawable(Bitmap bitmap){
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(shader);
        mRadius = Math.min(bitmap.getWidth(),bitmap.getHeight()) /;
    }

    @Override
    public int getIntrinsicHeight() {
        return mRadius *  ;
    }

    @Override
    public int getIntrinsicWidth() {
        return mRadius * ;
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mPaint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.RGB_888;
    }
}
           

好,對于Drawable的進階用法就先介紹這一個,還有一些常用的,等以後再慢慢介紹。主要是基本用法,希望大家都能掌握了,今後用到了可以運用自如。