摘要:當在移動之前,獲取拖拽的方向。只能左右滑動刪除。具體實現如下當移動的時候。現在的第條被刪除。為了實現滑動菜單的功能,定義了。
LRecyclerView能做什么?
如果你之前沒有聽說過LRecyclerView,那么請參考:
Android LRecyclerView實現下拉刷新,滑動到底部自動加載更多
經過再三思考,同時也為了大家使用方便,LRecyclerView集成了SwipeMenu系列功能,包括Item側滑菜單、長按拖拽Item,滑動刪除Item等功能。
demo apk下載地址:點我下載
功能演示本次新增SwipeMenu系列功能描述如下:
左右兩側都有菜單;
根據ViewType顯示菜單;
長按拖拽Item(List),與菜單結合;
長按拖拽Item(Grid);
滑動刪除Item;
指定某個Item不能拖拽或者不能滑動刪除;
用SwipeMenuLayout實現你自己的側滑。
項目地址:https://github.com/jdsjlzx/LR...
SwipeMenuAdapter為了實現SwipeMenu的功能,此次新增了一個SwipeMenuAdapter類。
SwipeMenuAdapter與library中已經存在的LRecyclerViewAdapter會不會沖突呢?答案是不會。SwipeMenuAdapter是用戶級別的基類adapter,也就是用戶需要繼承SwipeMenuAdapter去實現自己的adapter,還像之前那樣使用即可。
SwipeMenuAdapter類的定義:
public abstract class SwipeMenuAdapterextends RecyclerView.Adapter
實現自己的MenuAdapter:
public class MenuAdapter extends SwipeMenuAdapter{ protected List mDataList = new ArrayList<>(); public MenuAdapter() { } @Override public int getItemCount() { return mDataList.size(); } public List getDataList() { return mDataList; } public void setDataList(Collection list) { this.mDataList.clear(); this.mDataList.addAll(list); notifyDataSetChanged(); } public void addAll(Collection list) { int lastIndex = this.mDataList.size(); if (this.mDataList.addAll(list)) { notifyItemRangeInserted(lastIndex, list.size()); } } public void remove(int position) { mDataList.remove(position); notifyItemRemoved(position); if(position != mDataList.size()){ // 如果移除的是最后一個,忽略 notifyItemRangeChanged(position, mDataList.size() - position); } } public void clear() { mDataList.clear(); notifyDataSetChanged(); } @Override public View onCreateContentView(ViewGroup parent, int viewType) { return LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_text_swipe, parent, false); } @Override public MenuAdapter.DefaultViewHolder onCompatCreateViewHolder(View realContentView, int viewType) { return new DefaultViewHolder(realContentView); } @Override public void onBindViewHolder(MenuAdapter.DefaultViewHolder holder, int position) { String item = mDataList.get(position).title; DefaultViewHolder viewHolder = holder; viewHolder.tvTitle.setText(item); } static class DefaultViewHolder extends RecyclerView.ViewHolder { TextView tvTitle; public DefaultViewHolder(View itemView) { super(itemView); tvTitle = (TextView) itemView.findViewById(R.id.tv_title); } } }
是不是很方便?MenuAdapter基本的功能都滿足了,直接拷貝到項目中即可使用。
上面說了那么多,關鍵的也就這幾句:
mDataAdapter = new MenuAdapter(); mDataAdapter.setDataList(dataList); mLRecyclerViewAdapter = new LRecyclerViewAdapter(this, mDataAdapter); mRecyclerView.setAdapter(mLRecyclerViewAdapter);
下面具體分析每個功能。
左右兩側都有菜單效果圖:
具體使用步驟如下。
為SwipeRecyclerView的Item創建菜單
// 設置菜單創建器。 mRecyclerView.setSwipeMenuCreator(swipeMenuCreator); //設置菜單Item點擊監聽事件 mRecyclerView.setSwipeMenuItemClickListener(menuItemClickListener);
其中swipeMenuCreator和menuItemClickListener代碼如下:
/** * 菜單創建器。在Item要創建菜單的時候調用。 */ private SwipeMenuCreator swipeMenuCreator = new SwipeMenuCreator() { @Override public void onCreateMenu(SwipeMenu swipeLeftMenu, SwipeMenu swipeRightMenu, int viewType) { int size = getResources().getDimensionPixelSize(R.dimen.item_height); // 添加左側的,如果不添加,則左側不會出現菜單。 { SwipeMenuItem addItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_green)// 點擊的背景。 .setImage(R.mipmap.ic_action_add) // 圖標。 .setWidth(size) // 寬度。 .setHeight(size); // 高度。 swipeLeftMenu.addMenuItem(addItem); // 添加一個按鈕到左側菜單。 SwipeMenuItem closeItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_red) .setImage(R.mipmap.ic_action_close) .setWidth(size) .setHeight(size); swipeLeftMenu.addMenuItem(closeItem); // 添加一個按鈕到左側菜單。 } // 添加右側的,如果不添加,則右側不會出現菜單。 { SwipeMenuItem deleteItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_red) .setImage(R.mipmap.ic_action_delete) .setText("刪除") // 文字,還可以設置文字顏色,大小等。。 .setTextColor(Color.WHITE) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(deleteItem);// 添加一個按鈕到右側側菜單。 SwipeMenuItem closeItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_purple) .setImage(R.mipmap.ic_action_close) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(closeItem); // 添加一個按鈕到右側菜單。 SwipeMenuItem addItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_green) .setText("添加") .setTextColor(Color.WHITE) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(addItem); // 添加一個按鈕到右側菜單。 } } }; /** * 菜單點擊監聽。 */ private OnSwipeMenuItemClickListener menuItemClickListener = new OnSwipeMenuItemClickListener() { /** * Item的菜單被點擊的時候調用。 * @param closeable closeable. 用來關閉菜單。 * @param adapterPosition adapterPosition. 這個菜單所在的item在Adapter中position。 * @param menuPosition menuPosition. 這個菜單的position。比如你為某個Item創建了2個MenuItem,那么這個position可能是是 0、1, * @param direction 如果是左側菜單,值是:SwipeMenuRecyclerView#LEFT_DIRECTION,如果是右側菜單,值是:SwipeMenuRecyclerView#RIGHT_DIRECTION. */ @Override public void onItemClick(Closeable closeable, int adapterPosition, int menuPosition, int direction) { closeable.smoothCloseMenu();// 關閉被點擊的菜單。 if (direction == LRecyclerView.RIGHT_DIRECTION) { Toast.makeText(mContext, "list第" + adapterPosition + "; 右側菜單第" + menuPosition, Toast.LENGTH_SHORT).show(); } else if (direction == LRecyclerView.LEFT_DIRECTION) { Toast.makeText(mContext, "list第" + adapterPosition + "; 左側菜單第" + menuPosition, Toast.LENGTH_SHORT).show(); } } };
從上面代碼可以看出,swipeMenuCreator完成了左右菜單的創建,menuItemClickListener實現了菜單的點擊事件。
需要注意的是,LRecyclerView提供了下面兩個方法,具體使用請詳見demo。
public void openLeftMenu(int position, int duration) { openMenu(position, LEFT_DIRECTION, duration); } public void openRightMenu(int position) { openMenu(position, RIGHT_DIRECTION, SwipeMenuLayout.DEFAULT_SCROLLER_DURATION); }
openLeftMenu:打開item的左邊菜單
openRightMenu:打開item的右邊菜單
這里關鍵的就是這個position(詳細請參考demo),先埋下個伏筆,后面介紹。
根據ViewType顯示菜單效果圖:
根據ViewType決定SwipeMenu在哪一行出現,可以左側,可以右側。
自定義MenuViewTypeAdapter,代碼如下:
public class MenuViewTypeAdapter extends MenuAdapter { public static final int VIEW_TYPE_MENU = 1; public static final int VIEW_TYPE_NONE = 2; @Override public int getItemViewType(int position) { return position % 2 == 0 ? VIEW_TYPE_MENU : VIEW_TYPE_NONE; } }
在實現swipeMenuCreator 時,需要根據ItemViewType值來決定是否創建左右菜單。
private SwipeMenuCreator swipeMenuCreator = new SwipeMenuCreator() { @Override public void onCreateMenu(SwipeMenu swipeLeftMenu, SwipeMenu swipeRightMenu, int viewType) { // 根據Adapter的ViewType來決定菜單的樣式、顏色等屬性、或者是否添加菜單。 if (viewType == MenuViewTypeAdapter.VIEW_TYPE_NONE) { // Do nothing. } else if (viewType == MenuViewTypeAdapter.VIEW_TYPE_MENU) { int size = getResources().getDimensionPixelSize(R.dimen.item_height); ...... } } };長按拖拽Item(List),與菜單結合
效果圖:
關鍵代碼:
mRecyclerView.setLongPressDragEnabled(true);// 開啟拖拽功能 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監聽拖拽,更新UI。
onItemMoveListener具體如下:
/** * 當Item移動的時候。 */ private OnItemMoveListener onItemMoveListener = new OnItemMoveListener() { @Override public boolean onItemMove(int fromPosition, int toPosition) { final int adjFromPosition = mLRecyclerViewAdapter.getAdapterPosition(true, fromPosition); final int adjToPosition = mLRecyclerViewAdapter.getAdapterPosition(true, toPosition); // 當Item被拖拽的時候。 Collections.swap(mDataAdapter.getDataList(), adjFromPosition, adjToPosition); //Be carefull in here! mLRecyclerViewAdapter.notifyItemMoved(fromPosition, toPosition); return true;// 返回true表示處理了,返回false表示你沒有處理。 } @Override public void onItemDismiss(int position) { // 當Item被滑動刪除掉的時候,在這里是無效的,因為這里沒有啟用這個功能。 // 使用Menu時就不用使用這個側滑刪除啦,兩個是沖突的。 } };
注意下面代碼:
final int adjFromPosition = mLRecyclerViewAdapter.getAdapterPosition(true, fromPosition); final int adjToPosition = mLRecyclerViewAdapter.getAdapterPosition(true, toPosition);
關于position的位置,為了大家使用方便,特在LRecyclerViewAdapter中提供了一個方法getAdapterPosition(boolean isCallback, int position)。
isCallback 含義:position是否接口回調中帶來的
position 含義:如果不是接口回調,就是用戶自己指定的position
getAdapterPosition(boolean isCallback, int position)只用于非LRecyclerViewAdapter提供的接口。
舉例說明:
setOnItemMoveListener不是 LRecyclerViewAdapter自帶接口(也就是內部方法),需要調用getAdapterPosition方法獲得正確的position
如setOnItemClickLitener 是 LRecyclerViewAdapter自帶接口,接口里面自帶了position,用戶就不必調用getAdapterPosition方法,直接使用就可以了。
mLRecyclerViewAdapter.setOnItemClickLitener(new OnItemClickLitener() { @Override public void onItemClick(View view, int position) { String text = "Click position = " + position; } @Override public void onItemLongClick(View view, int position) { } });長按拖拽Item(Grid)
效果圖:
與list功能一樣,只是布局不一樣。
滑動直接刪除Item效果圖:
注意:
滑動刪除和滑動菜單是互相沖突的,兩者只能出現一個。
關鍵代碼:
mRecyclerView.setLongPressDragEnabled(true); mRecyclerView.setItemViewSwipeEnabled(true);// 開啟滑動刪除 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監聽拖拽,更新UI
按照配置就可以實現滑動刪除。
指定某個Item不能拖拽或者不能滑動刪除效果圖:
關鍵代碼:
mRecyclerView.setLongPressDragEnabled(true); mRecyclerView.setItemViewSwipeEnabled(true);// 開啟滑動刪除。 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監聽拖拽,更新UI。 mRecyclerView.setOnItemMovementListener(onItemMovementListener);
其中,onItemMovementListener具體實現如下:
/** * 當Item被移動之前。 */ public static OnItemMovementListener onItemMovementListener = new OnItemMovementListener() { /** * 當Item在移動之前,獲取拖拽的方向。 * @param recyclerView {@link RecyclerView}. * @param targetViewHolder target ViewHolder. * @return */ @Override public int onDragFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder) { // 我們讓第一個不能拖拽 if (targetViewHolder.getAdapterPosition() == 0) { return OnItemMovementListener.INVALID;// 返回無效的方向。 } RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) {// 如果是LinearLayoutManager。 LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {// 橫向的List。 return OnItemMovementListener.LEFT | OnItemMovementListener.RIGHT; // 只能左右拖拽。 } else {// 豎向的List。 return OnItemMovementListener.UP | OnItemMovementListener.DOWN; // 只能上下拖拽。 } } else if (layoutManager instanceof GridLayoutManager) {// 如果是Grid。 return OnItemMovementListener.LEFT | OnItemMovementListener.RIGHT | OnItemMovementListener.UP | OnItemMovementListener.DOWN; // 可以上下左右拖拽。 } return OnItemMovementListener.INVALID;// 返回無效的方向。 } @Override public int onSwipeFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder) { // 我們讓第一個不能滑動刪除。 if (targetViewHolder.getAdapterPosition() == 0) { return OnItemMovementListener.INVALID;// 返回無效的方向。 } RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) {// 如果是LinearLayoutManager LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {// 橫向的List。 return OnItemMovementListener.UP | OnItemMovementListener.DOWN; // 只能上下滑動刪除。 } else {// 豎向的List。 return OnItemMovementListener.LEFT | OnItemMovementListener.RIGHT; // 只能左右滑動刪除。 } } return OnItemMovementListener.INVALID;// 其它均返回無效的方向。 } };
onItemMoveListener具體實現如下:
/** * 當Item移動的時候。 */ private OnItemMoveListener onItemMoveListener = new OnItemMoveListener() { @Override public boolean onItemMove(int fromPosition, int toPosition) { final int adjFromPosition = mLRecyclerViewAdapter.getAdapterPosition(true, fromPosition); final int adjToPosition = mLRecyclerViewAdapter.getAdapterPosition(true, toPosition); if (adjToPosition == 0) {// 保證第一個不被擠走。 return false; } // 當Item被拖拽的時候。 Collections.swap(mDataAdapter.getDataList(), adjFromPosition, adjToPosition); //Be carefull in here! mLRecyclerViewAdapter.notifyItemMoved(fromPosition, toPosition); return true; } @Override public void onItemDismiss(int position) { final int adjPosition = mLRecyclerViewAdapter.getAdapterPosition(true, position); mDataAdapter.remove(adjPosition); AppToast.showShortText(DragSwipeFlagsActivity.this, "現在的第" + adjPosition + "條被刪除。"); } };
通過代碼中的注釋,就可以明白了,一切盡在代碼中。
用SwipeMenuLayout實現你自己的側滑效果圖:
這個與LRecyclerView關系不大,但是與SwipeMenu關系密切。為了實現滑動菜單的功能,定義了SwipeMenuLayout。
SwipeMenuLayout類的定義:
public class SwipeMenuLayout extends FrameLayout implements SwipeSwitch
在開頭提到的SwipeMenuAdapter的
@Override public final VH onCreateViewHolder(ViewGroup parent, int viewType) { View contentView = onCreateContentView(parent, viewType); if (mSwipeMenuCreator != null) { SwipeMenuLayout swipeMenuLayout = (SwipeMenuLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_recyclerview_swipe_item_default, parent, false); ...... }
layout_recyclerview_swipe_item_default.xml
看來這個布局,你是不是有種恍然大悟的感覺呢?左右滑動就是通過SwipeMenuView來實現的。
項目地址:https://github.com/jdsjlzx/LR...,歡迎Star!
ThanksSwipeRecyclerView 作者:嚴振杰
別看他年齡小,也很牛啊!
如果你覺得這篇文章對你有用,那么贊一個或者留個言吧!
另外下載Demo有意外收獲啊!
如果你對LRecyclerView有什么好的想法或者建議,期待你的留言!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65018.html
摘要:支持復雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動,還可以支持粘貼頭部類似微信好友分組,支持不規則瀑布流效果,支持側滑刪除功能。十分方便實現復雜的布局頁面,結構上層次分明,便于維護。 目錄介紹 1.復雜頁面庫介紹 2.本庫優勢亮點 2.1 支持多種狀態切換管理 2.2 支持添加多個header和footer 2.3 支持側滑功能和拖拽移動 2.4 其他亮點介紹 3.如...
摘要:支持復雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動,還可以支持粘貼頭部類似微信好友分組,支持不規則瀑布流效果,支持側滑刪除功能。支持粘貼頭部的需求效果,這種效果類似微信好友分組的那種功能界面。 目錄介紹 1.復雜頁面庫介紹 2.本庫優勢亮點 2.1 支持多種狀態切換管理 2.2 支持添加多個header和footer 2.3 支持側滑功能和拖拽移動 2.4 其他亮點介紹 ...
摘要:系列,自定義實現知乎首頁仿今日頭條最強頂部導航指示器,支持種模式系列之一使用打造千變萬化的指示器優雅的為添加和實現快速滑動實現條目拖拽排序與滑動刪除高仿網易新聞首頁添加,刪除,排序類似大眾點評美團等應用的城市選擇器那些酷炫的開源庫整理 Material Design系列,自定義Behavior實現Android知乎首頁 showImg(http://img.blog.csdn.net/...
閱讀 519·2023-04-26 00:33
閱讀 3544·2021-11-24 09:39
閱讀 2930·2021-09-22 15:34
閱讀 2322·2019-08-23 18:07
閱讀 2917·2019-08-23 18:04
閱讀 3703·2019-08-23 16:06
閱讀 2899·2019-08-23 15:27
閱讀 1618·2019-08-23 14:32