本文已受權微信公衆號:鴻洋(hongyangAndroid)原創首發java
《交互炸了》或許是一系列高端特效教程, 文中會介紹一些比較炫酷的特效,以及實現的思路。特效實現自己也許不會有太大的難度。難點在於實現的思路。一旦思路被打開,特效將很簡單實現。git
DragPhotoView項目地址https://github.com/githubwing/DragPhotoViewgithub
你們好,本期是交互炸了第四期~ 本期帶來的效果是最新版微信朋友圈看圖下拖的效果,沒見過的趕忙去更新微信啦~~canvas
效果圖以下:微信
自我感受實現的效果還不錯哈.猛地一看本身都覺得他就是微信了哈哈.markdown
build.gradle
文件//root project
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
//module project
dependencies {
compile 'com.github.githubwing:DragPhotoView:1.0.1'
}
把它當成普通ImageView使用就好了,全部ImageView的玩法均可以在它身上玩.注意必需要加一個onExitListener,這是在拖拽出範圍的監聽.maven
// 全部ImageView用法均可以
DragPhotoView photoView = (DragPhotoView)findViewById(R.id.photoView);
photoView.setImageResource(R.drawable.ram);
//必須添加一個onExitListener,在拖拽到底部時觸發.
photoView.setOnExitListener()
photoView.setOnTapListener()
上面講解的是用法,但是用誰都會,使用一個三方庫,都要了解實現對不? 下面就給你們介紹實現的思路.ide
第一眼看到這個效果,就有想實現的衝動,由於使用場景挺多的感受. 因此直接找來GitHub上star最多的PhotoView來進行擴展,這裏我選擇直接依賴而且繼承PhotoView,理由是若是PhotoView出了更新,依賴直接改動版本便可.若是我選擇源碼copy的方式改動,那麼將得不到PhotoView的支持.post
這裏須要Activity配合,將背景設置爲透明.而且背景實黑色的,爲了配合手勢改變View背景透明度,我繪製一個超大的矩形充當背景:gradle
@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項目地址https://github.com/githubwing/DragPhotoView
若是你以爲不錯,歡迎Star 也能夠加入個人Android酒館:425983695