欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義視圖中圖片的處理

 更新時間:2022年07月21日 09:55:31   作者:撩得Android一次心動  
Android系統(tǒng)提供了ImageView顯示普通的靜態(tài)圖片,也提供了AnimationDrawable來開發(fā)逐幀動畫,還可通過Animation對普通圖片使用補間動畫。圖形、圖像處理不僅對Android系統(tǒng)的應(yīng)用界面非常重要,而且Android系統(tǒng)上的益智類游戲、2D游戲都需要大量的圖形、圖像處理

所謂游戲,本質(zhì)就是提供更逼真的、能模擬某種環(huán)境的用戶界面,并根據(jù)某種規(guī)則來響應(yīng)用戶操作。為了提供更逼真的用戶界面,需要借助于圖形、圖像處理。

從廣義的角度來看,Android應(yīng)用中的圖片不僅包括*.png、*.jpg、 *.gif等各種格式的位圖,也包括使用XML資源文件定義的各種Drawable對象。

1.使用Drawable對象

為Android應(yīng)用增加了Drawable資源之后,Android SDK會為這份資源在R清單文件中創(chuàng)建一個索引項:R.drawable.file_name。

獲取方式:

  • 在XML資源文件中通過@drawablelfile_name訪問該Drawable對象
  • 在Java代碼中通過R.drawable.file_name訪問該Drawable對象。

需要指出的是,R.drawable.file_name是一個int類型的常量,它只代表Drawable對象的ID,如果Java程序中需要獲取實際的Drawable對象,則可調(diào)用Resources的getDrawable (int id)方法來實現(xiàn)。

2.Bitmap和BitmapFactory

Bitmap代表一個位圖,BitmapDrawable里封裝的圖片就是一個Bitmap對象。

兩者之間的轉(zhuǎn)換:

//把一個Bitmap對象包裝成BitmapDrawable對象
BitmapDrawable drawable = new BitmapDrawable (bitmap) ;

如果需要獲取BitmapDrawable所包裝的Bitmap對象,則可調(diào)用BitmapDrawable的getBitmap ()方法,如下面的代碼所示:

//獲取BitmapDrawable所包裝的Bitmap 對象
Bitmap bitmap = drawable.getBitmap();

新建Bitmap對象的一些方法:

  • createBitmap (Bitmap source,int x, int y,int width,int height):從源位圖source的指定坐標(biāo)點(給定x、y)開始,從中“挖取"寬width、高height的一塊出來,創(chuàng)建新的Bitmap對象。
  • createScaledBitmap (Bitmap src, int dstWidth,int dstHeight,boolean filter) :對源位圖src進行縮放,縮放成寬dstWidth、高dstHeight的新位圖。 filter是過濾器。
  • createBitmap (int width,int height,Bitmap.Config config):創(chuàng)建一個寬width、高height的新位圖。
  • createBitmap (Bitmap source,int x, int y, int width,int height,Matrixm, boolean filter):從源位圖source 的指定坐標(biāo)點(給定x、y)開始,從中“挖取"寬 width、高height的一塊出來,創(chuàng)建新的Bitmap對象,并按Matrix指定的規(guī)則進行變換。

Bitmap.Config類,在Bitmap類里createBitmap(int width, int height, Bitmap.Config config)方法里會用到,打開個這個類一看 :枚舉變量

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是一個工具類,它提供了大量的方法,這些方法可用于從不同的數(shù)據(jù)源來解析、創(chuàng)建Bitmap對象。BitmapFactory包含了如下方法。

  • decodeByteArray (byte[]data,int offset,int length)︰從指定字節(jié)數(shù)組的offset位置開始,將長度為length的字節(jié)數(shù)據(jù)解析成Bitmap對象。
  • decodeFile (String pathName) :從pathName指定的文件中解析、創(chuàng)建Bitmap對象。
  • decodeFileDescriptor (FileDescriptor fd):用于從FileDescriptor對應(yīng)的文件中解析、創(chuàng)建Bitmap對象。
  • decodeResource (Resources res,int id) :用于根據(jù)給定的資源ID從指定資源中解析、創(chuàng)建Bitmap對象。
  • decodeStream (InputStream is):用于從指定輸入流中解析、創(chuàng)建Bitmap對象。

對于創(chuàng)建而言,對應(yīng)的就是回收了。如果系統(tǒng)不停的去解析、創(chuàng)建Bitmap對象,可能由于創(chuàng)建的Bitmap所占用的內(nèi)存還沒回收,而導(dǎo)致OOM。

  • boolean isRecycled ():返回該Bitmap對象是否已被回收。
  • void recycle () :強制一個Bitmap對象立即回收自己。

如果Android應(yīng)用需要訪問其他存儲路徑(比如SD卡)里的圖片,那么都需要借助于BitmapFactory來解析、創(chuàng)建Bitmap對象。

2.1 例子

下面開發(fā)一個查看/assets/目錄下圖片的圖片查看器,當(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;
            }
            //找到下一個圖片文件
            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 {
                //打開指定資源對應(yīng)的輸入流
                assetFile = assets.open(images[currentImg++]);
            } catch (IOException e) {
                e.printStackTrace();
            }
            BitmapDrawable bitmapDrawable = (BitmapDrawable) image.getDrawable();
            //如果圖片還未回收,先強制回收該圖片
            if(bitmapDrawable != null&&!bitmapDrawable.getBitmap().isRecycled()){
                bitmapDrawable.getBitmap().recycle();
            }
            //改變ImageView顯示圖片
            //調(diào)用了BitmapFactory從指定輸入流解析并創(chuàng)建Bitmap
            image.setImageBitmap(BitmapFactory.decodeStream(assetFile));
        });
    }
}

