寫多了自定義View,可以來試一試自定義Drawable

在 Android 開發中,會大量使用到自定義View,于是在很多開發者心里形成了自定義View優先的原則,需要一個新的效果,沒問題,寫個自定義View。但是寫個自定義View還是一個比較麻煩的事,比如說需要復寫onMeasureonDraw,要考慮padding,考慮wrap_content等等。但是很多效果都沒必要自定義View,寫個Drawable就可以了。

Android 提供的 Drawable

Drawable,表示一個能夠在Canvas上繪制的抽象的概念。相比于View,它相當的輕量級,不用考慮measurelayout,需要考慮的僅僅是如何繪制,即draw函數。

在 Android 系統中,包含了幾種已經定義好的 Drawable,它們和它們對應的 XML 標簽如下所示:

Drawable類 對應的xml標簽 描述
BitmapDrawable bitmap 就是表示一張圖片
ShapeDrawable shape 通過顏色構建的圖形
LayerDrawable layer-list 表示層次化的Drawable集合
StateListDrawable selector Drawable集合,其中每個Drawable對應一個狀態
LevelListDrawable level-list Drawable集合,其中每個Drawable對應一個等級
TransitionDrawable transition 用于實現兩個Drawable直接按的淡入淡出效果
InsetDrawable inset 可以將其他Drawable內嵌到自己當中
ScaleDrawable scale 可將指定的Drawable縮放到一定比例
ClipDrawable clip 根據當前等級來裁剪另一個Drawable

以上是Android 系統中提供的一些Drawable,有些可能很少用,但是知道一些也是好的。另外需要說的就是關于Drawable的寬高。

Drawable作為一個能夠繪制到Canvas上的對象,是沒有寬高的概念的。這個可能不好理解,但是想一想這個問題就知道了:Drawable既然能在Canvas上繼續進行繪制,那么它也不會知道Canvas是多寬多高,不管Canvas是多大的,它都必須能夠保證正常的繪制,當作用于View的背景時,Drawable會被拉伸至View的同等大小。但是大家會注意到兩個函數:

int Drawable.getIntrinsicHeight()  //獲取其固有高度
int Drawable.getIntrinsicWidth()   //獲取其固有寬度

這兩個參數并不是每個Drawable都具有,對于大多數Drawable來說,它們都是返回-1的,但是對于BitmapDrawable,它的固有寬高就是圖片的寬高。這兩個值還會影響到View的測量,關于這一點請看后面例子。

自定義 Drawable

Drawable的最主要的使用場景一是作用于ImageView,二是作為View的背景。自定義的Drawable是無法在XML中使用的。自定義一個Drawable僅僅需要復寫幾個函數,可以說是相當的容易。下面的例子就是自定義一個圓角的Drawable,當它作用于View的背景時會繪制一個圓角的純色背景,而關于每個函數的意義和注意事項都寫在注釋里了。

public class RoundColorDrawable extends Drawable {

    private Paint paint;

    public RoundColorDrawable() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLUE);
    }

    public void setColor(int color) {
        paint.setColor(color);
    }

    /**
     * 重點函數,在該函數中需要處理該Drawable如何進行繪制,并使用Canvas的方法將需要繪制的東西
     * 繪制在畫布上。
     * @param canvas 該Drawable將要繪制到的畫布,一般情況下,這個{@link Canvas} 對象就是
     *               View在 onDraw 方法中的 畫布。
     */
    @Override
    public void draw(@NonNull Canvas canvas) {
        //這里僅僅繪制了一個于canvas尺寸大小相同的圓角矩形
        canvas.drawRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), 40, 40, paint);
    }

    @Override
    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        paint.setAlpha(alpha);
    }

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

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

    /**
     * 返回固有的高度,會影響到測量
     */
    @Override
    public int getIntrinsicHeight() {
        return 200;
    }

    /**
     * 返回固有寬度,會影響到測量
     */
    @Override
    public int getIntrinsicWidth() {
        return -1;
    }
}

需要注意的是,繼承Drawable必須復寫4個函數:drawsetAlphasetColorFiltergetOpacity。這4個函數的覆寫都是比較容易的。另外兩個返回固有寬高的函數:getIntrinsicHeightgetIntrinsicWidth,不強制覆寫,但是對它們的意義要了解,因為它們會設計到 View 的測量,其返回了固定值之后則View必須會撐大到能夠包裹住這個尺寸,例如這里的getIntrinsicHeight高度返回了200,那么將這個Drawable作為View的背景時,View的尺寸肯定要大于等于200。

下面就將這個Drawable引用到代碼中,布局比較簡單就不貼出來了,下面是代碼部分:

setContentView(R.layout.image_test);
imageView = (ImageView) findViewById(R.id.image_view);
textView = (TextView) findViewById(R.id.text_view);

RoundColorDrawable drawable = new RoundColorDrawable();
imageView.setImageDrawable(drawable);
textView.setBackground(drawable);

效果圖如下,上面是TextView,中間則是一個ImageView

Screenshot_1492439813.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,638評論 25 708
  • 一:自定義View繪制流程函數調用鏈 二.幾個重要的函數 1.構造函數 構造函數是View的入口,可以用于初始化一...
    請叫我財迷閱讀 1,370評論 0 3
  • 前言 如上圖所示,相信可愛的安卓程序猿們在開發中經常會遇到這種樣式的UI開發。其實上面這種布局很簡單,沒有難度,只...
    笑哥哥閱讀 3,873評論 0 4
  • 在這個城市里,身邊三三兩兩的朋友,一起吃飯,一起逛街,但是實際上感覺心里是很孤獨的,生活感覺每天都是一樣的,別人都...
    北國之北閱讀 258評論 0 1
  • (超級大劇透)一開始以為是黑幫動作片,然而里面并沒有什么激烈的讓人腎上腺激素飆升的場景,殺人也都是干凈利落,反而整...
    frankaka閱讀 277評論 0 0