本文是MultiItem系列的擴展文章,跨RecyclerView的Item拖動,並支持縮放的功能,主要防辦公軟件的面板,本功能的實現大量參考了ItemTouchHelper
的源碼。
MutliItem主要解決多類型RecyclerView Adapter問題,在正常使用中作到了Adapter零編碼,解放了複雜的Adapter類,提升擴展性。java
Github地址:github.com/free46000/M…,請你們多多關注,更多更新會首先在GitHub上體現,也會在第一時間在本平臺發佈。 git
拖動功能使用比較簡單,拖動功能相關流程和控制都會回調到ItemDragListener
監聽中。
實例化拖動輔助類,設置監聽,並在dispatchTouchEvent
中調用dragHelper.onTouch(ev)
方法github
@Override
protected void onCreate(Bundle savedInstanceState) {
...
//ItemDragHelper,須要傳入外層的橫向滾動的RecyclerView
dragHelper = new ItemDragHelper(horizontalRecycler);
//爲dragHelper設置拖動監聽,基本都有默認實現,可根據具體業務繼承重寫方法
dragHelper.setOnItemDragListener(new OnBaseDragListener());
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//須要保證在Activity或者外層的ViewGroup中重寫此方法
//調用dragHelper.onTouch():true消耗掉事件;false則執行super
return dragHelper.onTouch(ev) || super.dispatchTouchEvent(ev);
}複製代碼
爲垂直列表註冊數據源,必須實現ItemData
接口ide
//註冊的數據源(TextDragBean)類,必須實現`ItemData`接口
baseItemAdapter.register(TextDragBean.class, new TextViewDragManager());複製代碼
開啓拖動功能佈局
dragHelper.startDrag(viewHolder);複製代碼
拖動監聽,此處只複寫了拖動結束回調的接口post
class OnBaseDragListener extends OnItemDragListener {
@Override
public void onDragFinish(RecyclerView recyclerView, int itemRecyclerPos, int itemPos) {
super.onDragFinish(recyclerView, itemRecyclerPos, itemPos);
String text = String.format("拖動起始第%s個列表的第%s項 結束第%s個列表的第%s項 \n\n拖動數據:%s", originalRecyclerPosition,
originalItemPosition, itemRecyclerPos, itemPos, dragItemData);
Toast.makeText(PanelActivity.this, text, Toast.LENGTH_SHORT).show();
}
}複製代碼
主要包括對Item的拖動、移動、切換的控制功能,數據源須要實現ItemDrag
接口,這樣在拖動過程當中OnItemDragListener
會根據不一樣的狀態進行對應的控制。
固然你也能夠經過OnBaseDragListener
的不一樣回調方法,根據業務實現定製化的控制,這裏咱們看下ItemDrag
接口:動畫
/** * 數據源Item拖動接口,實現一些move change等定製化的通用控制 * Created by free46000 on 2017/4/3. */
public interface ItemDrag {
/** * 是否能夠在本身的Recycler中move * * @return boolean */
boolean isCanMove();
/** * 是否能夠切換到其餘Recycler * * @return boolean */
boolean isCanChangeRecycler();
/** * 是否能夠開啓拖動 * * @return boolean */
boolean isCanDrag();
}複製代碼
實例化輔助類併爲輔助類設置須要的視圖對象this
//實例化縮放功能輔助類
scaleHelper = new ViewScaleHelper();
//設置最外層的Content視圖
scaleHelper.setContentView(contentView);
//設置橫向的Recycler列表視圖
scaleHelper.setHorizontalView(horizontalRecycler);複製代碼
添加外層的垂直視圖到輔助類,進行縮放統一管理編碼
scaleHelper.addVerticalView(verticalView);複製代碼
在OnItemDragListener
的回調中返回當前縮放級別,配合完成縮放後的拖動功能spa
class OnBaseDragListener extends OnItemDragListener {
@Override
public float getScale() {
return scaleHelper.isInScaleMode() ? scaleHelper.getScale() : super.getScale();
}
}複製代碼
開啓或關閉縮放功能
//開啓或關閉縮放模式
scaleHelper.toggleScaleModel();
//開啓縮放模式
scaleHelper.startScaleModel();
//關閉縮放模式
scaleHelper.stopScaleModel();複製代碼
定製化業務主要經過複寫ItemDragListener
的相關方法實現,下面簡單列舉一些可定製的功能:
getScale()
縮放比例詳見ViewScaleHelper#getScale()
getHorizontalScrollMaxSpeed
getVerticalScrollMaxSpeed
最大水平垂直滾動速度getHorizontalLimit
getVerticalLimit
計算水平垂直滾動距離calcHorizontalScrollDistance
calcVerticalScrollDistance
最大水平垂直滾動速度onDrawFloatView(View floatView)
浮動視圖動畫處理getMoveLimit()
兩個Item是否進行move邊界值上面所介紹定製化用法並非所有,若有須要更深層次定製能夠提交issues或留言
備註:如下所說觸摸位置都爲相對屏幕位置,這樣方便後續計算
被拖動Item視圖設爲不可見狀態,浮動視圖採用WindowManager + ImageView
展現被拖動Item視圖的Bitmap
ItemTouchHelper
的源碼ItemDragListener
的calcXXXScrollDistance()
calcScrollXXXDirect()
horizontalRecycler.findChildViewUnder(x, y)
找到垂直recyclerView
的位置,若找到位置繼續recyclerView
所在的位置,判斷是否爲第一次選中或者是切換recyclerView
的操做,此處可經過itemDragListener
回調攔截這次操做的結果recyclerView
的位置,此時須要對被拖動的Item進行remove
,並在新的recyclerView
中add
進去recyclerView.findChildViewUnder(itemX, itemY)
找到itemView
的位置itemView
所在的位置,判斷是否須要移動itemView
位置的操做,此處可經過itemDragListener
回調攔截這次操做的結果itemView
位置則須要把recyclerView
滾動到合適的位置,防recyclerView
亂跳視圖縮放採用的是把外層的視圖還有橫向列表視圖擴大,並對橫向列表視圖進行setScaleX setScaleY
的操做,而後對縮放後的視圖寬度進行賦值,防止一些充滿屏幕的佈局,影響縮放效果,等中止縮放的時候還原便可。
這個功能實現起來比較倉促,並無過多的考慮,算是一個beta版本。以上整理了用法,並對主要流程作了簡單的解析,若是你們有興趣能夠結合源碼理解原理,若有不明白,或者實現不夠優雅的地方,歡迎你們指出。