關(guān)于 Android Drawable Resource學習

關(guān)于 Android Drawable Resource學習


聲明本文參照官方文檔Drawable Resource

Drawable是所有圖像類的基類尉共,Android中定義了許多XXDrawable吕粹,這給開發(fā)帶來了極大的方便,許多效果可以直接使用drawable來處理,而無需自己定義view枫疆。

首先看一下Drawable這個類的層次關(guān)系,如下圖:

Drawable類繼承關(guān)系

主要學習常見的Drawable:

1.ShapeDrawable <shape />
2.BitmapDrawable <bitmap />
3.ColorDrawable <color />
4.ClipDrawable <clip />
5.InsetDrawable <inset />
6.ScaleDrawable <scale />
7.RoateDrawable <roate />
8.LevelListDrawable <level-list />
9.AnimaitonDrawable <animation-list />
10.StateListDrawable <selector />
11.LayerDrawable <layer-list />
12.TransitionDrawable <transition />
13.RippleDrawable <ripple />

<h2 id="6">ScaleDrawable</h2>


ScaleDrawable對應的標簽是 <scale/>,可以通過設(shè)置它的level將指定大小的drawable縮放

概述


這個標簽對應的語法(syntax)如下

<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    //xmlns:android 這個是定義XML命名空間的,是必須的曹抬,且值必須為這個

    android:drawable="@drawable/drawable_resource"
    //android:drawable 這個是來引用一個drawable資源的,是必須的

    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    //android:scaleGravity 關(guān)鍵字急鳄。指定縮放后的gravity的位置谤民。必須是上面可選值中的一個或多個(多個用‘|’分隔)。

    android:scaleHeight="percentage"
    // android:scaleHeight  縮放的高度疾宏,以百分比來表示drawable的縮放张足,比如50%

    android:scaleWidth="percentage"
    // android:scaleWidth  縮放的寬度,以百分比來表示drawable的縮放坎藐,比如50%
 />

上面這個標簽的語法中的每個屬性又是在哪定義的呢为牍?是不是也像我們自己定義一個控件屬性類似呢?

那么我們找到這些屬性定義:在R.styleable.ScaleDrawable 這個文件中(在Android源碼中位置/framework/base/core/res/res/values/attrs.xml )岩馍,很顯然也是一個自定義控件而已碉咆,只不過是系統(tǒng)定義好的,重復的就不在贅述了蛀恩,如下:

PS 你可以在線查看系統(tǒng)源碼

<declare-styleable name="ScaleDrawable">

    <!-- Scale width, expressed as a percentage of the drawable's bound. The value's
         format is XX%. For instance: 100%, 12.5%, etc.-->
    <attr name="scaleWidth" format="string" />

    <!-- Scale height, expressed as a percentage of the drawable's bound. The value's
         format is XX%. For instance: 100%, 12.5%, etc.-->

    <attr name="scaleHeight" format="string" />
    <!-- Specifies where the drawable is positioned after scaling. The default value is
         left. -->

    <attr name="scaleGravity">
        <!-- Push object to the top of its container, not changing its size. -->
        <flag name="top" value="0x30" />
        <!-- Push object to the bottom of its container, not changing its size. -->
        <flag name="bottom" value="0x50" />
        <!-- Push object to the left of its container, not changing its size. -->
        <flag name="left" value="0x03" />
        <!-- Push object to the right of its container, not changing its size. -->
        <flag name="right" value="0x05" />
        <!-- Place object in the vertical center of its container, not changing its size. -->
        <flag name="center_vertical" value="0x10" />
        <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
        <flag name="fill_vertical" value="0x70" />
        <!-- Place object in the horizontal center of its container, not changing its size. -->
        <flag name="center_horizontal" value="0x01" />
        <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
        <flag name="fill_horizontal" value="0x07" />
        <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
        <flag name="center" value="0x11" />
        <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
        <flag name="fill" value="0x77" />
        <!-- Additional option that can be set to have the top and/or bottom edges of
             the child clipped to its container's bounds.
             The clip will be based on the vertical gravity: a top gravity will clip the bottom
             edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
        <flag name="clip_vertical" value="0x80" />
        <!-- Additional option that can be set to have the left and/or right edges of
             the child clipped to its container's bounds.
             The clip will be based on the horizontal gravity: a left gravity will clip the right
             edge, a right gravity will clip the left edge, and neither will clip both edges. -->
        <flag name="clip_horizontal" value="0x08" />
        <!-- Push object to the beginning of its container, not changing its size. -->
        <flag name="start" value="0x00800003" />
        <!-- Push object to the end of its container, not changing its size. -->
        <flag name="end" value="0x00800005" />
    </attr>

    <!-- Reference to a drawable resource to draw with the specified scale. -->
    <attr name="drawable" />

    <!-- Use the drawable's intrinsic width and height as minimum size values.
         Useful if the target drawable is a 9-patch or otherwise should not be scaled
         down beyond a minimum size. -->
    <attr name="useIntrinsicSizeAsMinimum" format="boolean" />
    // 這個屬性類型是布爾類型疫铜,是否使用本身的大小作為最小值,默認是false
