Android自定義視圖中圖片的處理
所謂游戲,本質(zhì)就是提供更逼真的、能模擬某種環(huán)境的用戶界面,并根據(jù)某種規(guī)則來(lái)響應(yīng)用戶操作。為了提供更逼真的用戶界面,需要借助于圖形、圖像處理。
從廣義的角度來(lái)看,Android應(yīng)用中的圖片不僅包括*.png、*.jpg、 *.gif等各種格式的位圖,也包括使用XML資源文件定義的各種Drawable對(duì)象。
1.使用Drawable對(duì)象
為Android應(yīng)用增加了Drawable資源之后,Android SDK會(huì)為這份資源在R清單文件中創(chuàng)建一個(gè)索引項(xiàng):R.drawable.file_name。
獲取方式:
- 在XML資源文件中通過(guò)@drawablelfile_name訪問(wèn)該Drawable對(duì)象
- 在Java代碼中通過(guò)R.drawable.file_name訪問(wèn)該Drawable對(duì)象。
需要指出的是,R.drawable.file_name是一個(gè)int類型的常量,它只代表Drawable對(duì)象的ID,如果Java程序中需要獲取實(shí)際的Drawable對(duì)象,則可調(diào)用Resources的getDrawable (int id)方法來(lái)實(shí)現(xiàn)。
2.Bitmap和BitmapFactory
Bitmap代表一個(gè)位圖,BitmapDrawable里封裝的圖片就是一個(gè)Bitmap對(duì)象。
兩者之間的轉(zhuǎn)換:
//把一個(gè)Bitmap對(duì)象包裝成BitmapDrawable對(duì)象 BitmapDrawable drawable = new BitmapDrawable (bitmap) ;
如果需要獲取BitmapDrawable所包裝的Bitmap對(duì)象,則可調(diào)用BitmapDrawable的getBitmap ()方法,如下面的代碼所示:
//獲取BitmapDrawable所包裝的Bitmap 對(duì)象 Bitmap bitmap = drawable.getBitmap();
新建Bitmap對(duì)象的一些方法:
- createBitmap (Bitmap source,int x, int y,int width,int height):從源位圖source的指定坐標(biāo)點(diǎn)(給定x、y)開(kāi)始,從中“挖取"寬width、高h(yuǎn)eight的一塊出來(lái),創(chuàng)建新的Bitmap對(duì)象。
- createScaledBitmap (Bitmap src, int dstWidth,int dstHeight,boolean filter) :對(duì)源位圖src進(jìn)行縮放,縮放成寬dstWidth、高dstHeight的新位圖。 filter是過(guò)濾器。
- createBitmap (int width,int height,Bitmap.Config config):創(chuàng)建一個(gè)寬width、高h(yuǎn)eight的新位圖。
- createBitmap (Bitmap source,int x, int y, int width,int height,Matrixm, boolean filter):從源位圖source 的指定坐標(biāo)點(diǎn)(給定x、y)開(kāi)始,從中“挖取"寬 width、高h(yuǎn)eight的一塊出來(lái),創(chuàng)建新的Bitmap對(duì)象,并按Matrix指定的規(guī)則進(jìn)行變換。
Bitmap.Config類,在Bitmap類里createBitmap(int width, int height, Bitmap.Config config)方法里會(huì)用到,打開(kāi)個(gè)這個(gè)類一看 :枚舉變量
public static final Bitmap.Config ALPHA_8
public static final Bitmap.Config ARGB_4444
public static final Bitmap.Config ARGB_8888
public static final Bitmap.Config RGB_565
BitmapFactory是一個(gè)工具類,它提供了大量的方法,這些方法可用于從不同的數(shù)據(jù)源來(lái)解析、創(chuàng)建Bitmap對(duì)象。BitmapFactory包含了如下方法。
- decodeByteArray (byte[]data,int offset,int length)︰從指定字節(jié)數(shù)組的offset位置開(kāi)始,將長(zhǎng)度為length的字節(jié)數(shù)據(jù)解析成Bitmap對(duì)象。
- decodeFile (String pathName) :從pathName指定的文件中解析、創(chuàng)建Bitmap對(duì)象。
- decodeFileDescriptor (FileDescriptor fd):用于從FileDescriptor對(duì)應(yīng)的文件中解析、創(chuàng)建Bitmap對(duì)象。
- decodeResource (Resources res,int id) :用于根據(jù)給定的資源ID從指定資源中解析、創(chuàng)建Bitmap對(duì)象。
- decodeStream (InputStream is):用于從指定輸入流中解析、創(chuàng)建Bitmap對(duì)象。
對(duì)于創(chuàng)建而言,對(duì)應(yīng)的就是回收了。如果系統(tǒng)不停的去解析、創(chuàng)建Bitmap對(duì)象,可能由于創(chuàng)建的Bitmap所占用的內(nèi)存還沒(méi)回收,而導(dǎo)致OOM。
- boolean isRecycled ():返回該Bitmap對(duì)象是否已被回收。
- void recycle () :強(qiáng)制一個(gè)Bitmap對(duì)象立即回收自己。
如果Android應(yīng)用需要訪問(wèn)其他存儲(chǔ)路徑(比如SD卡)里的圖片,那么都需要借助于BitmapFactory來(lái)解析、創(chuàng)建Bitmap對(duì)象。
2.1 例子
下面開(kāi)發(fā)一個(gè)查看/assets/目錄下圖片的圖片查看器,當(dāng)用戶單擊該按鈕時(shí)程序會(huì)自動(dòng)去搜尋/assets/目錄下的下—張圖片。此處不再給出界面布局代碼,該程序的代碼如下。
public class Test4Activity extends Activity { String[] images = null; AssetManager assets = null; int currentImg = 0; private ImageView image; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test4_acitvity); image = findViewById(R.id.test4_iv); Button next = findViewById(R.id.test4_bt_next); try { assets = getAssets(); //獲取assets目錄目錄下的所有文件 images =assets.list(""); } catch (IOException e) { e.printStackTrace(); } //按鈕事件 next.setOnClickListener(view -> { //如果發(fā)生數(shù)組越界 if(currentImg >= images.length){ currentImg = 0; } //找到下一個(gè)圖片文件 while (!images[currentImg].endsWith(".png")&&!images[currentImg].endsWith(".jpg") &&!images[currentImg].endsWith(".gif")){ currentImg++; //如果已經(jīng)發(fā)生了數(shù)組越界 if(currentImg >= images.length){ currentImg = 0; } } InputStream assetFile = null; try { //打開(kāi)指定資源對(duì)應(yīng)的輸入流 assetFile = assets.open(images[currentImg++]); } catch (IOException e) { e.printStackTrace(); } BitmapDrawable bitmapDrawable = (BitmapDrawable) image.getDrawable(); //如果圖片還未回收,先強(qiáng)制回收該圖片 if(bitmapDrawable != null&&!bitmapDrawable.getBitmap().isRecycled()){ bitmapDrawable.getBitmap().recycle(); } //改變ImageView顯示圖片 //調(diào)用了BitmapFactory從指定輸入流解析并創(chuàng)建Bitmap image.setImageBitmap(BitmapFactory.decodeStream(assetFile)); }); } }
2.2 額外知識(shí)點(diǎn)(assets)
系統(tǒng)為每一個(gè)新設(shè)計(jì)的程序提供了/assets文件夾,這個(gè)文件夾保存的文件能夠打包在程序里。
/res和/assets的不同點(diǎn)是,android不為/assets下的文件生成ID。假設(shè)使用/assets下的文件,須要指定文件的路徑和文件名稱。怎樣訪問(wèn)/assets下的內(nèi)容?
例如,假設(shè)在assets目錄下有一個(gè)名稱為filename的文件,那么就可以使用以下代碼來(lái)訪問(wèn)它:
AssetManager assset= getAssets(); InputStream is = assset.open("filename");
2.3 代碼更嚴(yán)謹(jǐn)
1.發(fā)現(xiàn)這代碼一點(diǎn)黃色都沒(méi)有,證明很嚴(yán)謹(jǐn)。
注意為什么button放在了里面,而imageView放在了外面。
將button放在外面會(huì)有Field can be converted to a local variable的警告,意思是檢測(cè)到這個(gè)變量可以使用局部變量替換,建議刪除并寫(xiě)成局部變量。就是其他地方也沒(méi)有使用到它,沒(méi)有必要聲明成成員變量。
2.設(shè)計(jì)到數(shù)組訪問(wèn),一定要防止其數(shù)組越界。上面還搞了兩個(gè)。
assetFile = assets.open(images[currentImg++]);
此時(shí)進(jìn)入到open的必定是圖片資源的name,用了之后currentImg自加,探索下一個(gè)圖片。第一個(gè)防止其數(shù)組越界的判斷就是防這里的;第二是對(duì)應(yīng)著判斷不是圖片資源的++。但是這個(gè)代碼還有問(wèn)題:假如里面有資源,但是都不是圖片資源。那就會(huì)進(jìn)入死循環(huán)
3.在顯示圖片之前,一定要釋放之前的Bitmap,以免OOM
釋放的判斷的條件是使用Bitmap的封裝類。
3.Android9新增的ImageDecoder
Android 9 引入了 ImageDecoder、OnHanderDecodedListener 等API,提供了更強(qiáng)大的圖片解碼支持,可以解碼png、jpeg等靜態(tài)圖片和gif、webp等動(dòng)畫(huà)圖片。另外。還新增了支持HEIF格式:
HEIF格式:這種壓縮格式據(jù)有超高的壓縮比例,相比JPEG,可以壓縮到其一半大小,而且可以保證其近似的圖片質(zhì)量。
當(dāng)使用 ImageDecoder 解碼gif、webp等動(dòng)畫(huà)圖片時(shí),會(huì)返回一個(gè)AnimatedImageDrawable對(duì)象,調(diào)用AnimatedImageDrawable對(duì)象的start()方法即可開(kāi)始執(zhí)行動(dòng)畫(huà)。
ImageDecoder 解碼圖片的方式:
- 調(diào)用 ImageDecoder 的重載的 createSource 方法來(lái)創(chuàng)建 Source 對(duì)象。根據(jù)不同的圖片來(lái)源, createSource 方法有不同的重載模式。
- 調(diào)用ImageDecoder 的 decodeDrawabIe(Source) or decodeBitmap(Source)方法來(lái)讀取代表圖片的 Drawable或 Bitmap對(duì)象。
在第二步時(shí),可以額外傳入一個(gè)OnHanderDecodedListener參數(shù),該參數(shù)代表了監(jiān)聽(tīng)器,該監(jiān)聽(tīng)器要實(shí)現(xiàn)一個(gè) onHanderDecoded(ImageDecoder,ImageInfo,Source)方法,可以對(duì)ImageDecoder進(jìn)行額外的設(shè)置,也可以通過(guò) ImageInfo 獲取被解碼圖片的信息。
3.1 例子
public class Test5Activity extends AppCompatActivity { //說(shuō)白了只有api 28 之后的才進(jìn)的來(lái) @RequiresApi(api = Build.VERSION_CODES.P) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test5); //獲取對(duì)象 TextView textView = findViewById(R.id.test5_tv); ImageView imageView = findViewById(R.id.test5_iv); //創(chuàng)建 imageDecoder.Source對(duì)象 //第一步: ImageDecoder.Source source = ImageDecoder.createSource(getResources(),R.drawable.viewgif); try { //第二步:執(zhí)行decodeDrawable()方法獲取Drawable對(duì)象 @SuppressLint({"WrongThread", "SetTextI18n"}) Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{ //通過(guò) info 參數(shù)獲取被解碼圖片的信息 textView.setText("圖片的原始寬度:"+info.getSize().getWidth()+ "\n"+"圖片原始寬高"+info.getSize().getHeight()); //設(shè)置圖片解碼之后的縮放大小 decoder.setTargetSize(600,580); }); imageView.setImageDrawable(drawable); //如果drawable 是AnimatedImageDrawable的實(shí)例,則執(zhí)行動(dòng)畫(huà) if(drawable instanceof AnimatedImageDrawable){ ((AnimatedImageDrawable) drawable).start(); } } catch (IOException e) { e.printStackTrace(); } } }
與傳統(tǒng)的BitmapFactory相比,ImageDecoder 甚至可以解碼包含不完整或錯(cuò)誤的圖片,如果希望顯示ImageDecoder解碼出錯(cuò)之前的部分圖片,則可通過(guò)為 ImageDecoder沒(méi)置OnPartialImageListener監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)。例如如下代碼片段:
//先用Lambda 表達(dá)式作為OnHeaderDecodeListener監(jiān)聽(tīng)器 Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{ //為ImageDecoder 設(shè)置 OnPartialImageListener 監(jiān)聽(tīng)器(Lambda 表達(dá)式) decoder.setOnPartialImageListener(e->{ .... //return true 表明即使不能完整地解碼全部圖片也返回Drawable或Bitmap return true; }); });
到此這篇關(guān)于Android自定義視圖中圖片的處理的文章就介紹到這了,更多相關(guān)Android圖片內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android實(shí)現(xiàn)圖片九宮格
- Android不壓縮圖片實(shí)現(xiàn)高清加載巨圖實(shí)例
- Android實(shí)現(xiàn)手勢(shì)劃定區(qū)域裁剪圖片
- AndroidStudio實(shí)現(xiàn)能在圖片上涂鴉程序
- Android studio實(shí)現(xiàn)左右滑動(dòng)切換圖片
- Android實(shí)現(xiàn)左右滑動(dòng)切換圖片
- Android開(kāi)發(fā)實(shí)現(xiàn)圖片大小與質(zhì)量壓縮及保存
- Android性能優(yōu)化之圖片大小,尺寸壓縮綜合解決方案
- Android實(shí)現(xiàn)圖片預(yù)覽與保存功能
相關(guān)文章
詳細(xì)分析Android中onTouch事件傳遞機(jī)制
相信不少朋友在剛開(kāi)始學(xué)習(xí)Android的時(shí)候,對(duì)于onTouch相關(guān)的事件一頭霧水。分不清onTouch(),onTouchEvent()和OnClick()之間的關(guān)系和先后順序,所以覺(jué)得有必要搞清onTouch事件傳遞的原理。經(jīng)過(guò)一段時(shí)間的琢磨以及相關(guān)博客的介紹,這篇文章就給大家詳細(xì)的分析介紹下。2016-10-10Android平臺(tái)生成二維碼并實(shí)現(xiàn)掃描 & 識(shí)別功能
這篇文章主要介紹了Android平臺(tái)生成二維碼并實(shí)現(xiàn)掃描 & 識(shí)別功能的相關(guān)資料,需要的朋友可以參考下2016-06-06Android實(shí)現(xiàn)apk插件方式換膚的實(shí)例講解
在本篇文章里小編給大家整理的是關(guān)于Android實(shí)現(xiàn)apk插件方式換膚的實(shí)例代碼以及相關(guān)知識(shí)點(diǎn),有需要的朋友們學(xué)習(xí)下。2019-10-10Android自定義viewgroup可滾動(dòng)布局 GestureDetector手勢(shì)監(jiān)聽(tīng)(5)
這篇文章主要為大家詳細(xì)介紹了Android自定義viewgroup可滾動(dòng)布局,GestureDetector手勢(shì)監(jiān)聽(tīng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12Android使用Kotlin實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android使用Kotlin實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03通過(guò)實(shí)例簡(jiǎn)單講解Android App中的Activity組件
這篇文章主要介紹了通過(guò)Android App中的Activity組件,包括Activity的定義和繼承以及啟動(dòng)等基本知識(shí),需要的朋友可以參考下2016-04-04更新至Android Studio4.1后發(fā)現(xiàn)as打不開(kāi)的解決方法(原因分析)
這篇文章主要介紹了更新至Android Studio4.1后發(fā)現(xiàn)as打不開(kāi)的解決方案,本文給大家分享問(wèn)題所在原因給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10