本文同步自wing的地方酒館
《互動炸了》或許是一系列高階特效教程, 文中會介紹一些比較炫酷的特效,以及實現的思路。特效實現本身也許不會有太大的難度。難點在於實現的思路。一旦思路被開啟,特效將很簡單實現。
DragPhotoView專案地址github.com/githubwing/…
大家好,本期是互動炸了第四期~ 本期帶來的效果是最新版微信朋友圈看圖下拖的效果,沒見過的趕緊去更新微信啦~~
本期跟以往不一樣:
不是demo! 拿來直接用!不是demo! 拿來直接用!不是demo! 拿來直接用!重要說三你懂.
效果圖如下:
自我感覺實現的效果還不錯哈.猛地一看自己都以為他就是微信了哈哈.
一分鐘使用方式:
修改你的 build.gradle
檔案
//root project
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
//module project
dependencies {
compile 'com.github.githubwing:DragPhotoView:1.0.1'
}複製程式碼
把它放到xml裡
把它當成普通ImageView使用就行了,所有ImageView的玩法都可以在它身上玩.注意必須要加一個onExitListener,這是在拖拽出範圍的監聽.
// 所有ImageView用法都可以
DragPhotoView photoView = (DragPhotoView)findViewById(R.id.photoView);
photoView.setImageResource(R.drawable.ram);
//必須新增一個onExitListener,在拖拽到底部時觸發.
photoView.setOnExitListener()
photoView.setOnTapListener()複製程式碼
這樣就完成了接入,甚至比一分鐘還快有沒有!拒絕標題黨.
上面講解的是用法,可是用誰都會,使用一個三方庫,都要了解實現對不? 下面就給大家介紹實現的思路.
實現
基於PhotoView
第一眼看到這個效果,就有想實現的衝動,因為使用場景挺多的感覺. 所以直接找來GitHub上star最多的PhotoView來進行擴充套件,這裡我選擇直接依賴並且繼承PhotoView,理由是如果PhotoView出了更新,依賴直接改動版本即可.如果我選擇原始碼copy的方式改動,那麼將得不到PhotoView的支援.
圖片縮放,背景透明
這裡需要Activity配合,將背景設定為透明.並且背景實黑色的,為了配合手勢改變View背景透明度,我繪製一個超大的矩形充當背景:
@Override
protected void onDraw(Canvas canvas) {
mPaint.setAlpha(mAlpha);
canvas.drawRect(0, 0, 2000, 2000, mPaint);
canvas.translate(mTranslateX, mTranslateY);
canvas.scale(mScale, mScale, mWidth / 2, mHeight / 2);
super.onDraw(canvas);
}複製程式碼
畫布位移和縮放還有透明度都跟著手勢變化而變化.所以要處理觸控事件,一開始我嘗試重寫onTouchEvent方法,發現並不生效,原因是PhotoView內部使用了自己的手勢處理機制. 所以手勢處理束手無策裡嗎? 非也,我們可以在dispatchTouchEvent做處理.所以重寫該方法:
首先判斷是否處於縮放模式,只有非縮放模式的時候才可以拖拽
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (getScale() == 1) {
}
}複製程式碼
之後處理ACTION_MOVE事件:
需要注意的是,要解決一下Viewpager和DragPhotoView和PhotoView的衝突.
DragPhotoView和PhotoView的衝突在於手勢縮放,所以只要判斷一下當前是幾個觸控點即可.
下Viewpager和DragPhotoView衝突在左右滑,所以這裡判斷為:如果沒有向下移動過,則Y位移為0交由ViewPager處理,如果向下移動過,則改變標誌位說明正在處於拖拽狀態
case MotionEvent.ACTION_MOVE:
//in viewpager
if (mTranslateY == 0 && mTranslateX != 0) {
//如果不消費事件,則不作操作
if (!isTouchEvent) {
mScale = 1;
return super.dispatchTouchEvent(event);
}
}
//single finger drag down
if (mTranslateY >= 0 && event.getPointerCount() == 1) {
onActionMove(event);
//如果有上下位移 則不交給viewpager
if (mTranslateY != 0) {
isTouchEvent = true;
}
return true;
}
//防止下拉的時候雙手縮放
if (mTranslateY >= 0 && mScale < 0.95) {
return true;
}
break;複製程式碼
在ACTION_UP的時候,要判斷一下是否拖拽超過閥值,如果超過了閥值則進行結束Activity操作.
這裡遇到個坑就是,單指返回和雙擊放大手勢衝突了.目前沒有找到什麼好的解決方法,只能開啟執行緒計時來根據標誌位判斷,各位看官有好的解決方式,請聯絡告知我,謝謝!
case MotionEvent.ACTION_UP:
//防止下拉的時候雙手縮放
if (event.getPointerCount() == 1) {
onActionUp(event);
isTouchEvent = false;
//judge finish or not
postDelayed(new Runnable() {
@Override
public void run() {
if (mTranslateX == 0 && mTranslateY == 0 && canFinish) {
if (mTapListener != null) {
mTapListener.onTap(DragPhotoView.this);
}
}
canFinish = false;
}
}, 300);
}複製程式碼
這樣基本上就完成了對PhotoView的擴充套件. 已經可以接入專案中使用了.
但是本文還沒有完,下面說一下共享元素的全版本實現
Android自帶的共享元素只有5.0以上才可以使用.那麼怎麼相容到5.0以下呢.並且Demo中的拖拽共享是怎麼實現的呢?
其實思路很簡單,只需要在Activity A啟動Activity B的時候,關閉系統專場動畫,把被點選的View 大小,座標等資訊傳入. B先為透明狀態,把B上的View做一個位移動畫,就可以實現了.
public void startPhotoActivity(Context context, ImageView imageView) {
Intent intent = new Intent(context, DragPhotoActivity.class);
int location[] = new int[2];
imageView.getLocationOnScreen(location);
intent.putExtra("left", location[0]);
intent.putExtra("top", location[1]);
intent.putExtra("height", imageView.getHeight());
intent.putExtra("width", imageView.getWidth());
context.startActivity(intent);
//關閉系統共享元素動畫
overridePendingTransition(0,0);
}複製程式碼
至於拖拽共享元素,原理是一樣的,具體的細節就在demo中啦~~
本文到此就結束啦~
DragPhotoView專案地址github.com/githubwing/…
如果你覺得不錯,歡迎Star,也可以加入我的Android酒館:425983695