</declare-styleable>
下面重點分析一下ScaleDrawable是如何工作的
@Override
public void draw(Canvas canvas) {
    final Drawable d = getDrawable();
    if (d != null && d.getLevel() != 0) {
        d.draw(canvas);
    }
}

這個draw方法赦肋,只有l(wèi)evel不為0才會繪制drawable块攒。

當調(diào)用drawable.setLevel()的方法后,會回調(diào)到onLevelChange()

public final boolean setLevel(int level) {
    if (mLevel != level) {
        mLevel = level;
        return onLevelChange(level);
    }
    return false;
}

而在ScaleDrawable中重寫了這個方法佃乘,到里就一目了然了囱井。調(diào)用onBoundsChange方法后又去重繪了,這樣就可以更新Drawable大小了

@Override
protected boolean onLevelChange(int level) {
    super.onLevelChange(level);
    onBoundsChange(getBounds());
    invalidateSelf();
    return true;
}

那究竟android:scaleHeight="" android:scaleWidth=""和他自身level是如何影響drawable大小的呢趣避?

 @Override
protected void onBoundsChange(Rect bounds) {
    final Drawable d = getDrawable();
    final Rect r = mTmpRect;
    final boolean min = mState.mUseIntrinsicSizeAsMin;
    final int level = getLevel();

    int w = bounds.width();
    if (mState.mScaleWidth > 0) {
        final int iw = min ? d.getIntrinsicWidth() : 0;
        w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
    }

    int h = bounds.height();
    if (mState.mScaleHeight > 0) {
        final int ih = min ? d.getIntrinsicHeight() : 0;
        h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
    }

    final int layoutDirection = getLayoutDirection();
    Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);

    if (w > 0 && h > 0) {
        d.setBounds(r.left, r.top, r.right, r.bottom);
    }
}
從方法名就可以看出這是用來真正控制縮放效果的庞呕,如何控制的呢?

final int iw = min ? d.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
由于min這個屬性值通常為false(默認也是false),那么iw一般為零住练,可以簡化為
w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000);
所以如果level越大地啰,w(drawable)就越大,當level為10000的時候是沒有縮放效果的讲逛;
如果xml中的縮放比例越大亏吝,w(drawable)就越小。

例子


在drawble目錄下新建一個xml文件 scale_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/girl"
        android:scaleGravity="left"
    android:scaleHeight="40%"
    android:scaleWidth="40%"
 />
<!--70%表示將寬度縮小40% 即縮放后為原圖 60%大小-->

然后在布局文件中引用這個drawable資源

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    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="com.smart.myapplication.DrawableActivity">

    <ImageView
        android:id="@+id/image2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerInside"
        android:src="@drawable/girl" />

    <ImageView
        android:id="@+id/image1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/image2"
        android:layout_marginTop="50dp"
        android:scaleType="centerInside"
        android:src="@drawable/scale_drawable" />

</RelativeLayout>

此時還需要在代碼中設(shè)置ScaleDrawable的level才會有效果盏混,level默認是0蔚鸥,不顯示,將level設(shè)置為1即可许赃。

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawable);
    ImageView imageView=(ImageView)findViewById(R.id.image1);
    ScaleDrawable scaleDrawable=(ScaleDrawable)imageView.getDrawable();
    scaleDrawable.setLevel(1);  
 }

Demo效果圖
為了對比:第一張是原圖止喷,第二張是縮放后的效果圖

ScaleDrawable效果.png

<h2 id="6">BitmapDrawable </h2>


BitmapDrawable 對應的標簽是 <bitmap/>,特殊的是可以通過設(shè)置它的平鋪模式來變換不同的效果

概述


SYNTAX語法結(jié)構(gòu):

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@[package:]drawable/drawable_resource"
    android:antialias=["true" | "false"]
    // 是否開啟圖片抗鋸齒功能,一般開啟混聊,設(shè)置為true
    android:dither=["true" | "false"]
    //是否開啟抖動效果弹谁,一般開啟后可以讓圖形顯示質(zhì)量更好(不同分辨率的屏幕),設(shè)置為true
    android:filter=["true" | "false"]
    // 是否開啟過濾效果,當圖片被拉伸或壓縮句喜,開啟后會顯示更好的效果预愤,建議開啟
    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                      "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                      "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    android:mipMap=["true" | "false"]  
    //這個是圖片的一種處理技術(shù)
    android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />

重點解釋 android:tileMode
android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"]
關(guān)鍵字,這個屬性表示圖片平鋪模式咳胃,如果這個屬性enable鳖粟,那么gravity屬性會被忽略(ignore)∽景恚總共有四種屬性值:

  1. disabled 表示不用這個平鋪屬性,也是默認值
  2. repeat 表示圖片平鋪的效果
  3. mirror 表示鏡像投影的效果
  4. clamp 可以翻譯為緊緊抓住的意思泳秀,其效果是圖片四周的像素會擴展到周圍區(qū)域(緊緊靠緊标沪, 個人理解)

android:mipMap=["true" | "false"]
//這個是圖片的一種處理技術(shù),

