Android學(xué)習(xí)筆記18 圖形圖像完全解析

本文主要對Android開發(fā)中圖形圖像部分的相關(guān)內(nèi)容作個簡單的學(xué)習(xí)總結(jié)。

一、概述
二、ImageView詳解
三、Bitmap詳解
四、Canvas詳解
五、SurfaceView簡介
六、總結(jié)

一、概述

在我們的應(yīng)用開發(fā)中,圖形圖像處理往往是不可避免要接觸的內(nèi)容。一個完整的App,文字、圖像、動畫等都是用戶交互的重要組成元素。本文主要從ImageView開始,對Android開發(fā)中與圖形圖像處理相關(guān)的內(nèi)容作個簡單的總結(jié)。

二、ImageView用法與解析

1、ImageView簡介

ImageView的用途相信大家都已經(jīng)十分的熟悉,應(yīng)用中圖標(biāo)或者圖片的展示一般都需要用到這個控件。SDK文檔中對它的介紹,大致翻譯是ImageView,圖像視圖,是用來展示一個任意的圖像的控件,例如圖標(biāo)。它可以從不同的來源載入圖像,控制圖像的大小,并提供多種展示選項,比如縮放比例或者著色器等。

2、ImageView用法

首先我們看下ImageView一個最簡單的使用。

<ImageView
     android:id="@+id/iv_scaletype_test"
     android:layout_width="200dp"
     android:layout_height="200dp"
     android:src="@drawable/img_test" />

當(dāng)在布局文件里指定ImageView的寬高以及src屬性后,一張圖片就可以展示在ImageView上了。如果是用Java代碼動態(tài)控制,那么src屬性可以用方法setImageResource來完成。

當(dāng)然,我們也可以配置很多其它屬性。常用的有scaleType,了解它之前我們來看兩張對比圖。

未設(shè)置scaleType的ImageView
scaleType設(shè)置為CENTER_CROP的ImageView

可以看到,scaleType的不同設(shè)置可以控制圖像在ImageView中的顯示樣式。

scaleType的取值共有8種,分別是:

  • MATRIX,意思是“矩陣”,即用矩陣來繪制,不縮放
  • FIT_XY,不按比例縮放圖片,把圖片塞滿整個ImageView。
  • FIT_START,置頂,圖片顯示在ImageView的左上角start的位置
  • FIT_CENTER,居中
  • FIT_END,置底,圖片顯示在ImageView的右下角end的位置
  • CENTER,按圖片的原來尺寸居中顯示,當(dāng)圖片長/寬超過ImageView的長/寬,則截取圖片的居中部分顯示
  • CENTER_CROP,按比例擴大圖片的size居中顯示,使得圖片長(寬)等于或大于ImageView的長(寬)
  • CENTER_INSIDE,圖片完整居中顯示,比例縮小或原來的size使得圖片長/寬等于或小于ImageView的長/寬

一圖勝千言,請看:

scaleType不同的設(shè)置.gif

在未設(shè)置scaleType時,系統(tǒng)默認保證圖片完整、居中顯示,并等比縮放,其效果跟android:scaleType=”fitCenter”的效果一致。

在代碼里控制圖片的縮放樣式是用方法setScaleType來設(shè)置的。可以看到,用好這個屬性,可以明顯地改善圖片在界面上的顯示效果。

在ImageView的使用過程中,還有個tint屬性可以設(shè)置。tint翻譯是著色,它可以用來改變ImageView中內(nèi)容的顏色,在代碼中對應(yīng)的設(shè)置方法是imageview.setColorFilter(Color),我們可以利用這個屬性來修改一些圖標(biāo)的顯示顏色。

三、Bitmap詳解

Bitmap,翻譯為位圖,它是一個final類,Android系統(tǒng)圖像處理中最重要的類之一。Bitmap可以獲取圖像文件信息,對圖像進行剪切、旋轉(zhuǎn)、縮放,壓縮等操作,并可以以指定格式保存圖像文件。在實際使用過程中,因為Bitmap很占內(nèi)存,所以需要注意進行壓縮,高效加載避免OOM。

