在上一篇文章中Android中的圖片裁剪(二)之開源項目介紹了一些優(yōu)秀的圖片裁剪開源項目,在我們實現(xiàn)自己的裁剪功能的時候媒殉,也可以看下這些開源項目的源碼外盯,看看大牛們都是怎么實現(xiàn)的捂襟。
createBitmap方法
首先要做圖片裁剪的功能,要先認識Bitmap壶硅,在這個類里面,有幾個方法可以幫助我們實現(xiàn)功能销斟。就比如下面這一個方法
/**
* Returns an immutable bitmap from the specified subset of the source
* bitmap. The new bitmap may be the same object as source, or a copy may
* have been made. It is initialized with the same density as the original
* bitmap.
*...
*/
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)
好吧庐椒,方法注解太長,被我省略掉一些了蚂踊,但是用起來其實挺簡單的约谈,只要傳入指定的范圍,它就能生成一個新的位圖給你。(這里先說一句棱诱,圖片的裁剪功能其實做起來不難泼橘,要做好就挺麻煩的,在實際的工具開發(fā)中免不了要自定義View這樣的工作)迈勋,而這邊的范圍一般是一個可拖動的方框炬灭,點擊裁剪按鈕的時候生成我們需要的圖片。當然createBitmap方法還有很多其他重載實現(xiàn)靡菇,這里就不一一貼出來了重归。在具體實現(xiàn)的時候我們可以自定義兩個View
public class CropImageView extends ImageView {
HighlightView hv;
//...
}
class HighlightView {
//...
}
這里只是簡單的提供一下思路,HighlightView用來表示裁剪框?qū)ο笙梅铮庋b裁剪框的一些信息啊鼻吮,比如寬高和觸摸狀態(tài)什么的。CropImageView繼承ImageView用來顯示圖片和處理觸摸事件较鼓,在觸摸事件中改變HighlightView的狀態(tài):
public boolean onTouchEvent(@NonNull MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//對觸摸點進行一些邏輯判斷椎木,比如摸到裁剪框的邊還是其他什么的
int edge = hv.getHit(event.getX(), event.getY());
//...
//然后根據(jù)邏輯判斷結(jié)果設(shè)置裁剪框的狀態(tài)
hv.setMode((edge == HighlightView.MOVE)
? HighlightView.ModifyMode.Move
: HighlightView.ModifyMode.Grow);
//...
break;
//...
啦啦啦,是不是說了跟沒說一樣笨腥,主要是具體實現(xiàn)起來真的挺麻煩的拓哺,貼那么多代碼出來也沒啥用,我自己都要看暈了脖母,總歸自己造輪子還是挺辛苦的士鸥,而且剛造出來也肯定有一些問題的,所以才有那句名言么谆级,不要重復(fù)造輪子烤礁,我覺得只要看懂源代碼的思路,然后根據(jù)需求肥照,在別人的輪子上進行改造脚仔,這樣就快的多啦。
Matrix的基本使用
一般呢舆绎,在裁剪的工具中鲤脏,在對圖片裁剪前,多可以對圖片進行一些縮放吕朵,平移猎醇,旋轉(zhuǎn)之類的操作,這些效果都是可以通過Matrix來實現(xiàn)的努溃,那這個類怎么用呢硫嘶。我們先看一下[官方文檔中Matrix](file:///D:/Android/sdk/docs/reference/android/graphics/Matrix.html)的介紹(自帶梯子) ,首先看一下它的官方定義:
**The Matrix class holds a 3x3 matrix for transforming coordinates. **
直譯過來呢梧税,就是一個轉(zhuǎn)換坐標的3x3矩陣沦疾,你妹啊称近,什么是3x3矩陣...我也不知道啊 ,高等數(shù)學(xué)這東西我早就扔了好么哮塞,不過不知道沒關(guān)系刨秆,面向?qū)ο竺矗蚁戎涝趺从镁涂梢粤顺固遥袝r間有閑情再去深究坛善。我們先主要看一下Matrix類里面,我們要用到的一些方法(補充說一下邻眷,這Matrix類是在graphics包下的眠屎,不要導(dǎo)成opengl包下的):
/**
* Postconcats the matrix with the specified translation.
* M' = T(dx, dy) * M
*/
public boolean postTranslate(float dx, float dy)
/**
* Postconcats the matrix with the specified rotation.
* M' = R(degrees) * M
*/
public boolean postRotate(float degrees)
好啦,畢竟是文檔找的到東西肆饶,我這里就只貼兩個方法出來改衩,看注解應(yīng)該很容易理解方法的使用,第一個方法就是對矩陣進行左乘T(dx, dy)驯镊,第二個方法就是對矩陣左乘R(degrees)葫督,通過源碼我們可以看到,方法里面通過jni調(diào)用lib層用c板惑,c++實現(xiàn)運算轉(zhuǎn)換的橄镜。反正直白點講,在對它進行圖片變換的時候冯乘,第一個方法就是平移圖片洽胶,第二個方法就是旋轉(zhuǎn)圖片,啦啦啦裆馒,其他方法大家可以自行查找文檔姊氓,問題都不大。
圖片的平移喷好,縮放翔横,旋轉(zhuǎn)
通過重寫View或者Activity的onTouch事件來進行圖片的平移,縮放和旋轉(zhuǎn)會比較方便梗搅,這里我們要先做一些初始化工作禾唁,比如獲取圖片之類的,一般我們將圖片的大小控制在手機內(nèi)存的1/8无切,防止OOM和卡頓蟀俊,然后就是在onTouch事件里做具體實現(xiàn):
public boolean onTouch(View v, MotionEvent event)
{
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
// 主點按下
case MotionEvent.ACTION_DOWN:
cachMatrix.set(matrix);//用來變化的矩陣
prev.set(event.getX(), event.getY());
mode = DRAG;
break;
//...
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)//拖動
{
matrix.set(cachMatrix);
matrix.postTranslate(event.getX() - prev.x, event.getY() - prev.y);
}
else if (mode == ZOOM)//縮放
{
float newDist = spacing(event);
if (newDist > 10f)
{
matrix.set(cachMatrix);
float tScale = newDist / dist;
matrix.postScale(tScale, tScale, mid.x, mid.y);
}
}
break;
}
imgView.setImageMatrix(matrix);
//...
return true;
}
代碼就放了部分上去,主要說明一下思路订雾,當然在將這些功能和裁剪進行合并的時候,是要對裁剪框的位置再進行計算的,比如因為對圖片縮放了矛洞,所以再返回剪裁框大小的時候是要乘上縮放值的洼哎。
public Rect getScaledCropRect(float scale) {
return new Rect((int) (cropRect.left * scale), (int) (cropRect.top * scale),
(int) (cropRect.right * scale), (int) (cropRect.bottom * scale));
}
總結(jié)
圖片的裁剪就先寫到這里烫映,主要介紹了一些關(guān)鍵方法和整體的實現(xiàn)思路,后面有時間的話噩峦,我會把代碼整理后發(fā)布到github上去的锭沟,到時候再來補鏈接。