效果圖:

disable模式(也是原素材圖).png

那么我們?nèi)绾螌⑦@個素材圖,填滿整個控件的背景呢嗜傅,而且還不變形金句,類似下面的效果


BitmapDrawable-repeat.png
BitmapDrawable-clamp.png
BitmapDrawable-mirror.png

如果上面這個mirror模式效果不夠明顯,那看一下使用Android logo的效果吧

BitmapDrawable-mirror2.png

以上效果實現(xiàn)非常簡單
在drawable目錄下新建一個bitmap_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:src="@mipmap/pic_bg_01_min" //引用一個圖片
    android:dither="true"
    android:filter="true"
    android:gravity="center"
    android:tileMode="clamp"> //分別修改這個模式,即可看到每一個mode的效果
</bitmap>  

在View中直接設(shè)置background引用這個bitmap_drawable.xml 即可

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/ android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    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="com.smart.myapplication.BitmapDrawableActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bitmap_drawable"
        android:scaleType="centerInside"/>
</RelativeLayout>
<!--注意要設(shè)置imageview的background屬性而不是src屬性-->

后記:通常會使用這個屬性來平鋪一個圖片作為背景吕嘀,可以有效防止失真
當然我們還可以直接用代碼來完成上面的效果
违寞,例如

 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_bg_01_min);
 BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
 drawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
 drawable.setDither(true);
 drawable.setAntiAlias(true);
 drawable.setFilterBitmap(true);
 ImageView view = (ImageView) findViewById(R.id.image);
 view.setBackgroundDrawable(drawable);

InsetDrawable


InsetDrawable在xml中對應的標簽是 <inset/>

官方這樣解釋InsetDrawable的應用場景:
This is used when a View needs a background that is smaller than the View's actual bounds.
當一個view所需要的背景圖比他自身的實際邊界要小的時候,通常用這個InsetDrawable偶房。

概述


SYNTAX語法結(jié)構(gòu):

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    //  必須的趁曼,命名空間,且值必須為這個棕洋,不多解釋
    android:drawable="@drawable/drawable_resource"
    // 必須的挡闰,指定引用的drawable資源
    android:insetTop="dimension"
    android:insetRight="dimension"
    android:insetBottom="dimension"
    android:insetLeft="dimension" />
    // 上面這四個屬性值類型是dimension,即表示dimension值或者引用那種@dimen
    // android:insetLeft表示的是drawable距離左邊的距離,同理其他幾個類似

說到這你可能還不造是什么效果呢摄悯?OK赞季,來看個實際問題吧

效果圖.png

這個效果是這樣的,ListView的點擊效果充滿整個寬度奢驯,而分割線卻距離兩邊都有一個距離申钩,顯然不能單純的使用默認divider設(shè)置一個分割線,這個時候該InsetDrawable該登場了瘪阁!

在drawable目錄下定義一個inset_listview_divider.xml文件

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetLeft="@dimen/theme_padding_17dp"
    android:insetRight="@dimen/theme_padding_17dp" >
    <shape android:shape="rectangle" >
        <solid android:color="@color/info_item_color" />
    </shape>
</inset>    

然后在listvew中引用這個drawable即可

     <ListView
        android:id="@+id/city_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="@android:color/transparent"
        android:dividerHeight="0.3dp"
        android:divider="@drawable/inset_listview_divider"
        android:scrollbars="none" />    

mark未完待續(xù)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撒遣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子罗洗,更是在濱河造成了極大的恐慌愉舔,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伙菜,死亡現(xiàn)場離奇詭異轩缤,居然都是意外死亡,警方通過查閱死者的電腦和手機贩绕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門火的,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淑倾,你說我怎么就攤上這事馏鹤。” “怎么了娇哆?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵湃累,是天一觀的道長。 經(jīng)常有香客問我碍讨,道長治力,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任勃黍,我火速辦了婚禮宵统,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘覆获。我一直安慰自己马澈,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布弄息。 她就那樣靜靜地躺著痊班,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疑枯。 梳的紋絲不亂的頭發(fā)上辩块,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音,去河邊找鬼废亭。 笑死国章,一個胖子當著我的面吹牛朋贬,可吹牛的內(nèi)容都是我干的泽腮。 我是一名探鬼主播烤芦,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼秋冰,長吁一口氣:“原來是場噩夢啊……” “哼牲剃!你這毒婦竟也來了糙麦?” 一聲冷哼從身側(cè)響起歇攻,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤驮樊,失蹤者是張志新(化名)和其女友劉穎粗恢,沒想到半個月后柑晒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡眷射,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年匙赞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妖碉。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡涌庭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出欧宜,到底是詐尸還是另有隱情坐榆,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布冗茸,位于F島的核電站席镀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏夏漱。R本人自食惡果不足惜愉昆,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望麻蹋。 院中可真熱鬧,春花似錦焊切、人聲如沸扮授。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刹勃。三九已至,卻和暖如春嚎尤,著一層夾襖步出監(jiān)牢的瞬間荔仁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乏梁,地道東北人次洼。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像遇骑,于是被迫代替她去往敵國和親卖毁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容