Bitmap類比較特別,我們不能通過它的構(gòu)造方法來實例化,只能通過Bitmap的靜態(tài)方法或者借助BitmapFactory的靜態(tài)方法來實例化。類BitmapFactory,它可以讓我們從不同的來源,比如文件,流,字節(jié)數(shù)組等來源中創(chuàng)建Bitmap對象。下面是BitmapFactory的類結(jié)構(gòu)。可以看到,它提供了一系列從不同來源實例化Bitmap的方法。

BitmapFactory的類結(jié)構(gòu)

下面看個簡單的例子。

實例化Bitmap并顯示在ImageView上

上圖中,已經(jīng)用OkHttp網(wǎng)絡(luò)請求獲取到了字節(jié)數(shù)組,在Handler中處理消息時,先獲取到字節(jié)數(shù)組,然后利用BitmapFactory的decodeByteArray方法,實例化Bitmap,最后通過ImageView的setImageBitmap方法將Bitmap設(shè)置為ImageView的內(nèi)容。

Bitmap特別耗內(nèi)存,所以我們在使用中要十分注意優(yōu)化。常見的措施有,及時調(diào)用recycle()進行內(nèi)存回收,實例化Bitmap時進行圖片壓縮,以及采取圖片緩存等。

下面是在使用BitmapFactory的靜態(tài)方法實例化Bitmap時進行壓縮。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;

Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

可以看到上面的代碼實例化參數(shù)Options時設(shè)置inSampleSize為4,這樣實例化的Bitmap占用的內(nèi)存只為原來的1/16。

1.Bitmap的內(nèi)存占用

上面我們提到,在使用類BitmapFactory加載Bitmap時指定Options可以有效的優(yōu)化Bitmap的內(nèi)存占用,那么Bitmap的內(nèi)存占用具體怎么計算的呢?這里有個公式:

占用內(nèi)存 = 圖片寬 * 圖片高 * 單位像素占用的內(nèi)存

這里簡單說明一下,圖片的寬和高比較容易理解,單位像素的占用內(nèi)存一般是由圖片加載時的色彩模式?jīng)Q定的,android默認的色彩模式是ARGB_8888,一個像素占用的內(nèi)存是4個字節(jié)。

這里還需要注意的是,圖片的來源也會最終影響占用內(nèi)存。如果我們直接從網(wǎng)絡(luò)上獲取圖片,那么圖片的占用內(nèi)存就是上面的公式。但是如果是從drawable目錄下加載圖片,那么占用內(nèi)存會因為不同的drawable目錄而不同,因為Android系統(tǒng)在加載不同drawable目錄下的圖片到不用分辨率的機型上時會進行一定的縮放。

2.Bitmap的高效加載

BitmapFactory加載Bitmap時指定Options是一個比較好的習(xí)慣,那么Options的inSampleSize指定多少比較合適呢?其實最理想的情況是我們根據(jù)需要顯示的ImageView的大小計算出Options的inSampleSize。

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

3.Bitmap的緩存

項目中如果需要加載圖片,那么圖片緩存的設(shè)計非常重要。一般來說,圖片緩存會涉及到內(nèi)存緩存和磁盤緩存,當(dāng)需要加載圖片時,先看內(nèi)存中有沒有,沒有的話再看磁盤緩存中有沒有,最后再嘗試網(wǎng)絡(luò)請求獲取圖片。

內(nèi)存緩存和磁盤緩存目前比較常用的算法是LRU(Least Recently Used),即近期最少使用算法,內(nèi)存緩存我們可以借助LruCache這個類來完成,磁盤緩存可以用DiskLruCache,它們共同的原理是指定一個緩存的總大小,當(dāng)緩存滿時,優(yōu)先淘汰那些近期最少使用的緩存的對象。

四、Canvas解析

說到圖形圖像,那么肯定離不開要談Canvas這個類。當(dāng)我們想要繪制自己的圖形時,或者在自定義View中,一般都會用到它。Canvas,直譯為畫布,SDK文檔對它的介紹如下:

The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).