2.2 額外知識點(assets)

系統(tǒng)為每一個新設(shè)計的程序提供了/assets文件夾,這個文件夾保存的文件能夠打包在程序里。

/res和/assets的不同點是,android不為/assets下的文件生成ID。假設(shè)使用/assets下的文件,須要指定文件的路徑和文件名稱。怎樣訪問/assets下的內(nèi)容?

例如,假設(shè)在assets目錄下有一個名稱為filename的文件,那么就可以使用以下代碼來訪問它:

AssetManager assset= getAssets();  
InputStream is = assset.open("filename");

2.3 代碼更嚴謹

1.發(fā)現(xiàn)這代碼一點黃色都沒有,證明很嚴謹。

注意為什么button放在了里面,而imageView放在了外面。

將button放在外面會有Field can be converted to a local variable的警告,意思是檢測到這個變量可以使用局部變量替換,建議刪除并寫成局部變量。就是其他地方也沒有使用到它,沒有必要聲明成成員變量。

2.設(shè)計到數(shù)組訪問,一定要防止其數(shù)組越界。上面還搞了兩個。

assetFile = assets.open(images[currentImg++]);

此時進入到open的必定是圖片資源的name,用了之后currentImg自加,探索下一個圖片。第一個防止其數(shù)組越界的判斷就是防這里的;第二是對應(yīng)著判斷不是圖片資源的++。但是這個代碼還有問題:假如里面有資源,但是都不是圖片資源。那就會進入死循環(huán)

3.在顯示圖片之前,一定要釋放之前的Bitmap,以免OOM

釋放的判斷的條件是使用Bitmap的封裝類。

3.Android9新增的ImageDecoder

Android 9 引入了 ImageDecoder、OnHanderDecodedListener 等API,提供了更強大的圖片解碼支持,可以解碼png、jpeg等靜態(tài)圖片和gif、webp等動畫圖片。另外。還新增了支持HEIF格式:

HEIF格式:這種壓縮格式據(jù)有超高的壓縮比例,相比JPEG,可以壓縮到其一半大小,而且可以保證其近似的圖片質(zhì)量。

當(dāng)使用 ImageDecoder 解碼gif、webp等動畫圖片時,會返回一個AnimatedImageDrawable對象,調(diào)用AnimatedImageDrawable對象的start()方法即可開始執(zhí)行動畫。

ImageDecoder 解碼圖片的方式:

  • 調(diào)用 ImageDecoder 的重載的 createSource 方法來創(chuàng)建 Source 對象。根據(jù)不同的圖片來源, createSource 方法有不同的重載模式。
  • 調(diào)用ImageDecoder 的 decodeDrawabIe(Source) or decodeBitmap(Source)方法來讀取代表圖片的 Drawable或 Bitmap對象。

在第二步時,可以額外傳入一個OnHanderDecodedListener參數(shù),該參數(shù)代表了監(jiān)聽器,該監(jiān)聽器要實現(xiàn)一個 onHanderDecoded(ImageDecoder,ImageInfo,Source)方法,可以對ImageDecoder進行額外的設(shè)置,也可以通過 ImageInfo 獲取被解碼圖片的信息。

3.1 例子

public class Test5Activity extends AppCompatActivity {
    //說白了只有api 28 之后的才進的來
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test5);
        //獲取對象
        TextView textView = findViewById(R.id.test5_tv);
        ImageView imageView = findViewById(R.id.test5_iv);
        //創(chuàng)建 imageDecoder.Source對象
            //第一步:
            ImageDecoder.Source source = ImageDecoder.createSource(getResources(),R.drawable.viewgif);
            try {
                //第二步:執(zhí)行decodeDrawable()方法獲取Drawable對象
                @SuppressLint({"WrongThread", "SetTextI18n"})
                Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
                    //通過 info 參數(shù)獲取被解碼圖片的信息
                    textView.setText("圖片的原始寬度:"+info.getSize().getWidth()+
                            "\n"+"圖片原始寬高"+info.getSize().getHeight());
                    //設(shè)置圖片解碼之后的縮放大小
                    decoder.setTargetSize(600,580);
                });
                imageView.setImageDrawable(drawable);
                //如果drawable 是AnimatedImageDrawable的實例,則執(zhí)行動畫
                if(drawable instanceof AnimatedImageDrawable){
                    ((AnimatedImageDrawable) drawable).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}

與傳統(tǒng)的BitmapFactory相比,ImageDecoder 甚至可以解碼包含不完整或錯誤的圖片,如果希望顯示ImageDecoder解碼出錯之前的部分圖片,則可通過為 ImageDecoder沒置OnPartialImageListener監(jiān)聽器來實現(xiàn)。例如如下代碼片段:

//先用Lambda 表達式作為OnHeaderDecodeListener監(jiān)聽器
    Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
        //為ImageDecoder 設(shè)置 OnPartialImageListener 監(jiān)聽器(Lambda 表達式)
        decoder.setOnPartialImageListener(e->{
            ....
            //return true 表明即使不能完整地解碼全部圖片也返回Drawable或Bitmap
            return true;
        });
    });

到此這篇關(guān)于Android自定義視圖中圖片的處理的文章就介紹到這了,更多相關(guān)Android圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論