老規(guī)矩,先上圖,這個(gè)效果大家應(yīng)該都很熟悉
這里寫(xiě)圖片描述
這里寫(xiě)圖片描述
想要實(shí)現(xiàn)這樣的效果,在自定義控件的的時(shí)候,要首先分析一下功能要點(diǎn)有下面幾個(gè):
- 獲取點(diǎn)擊圖片所在位置
- 獲取相應(yīng)bitmap
- 在對(duì)應(yīng)位置繪制bitmap
- 重寫(xiě)onTouch,實(shí)現(xiàn)一系列的操作
首先寫(xiě)第一個(gè)要點(diǎn):
??獲取到點(diǎn)擊的控件,獲取到控件的位置和大小,以及索要顯示的圖片
/**
* 設(shè)置傳入進(jìn)來(lái)的View
*
* @param originView
*/
public void setOriginView(View originView, Bitmap bitmap) {
viewRect = new Rect();
startRect = new Rect();
//獲取控件的寬高
int width = originView.getWidth();
int height = originView.getHeight();
viewRect.right = width;
viewRect.bottom = height;
//記錄控件的原始寬高
startRect.right = width;
startRect.bottom = height;
int[] loaction = ViewUtils.getLoaction(originView);
//獲取到控件相對(duì)于屏幕的絕對(duì)位置
currentPoint.x = loaction[0] ;
currentPoint.y = loaction[1] - DeviceUtils.getStatuBarHeight(getContext());
//獲取到控件剛傳入時(shí)候的位置,用于后面歸為的標(biāo)記
startPoint.x = loaction[0] ;
startPoint.y = loaction[1] - DeviceUtils.getStatuBarHeight(getContext());
this.bitmap = bitmap;
}
在onDraw方法中,繪制出相應(yīng)的圖片
??在繪制的時(shí)候,要注意直接繪制到(0,0)位置,然后再通過(guò)translate將圖片唯一到相應(yīng)的位置,這種實(shí)現(xiàn)方法有一個(gè)好處,就是在進(jìn)行計(jì)算的時(shí)候,非常簡(jiǎn)單;
??一開(kāi)始的時(shí)候我是想通過(guò)scaleY,縮放動(dòng)畫(huà)來(lái)實(shí)現(xiàn)這樣的效果,結(jié)果搞了一天,發(fā)現(xiàn)大小在視覺(jué)效果上非常好,但是在唯一和坐標(biāo)確定的計(jì)算上非常麻煩(當(dāng)然,數(shù)學(xué)已經(jīng)還給老師這樣的話我是不會(huì)亂說(shuō)的)
;
mPaint.setColor(Color.BLACK);
mPaint.setAlpha((int) ((int) (255*v)/maxScaleX));
canvas.drawRect(0,0,mWidth,mHeight,mPaint);
canvas.save();
canvas.translate(currentPoint.x, currentPoint.y);
Bitmap bitmap = creatBitmap(this.bitmap, viewRect);
canvas.drawBitmap(bitmap,0, 0, null);
canvas.restore();
很明顯,繪制過(guò)程非常簡(jiǎn)單,一個(gè)簡(jiǎn)單的繪制背景和圖片操作,背景是不會(huì)改變的,圖片則會(huì)隨著一些動(dòng)作,比如拖拽,動(dòng)畫(huà)等效果來(lái)改變;
??creatBitmap(this.bitmap, viewRect),這個(gè)方法也是非常簡(jiǎn)單的,沒(méi)有什么技術(shù)那點(diǎn),但是為了防止圖片變形,我還是做了一些小小的限制,讓然,一般情況下是沒(méi)有問(wèn)題的;
private Bitmap creatBitmap(Bitmap bitmap, Rect viewRect) {
float width = viewRect.width();
float height = width * (bitmap.getHeight() * 1.0f / bitmap.getWidth());
return Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, true);
}
剩下的就是對(duì)onDraw方法里面用到的參數(shù)進(jìn)行操作了;
由于這個(gè)控件涉及到了單擊、雙擊、長(zhǎng)按、拖拽等操作,所以我直接使用了手勢(shì)GestureDetector來(lái)輔助操作矩肩;
首先是拖拽,代碼里面寫(xiě)的就非常清楚了,就是隨之手指的移動(dòng),不斷的更改圖片的大小和位置參數(shù),然后 postInvalidate();更新下UI就好了
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!isSacel) {
//手指移動(dòng)距離
distanceY = e2.getRawY() - e1.getRawY();
distanceX = e2.getRawX() - e1.getRawX();
if (distanceY > Math.abs(distanceX) && Math.abs(distanceY) > DeviceUtils.getMinTouchSlop(getContext())) {
isCanDrag = true;
}
if (isCanDrag) {
//滑動(dòng)造成的縮放倍數(shù)
float abs = Math.abs((mHeight - distanceY) * maxScaleX / mHeight);
abs = abs > maxScaleX ? maxScaleX : (abs < minScaleX ? minScaleX : abs);
//當(dāng)前顯示圖片的寬高
float width = (startRect.width() * abs);
float height = (startRect.height() * abs);
//防止圖片變形進(jìn)行的操作
double v = bitmap.getWidth() * 1.0 / bitmap.getHeight();
float endTranX = 0;
float endTranY = 0;
if (mWidth/mHeight> v){
width = (float) (height*v);
endTranX =(mWidth-width)/2;
}else {
height = (float) (width/v);
endTranY=(mHeight-height)/2;
}
//更改對(duì)應(yīng)參數(shù)
currentPoint.x = distanceX + endTranX;
currentPoint.y = distanceY+endTranY;
viewRect.right = (int) width;
viewRect.bottom = (int) height;
postInvalidate();
}
} else {
float y = -distanceY*doubliScale + getTranslationY();
float x = -distanceX*doubliScale + getTranslationX();
setTranslationY(y);
setTranslationX(x);
}
return true;
}
這樣,一個(gè)位移縮放功能就完成,由于一開(kāi)始已經(jīng)記錄下來(lái)了圖片的原始數(shù)據(jù),在歸為的時(shí)候只要使用動(dòng)畫(huà)歸為就行了,這個(gè)比較簡(jiǎn)單,代碼我就不放了;
最后:附上源碼