Canvas類包含很多draw的方法,要畫某樣?xùn)|西,一般需要4個基本元素:一是Bitmap,用來包含像素。二是Canvas,包含畫的方法。三是畫的參數(shù),比如寬高等屬性。四是Paint,畫筆,用來描述繪畫的顏色和樣式。

Canvas類中用來draw系列方法

同樣的,我們來看個簡單的例子。

public class MyDrawView extends View {

    private Paint mPaint;

    public MyDrawView(Context context) {
        super(context);

        mPaint = new Paint();
        mPaint.setColor(Color.RED);// 設(shè)置畫筆顏色為紅色
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPaint.setTextSize(50f);
        canvas.drawText("畫圓:", 100, 200, mPaint);// 畫文本

        canvas.drawCircle(300, 200, 80, mPaint);// 小圓
        mPaint.setAntiAlias(true);// 設(shè)置畫筆的鋸齒效果
        canvas.drawCircle(600, 200, 150, mPaint);// 大圓

        canvas.drawText("畫線:", 100, 600, mPaint);
        canvas.drawLine(600, 400, 1000, 400, mPaint);// 畫線
        canvas.drawLine(600, 400, 1000, 800, mPaint);// 斜線
    }
}

在上面的代碼中,我們創(chuàng)建了一個繼承自View的子類,構(gòu)造函數(shù)里我們初始化了畫筆Paint,設(shè)置顏色為紅色。在onDraw()方法里,我們使用Canvas內(nèi)部的幾個draw方法繪制不同的圖形,drawText是繪制文本,drawCircle是繪制圓...

最后效果如下:

Canvas畫圖

除了繪制各種基本的圖形,我們也可以通過drawBitmap來繪制圖片。實際開發(fā)中,利用Canvas、Paint等類,我們可以創(chuàng)造出很出酷炫的自定義圖形。

五、SurfaceView簡介

自己之前對SurfaceView這個類不是很熟悉,這次特地查閱了官方文檔結(jié)合相關(guān)資料,這里簡單地作個介紹。

View在大部分情況下可以滿足我們的繪圖需求,但是當(dāng)需要頻繁刷新,或者刷新時數(shù)據(jù)量比較大時,容易造成畫面卡頓,SurfaceView是用來在上述兩種情況下替代View的。

下面是官方文檔的介紹

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen

SurfaceView提供了一個專門用于繪圖的surface,它嵌入在View的內(nèi)部。我們可以控制這個surface的格式和大小,SurfaceView主要負責(zé)把surface放置在屏幕上的正確位置。

SurfaceView可以直接從內(nèi)存或者DMA等硬件接口取得圖像數(shù)據(jù),因此是個非常重要的繪圖容器。

六、總結(jié)

在實際開發(fā)中,我們可以為顯示的圖形圖像增加很多的特效,這部分內(nèi)容這里就不詳細介紹了。總的來說,我們可以利用ColorMatrix顏色矩陣類來處理圖像的色彩效果,Android系統(tǒng)利用矩陣來進行圖像的圖形變換,當(dāng)然,我們還可以充分地利用Android中的動畫來完成圖形圖像的動態(tài)效果展示。

關(guān)于Android中的圖形圖像部分的學(xué)習(xí)總結(jié)就是這些,當(dāng)然實踐出真知,只有在實際開發(fā)中不斷摸索不斷嘗試,才能更好地掌握Android中的這些圖形圖像處理,創(chuàng)造出更多更酷炫的自定義效果。

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

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,682評論 25 708
  • 1. Outline 本文主要從以下三個大的方面來說明一下2D Graphic 繪圖的一些相關(guān)函數(shù)及應(yīng)用。 Col...
    lee_3do閱讀 3,046評論 0 11
  • //通過獲得資源文件進行設(shè)置。根據(jù)不同的情況R.color.red也可以是R.string.red或者R.draw...
    gogoingmonkey閱讀 1,978評論 0 2
  • 參考Drawable子類之—— BitmapDrawable (可控制對齊平鋪的圖像) 明明圖片拉進去對應(yīng)的文件之...
    合肥黑閱讀 5,408評論 0 7
  • docker-compose 訪問http://192.168.99.100:8500/ui/#/dc1/serv...
    go4it閱讀 602評論 0 1