1. 程式人生 > >Android使用RecycleView實現拖拽交換item位置

Android使用RecycleView實現拖拽交換item位置

本文例項為大家分享了RecycleView實現拖拽交換item位置的具體程式碼,供大家參考,具體內容如下

老規矩,先來一張效果圖:

相比起ListView而言,RecycleView實現拖拽交換位置的效果要簡單很多,因為通過SDK中的ItemTouchHelper工具類可以輕鬆的實現這種效果,並且一套程式碼支援所有佈局方式;而ListView的話則需要通過生成View的快取映象設定到ImageView中,然後通過WindowManager來操作該ImageView,具體怎麼實現這裡就不展開講解了.迴歸到ItemTouchHelper話題上,這個工具類我們需要關心的方法只有一個,即:

?
1 public void attachToRecyclerView( @Nullable RecyclerView recyclerView) {}

通過名字也可以知道其作用就是和RecyclerView 建立關係.
而我們真正需要關心的地方就是ItemTouchHelper的內部類ItemTouchHelper.Callback,它是一個抽象類,需要我們去實現下面這幾個關鍵的抽象方法以及重寫幾個非抽象的方法:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //決定拖拽/滑動的方向 public abstract int getMovementFlags(RecyclerView recyclerView,          ViewHolder viewHolder);   //和位置交換有關,可用於實現drag功能 public abstract boolean onMove(RecyclerView recyclerView,          ViewHolder viewHolder, ViewHolder target);   //和滑動有關,可用於實現swipe功能 public abstract void onSwiped(ViewHolder viewHolder, int direction);   //是否長按啟用拖拽功能,預設是true public boolean isLongPressDragEnabled() { return true ;}   //是否支援滑動,預設true public boolean isItemViewSwipeEnabled() { return true ;}   //和目標View的狀態改變有關,例如drag,swipe,ide public void onSelectedChanged(ViewHolder viewHolder, int actionState) {}   //和移除View的狀態有關,通常用於清除在onSelectedChanged,onChildDraw中對View設定的動畫 public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {}

當建立完ItemTouchHelper.Callback的實現類,我這裡稱之為SimpleItemTouchHelperCallback後,還需要將資料的變化以及View的狀態通知到RecycleView的Adapter中,為了達到解耦的目的,通常可以通過定義介面來實現,在SimpleItemTouchHelperCallback的構造方法中傳入該解耦介面的引用,並讓RecycleView的Adapter實現該解耦的介面,這樣就實現了這2個類的通訊問題了.

