這個問題涉及圖片呈現(xiàn)的一整套方案。歸納而言這個問題是:給定任意尺寸的圖片如何在任意尺寸分辨率的機器上顯示?并且能夠保持圖片原來的清晰度。一般采用如下方案來解決這個問題:
創(chuàng)新互聯(lián)公司是網(wǎng)站建設(shè)技術(shù)企業(yè),為成都企業(yè)提供專業(yè)的網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計,網(wǎng)站設(shè)計,網(wǎng)站制作,網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗和眾多成功案例,為您定制適合企業(yè)的網(wǎng)站。10年品質(zhì),值得信賴!
1、首先給原圖片創(chuàng)建一塊內(nèi)存緩存副本。如果不創(chuàng)建緩存的話,那么任何一次圖片的剪切、縮放等操作都將丟失圖片信息,使得保持原有圖片的滋味那是不可能的。當(dāng)然對于一般的程序而言,這個操作只需要調(diào)用簡單的API即可完成。例如Android,只需要創(chuàng)建一個對應(yīng)圖片的Bitmap對象即可。
2、如果想要在設(shè)備顯示的初始化狀態(tài)圖片即為滿屏,那么必須調(diào)用相關(guān)API動態(tài)獲得設(shè)備的分辨率。然后按設(shè)備分辨率的大小對圖片進行剪切并顯示到設(shè)備上。
注意:在獲得圖片分辨率后,如果分辨率大于圖片,那不用說,直接顯示圖片就好。但是如果小于圖片,此時有多種選擇。可以將圖片縮放至屏幕分辨率(圖片縱橫比可能失真)也可以選擇剪切圖片的一部分顯示到屏幕上。
3、對圖片進行縮放或者移動
我們在圖片第一次顯示的時候無論是選擇縮放還是剪切,都要記錄下圖片被縮放的比例或者剪輯的范圍。這樣在用戶再次移動或者縮放的時候,根據(jù)之前的縮放比例和移動坐標(biāo),計算當(dāng)前應(yīng)該移動的位置和縮放比例。并且根據(jù)計算結(jié)果對緩存的圖片進行剪輯并顯示到屏幕上。
其實整個過程可以概括為如下流程:
——圖片的初始縮放比例和顯示起點坐標(biāo)——用戶觸發(fā)縮放或者移動操作——計算新的圖片縮放比例和顯示起點坐標(biāo)——根據(jù)新的縮放比例和顯示起點坐標(biāo)剪輯緩存圖片并繪制到屏幕上......
總得一句話要重寫onTouchEvent
1.手勢滾動有很多方法:
可用viewpager實現(xiàn)view的左右滑屏,也可以用ViewFlipper,還有笨方法就是一個imageview,獲取按下抬起坐標(biāo),判斷左滑右滑,然后set另一張圖片進去。
2.縮放也有很多做法
正統(tǒng)的做法是把imageview的屬性scaleType設(shè)置為matrix(矩陣),然后獲取滑動手勢,來操作矩陣獲得縮放的效果
用這個方法吧
//加載需要操作的圖片,這里是一張圖片
bitmap
bitmaporg
=
bitmapfactory.decoderesource(getresources(),r.drawable.r);
//獲取這個圖片的寬和高
int
width
=
bitmaporg.getwidth();
int
height
=
bitmaporg.getheight();
//定義預(yù)轉(zhuǎn)換成的圖片的寬度和高度
int
newwidth
=
200;
int
newheight
=
200;
//計算縮放率,新尺寸除原始尺寸
float
scalewidth
=
((float)
newwidth)
/
width;
float
scaleheight
=
((float)
newheight)
/
height;
//
創(chuàng)建操作圖片用的matrix對象
matrix
matrix
=
new
matrix();
//
縮放圖片動作
matrix.postscale(scalewidth,
scaleheight);
先上效果圖
源碼
單點拖動圖片對圖片進行平移操作。雙手縮放圖片大小和旋轉(zhuǎn)圖片到一定的角度。圖片縮放的時候 不能大于最大的縮放因子和小于最小的縮放因子。大于最大縮放因子或者小于最小縮放因子需要對圖像進行回彈。圖片旋轉(zhuǎn)的角度只能為90度的倍數(shù),不滿足90度要進行回彈。圖片回彈要一個漸變的效果。
大體思路: 首先,Android中提供了Matrix類可以對圖像進行處理。其次,要顯示一張圖片最容易想到的就是ImageView?;貜椧鬂u變的過程,可以通過屬性動畫進行設(shè)置。所以大體的思路是:繼承ImageView,重寫onTouchEvent()方法,判斷事件類型,在對應(yīng)的事件使用Matrix對圖像進行變換。
Matrix是一個已經(jīng)封裝好的矩陣,最重要的作用就是對坐標(biāo)點進行變換。
舉個栗子:
1.某個點(x0,y0,1)通過單位矩陣E映射得到的點還是(x0,y0,1)。
3.點(x0,y0,1)通過矩陣T映射得到的點就會做如下的變換
可以看到點(x0,y0,1)經(jīng)過T矩陣在x軸方向上平移了dx,在y軸方向上平移了dy。
通過以上的變換可以得到具體的思路: 我們維護一個圖像對應(yīng)的矩陣mCurrentMatrix,該矩陣主要是對ImageView中的圖像的各個點進行映射。ImageView在容器位置擺放完成之后,置mCurrentMatrix矩陣為單位矩陣。當(dāng)onTouchEvent()方法中觸發(fā)單點觸控并且手指進行平移的時候,調(diào)用矩陣mCurrentMatrix的postTranslate(dx,dy),對mCurrentMatrix進行變換。當(dāng)手指抬起,利用變換結(jié)束后的矩陣對圖像的各個點進行映射,從而得到平移變換后的圖像。同理可得,在兩只手指進行縮放旋轉(zhuǎn)的時候,我們對矩陣mCurrentMatrix進行各種變換,當(dāng)縮放旋轉(zhuǎn)的事件結(jié)束再利用變換完的矩陣去映射圖像的各個點,從而得到縮放、旋轉(zhuǎn)后的圖像。
安卓自定義View進階 - Matrix原理
安卓自定義View進階 - Matrix詳解
首先理清事件的邏輯:
初始化圖像大小和位置
縮放圖像大小和控件大小自適應(yīng),平移圖像中心和控件中心重合
onTouchEvent()函數(shù)
平移操作
將圖像對應(yīng)的矩陣進行變換。
縮放操作
mBoundRectF為記錄圖像邊界的矩形??s放的時候選取圖像的中心進行縮放。
旋轉(zhuǎn)操作
旋轉(zhuǎn)的時候旋轉(zhuǎn)的旋轉(zhuǎn)中心也是圖像的中心
圖像中各個點的映射
調(diào)用ImageView的setImageMatrix(Matrix matrix)會讓ImageView根據(jù)設(shè)置的matrix去重新繪制圖像。
更新圖像的矩形邊界
獲得圖像的矩形,并根據(jù)矩陣映射矩形各個點的坐標(biāo)。
縮放回彈
旋轉(zhuǎn)回彈
一些計算方法
要求圖像的變換是一個漸變的過程,很容易想到的就是屬性動畫。因為屬性動畫本身就是對值進行不斷set的過程。而我們維護的矩陣也是一個值,所以很自然可以想到,如果得到回彈之前的矩陣的值以及回彈之后矩陣的值,就可以根據(jù)動畫監(jiān)聽器中動畫當(dāng)前的系數(shù)值去改變矩陣的值。
對animator對象設(shè)置完監(jiān)聽器之后,就可以在手指抬起的時候調(diào)用屬性動畫的start()方法開啟動畫。
自定義可平移、縮放、旋轉(zhuǎn)的控件主要點有兩個方面:一是onTouchEvent()中判斷平移、旋轉(zhuǎn)、縮放的觸發(fā)條件,平移位移量、縮放比例因子、旋轉(zhuǎn)角度的計算。二是Matrix矩陣的應(yīng)用。
你要的圖片自動適應(yīng)屏幕寬度,以顯示它的圖片的縮略圖,并且不與自動處理的android ImageView的做任何事情,如果你想要圖片的寬度和高度更精確的控制,你可以在該寬度的活動得到屏幕上,則該圖像被縮放就行
1:ByteArrayOutputStream 壓縮圖片質(zhì)量,不會改變圖片大小
private?Bitmap?compressImage(Bitmap?image)?{
ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,?100,?baos);//質(zhì)量壓縮方法,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
int?options?=?100;????????while?(?baos.toByteArray().length?/?1024100)?{?//循環(huán)判斷如果壓縮后圖片是否大于100kb,大于繼續(xù)壓縮
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG,?options,?baos);//這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
options?-=?10;//每次都減少10????????}
ByteArrayInputStream?isBm?=?new?ByteArrayInputStream(baos.toByteArray());//把壓縮后的數(shù)據(jù)baos存放到ByteArrayInputStream中
Bitmap?bitmap?=?BitmapFactory.decodeStream(isBm,?null,?null);//把ByteArrayInputStream數(shù)據(jù)生成圖片
return?bitmap;
}
2:就是改變圖片大小
private?Bitmap?getimage(String?srcPath)?{
BitmapFactory.Options?newOpts?=?new?BitmapFactory.Options();????????//開始讀入圖片,此時把options.inJustDecodeBounds?設(shè)回true了
newOpts.inJustDecodeBounds?=?true;
Bitmap?bitmap?=?BitmapFactory.decodeFile(srcPath,newOpts);//此時返回bm為空
newOpts.inJustDecodeBounds?=?false;????????int?w?=?newOpts.outWidth;????????int?h?=?newOpts.outHeight;????????//現(xiàn)在主流手機比較多是800*480分辨率,所以高和寬我們設(shè)置為
float?hh?=?800f;//這里設(shè)置高度為800f
float?ww?=?480f;//這里設(shè)置寬度為480f????????//縮放比。由于是固定比例縮放,只用高或者寬其中一個數(shù)據(jù)進行計算即可
int?be?=?1;//be=1表示不縮放
if?(w??h??w??ww)?{//如果寬度大的話根據(jù)寬度固定大小縮放
be?=?(int)?(newOpts.outWidth?/?ww);
}?else?if?(w??h??h??hh)?{//如果高度高的話根據(jù)寬度固定大小縮放
be?=?(int)?(newOpts.outHeight?/?hh);
}????????if?(be?=?0)
be?=?1;
newOpts.inSampleSize?=?be;//設(shè)置縮放比例????????//重新讀入圖片,注意此時已經(jīng)把options.inJustDecodeBounds?設(shè)回false了
bitmap?=?BitmapFactory.decodeFile(srcPath,?newOpts);????????return?compressImage(bitmap);//壓縮好比例大小后再進行質(zhì)量壓縮????}