來看看我定義的解耦介面:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /**   * 定義RecycleView的Adapter和SimpleItemTouchHelperCallback直接互動的介面方法   * Created by mChenys on 2017/2/16.   */ public interface ItemTouchHelperAdapter {      //資料交換    void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target);      //資料刪除    void onItemDissmiss(RecyclerView.ViewHolder source);      //drag或者swipe選中    void onItemSelect(RecyclerView.ViewHolder source);      //狀態清除    void onItemClear(RecyclerView.ViewHolder source); }

完整的SimpleItemTouchHelperCallback程式碼如下:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 4 /**   * 處理RecycleView的選中,拖拽移動,拖拽刪除的實現類   * Created by mChenys on 2017/2/16.   */ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {      private ItemTouchHelperAdapter mAdapter;      public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {      mAdapter = adapter;    }      @Override    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {      //int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //允許上下的拖動      //int dragFlags =ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; //允許左右的拖動      //int swipeFlags = ItemTouchHelper.LEFT; //只允許從右向左側滑      //int swipeFlags = ItemTouchHelper.DOWN; //只允許從上向下側滑      //一般使用makeMovementFlags(int,int)或makeFlag(int, int)來構造我們的返回值      //makeMovementFlags(dragFlags, swipeFlags)        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; //允許上下左右的拖動      return makeMovementFlags(dragFlags, 0 );    }      @Override    public boolean isLongPressDragEnabled() {      return true ; //長按啟用拖拽    }      @Override    public boolean isItemViewSwipeEnabled() {      return false ; //不啟用拖拽刪除    }      @Override    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {      //通過介面傳遞拖拽交換資料的起始位置和目標位置的ViewHolder      mAdapter.onItemMove(source, target);      return true ;    }        @Override    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {      //移動刪除回撥,如果不用可以不用理      // mAdapter.onItemDissmiss(viewHolder);    }      @Override    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {      super .onSelectedChanged(viewHolder, actionState);      if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {        //當滑動或者拖拽view的時候通過介面返回該ViewHolder        mAdapter.onItemSelect(viewHolder);      }    }      @Override    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {      super .clearView(recyclerView, viewHolder);      if (!recyclerView.isComputingLayout()) {        //當需要清除之前在onSelectedChanged或者onChildDraw,onChildDrawOver設定的狀態或者動畫時通過介面返回該ViewHolder        mAdapter.onItemClear(viewHolder);      }    } }

RecycleView.Adapter實現類程式碼

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 /**   * Created by mChenys on 2017/2/15.   */ public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements ItemTouchHelperAdapter {    ...      @Override    public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {     ...    }      @Override    public void onBindViewHolder( final MyAdapter.MyViewHolder holder, int position) {      ...    }      @Override    public int getItemCount() {      //注意:這裡最少有一個,因為有多了一個新增按鈕      return null == mData ? 1 : mData.size() + 1 ;    }      @Override    public void onItemMove(RecyclerView.ViewHolder source,     RecyclerView.ViewHolder target) {      int fromPosition = source.getAdapterPosition();      int toPosition = target.getAdapterPosition();      if (fromPosition < mData.size() && toPosition < mData.size()) {        //交換資料位置        Collections.swap(mData, fromPosition, toPosition);        //重新整理位置交換        notifyItemMoved(fromPosition, toPosition);      }      //移動過程中移除view的放大效果      onItemClear(source);    }      @Override    public void onItemDissmiss(RecyclerView.ViewHolder source) {        int position = source.getAdapterPosition();      mData.remove(position); //移除資料      notifyItemRemoved(position); //重新整理資料移除    }      @Override    public void onItemSelect(RecyclerView.ViewHolder viewHolder) {        //當拖拽選中時放大選中的view      viewHolder.itemView.setScaleX( 1 .2f);      viewHolder.itemView.setScaleY( 1 .2f);    }      @Override    public void onItemClear(RecyclerView.ViewHolder viewHolder) {        //拖拽結束後恢復view的狀態      viewHolder.itemView.setScaleX( 1 .0f);      viewHolder.itemView.setScaleY( 1 .0f);    }      public class MyViewHolder extends RecyclerView.ViewHolder {     ...        public MyViewHolder(View itemView) {        super (itemView);       ...      }    }   }

MainActivity的使用方式

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 /**   * Created by mChenys on 2017/2/16.   */ public class MainActivity extends AppCompatActivity {    ...    @Override    protected void onCreate(Bundle savedInstanceState) {      super .onCreate(savedInstanceState);      ...      mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);      //建立adapter      MyAdapter myAdapter = new MyAdapter( this , mData);      //設定預設的佈局方式      mRecyclerView.setLayoutManager( new LinearLayoutManager( this , LinearLayoutManager.VERTICAL, false ));      //設定adapter      mRecyclerView.setAdapter(myAdapter);      //建立SimpleItemTouchHelperCallback      ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(myAdapter);      //用Callback構造ItemtouchHelper      ItemTouchHelper touchHelper = new ItemTouchHelper(callback);      //呼叫ItemTouchHelper的attachToRecyclerView方法建立聯絡      touchHelper.attachToRecyclerView(mRecyclerView);    }          @Override    public boolean onCreateOptionsMenu(Menu menu) {      ...      return super .onCreateOptionsMenu(menu);    }      @Override    public boolean onOptionsItemSelected(MenuItem item) {      ...      return super .onOptionsItemSelected(item);    }   } 錯誤解決方法
configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion '25.3.0'
            }
        }
   &nbs