摘要:當(dāng)在移動之前,獲取拖拽的方向。只能左右滑動刪除。具體實現(xiàn)如下當(dāng)移動的時候?,F(xiàn)在的第條被刪除。為了實現(xiàn)滑動菜單的功能,定義了。
LRecyclerView能做什么?
如果你之前沒有聽說過LRecyclerView,那么請參考:
Android LRecyclerView實現(xiàn)下拉刷新,滑動到底部自動加載更多
經(jīng)過再三思考,同時也為了大家使用方便,LRecyclerView集成了SwipeMenu系列功能,包括Item側(cè)滑菜單、長按拖拽Item,滑動刪除Item等功能。
demo apk下載地址:點我下載
功能演示本次新增SwipeMenu系列功能描述如下:
左右兩側(cè)都有菜單;
根據(jù)ViewType顯示菜單;
長按拖拽Item(List),與菜單結(jié)合;
長按拖拽Item(Grid);
滑動刪除Item;
指定某個Item不能拖拽或者不能滑動刪除;
用SwipeMenuLayout實現(xiàn)你自己的側(cè)滑。
項目地址:https://github.com/jdsjlzx/LR...
SwipeMenuAdapter為了實現(xiàn)SwipeMenu的功能,此次新增了一個SwipeMenuAdapter類。
SwipeMenuAdapter與library中已經(jīng)存在的LRecyclerViewAdapter會不會沖突呢?答案是不會。SwipeMenuAdapter是用戶級別的基類adapter,也就是用戶需要繼承SwipeMenuAdapter去實現(xiàn)自己的adapter,還像之前那樣使用即可。
SwipeMenuAdapter類的定義:
public abstract class SwipeMenuAdapterextends RecyclerView.Adapter
實現(xiàn)自己的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基本的功能都滿足了,直接拷貝到項目中即可使用。
上面說了那么多,關(guān)鍵的也就這幾句:
mDataAdapter = new MenuAdapter(); mDataAdapter.setDataList(dataList); mLRecyclerViewAdapter = new LRecyclerViewAdapter(this, mDataAdapter); mRecyclerView.setAdapter(mLRecyclerViewAdapter);
下面具體分析每個功能。
左右兩側(cè)都有菜單效果圖:
具體使用步驟如下。
為SwipeRecyclerView的Item創(chuàng)建菜單
// 設(shè)置菜單創(chuàng)建器。 mRecyclerView.setSwipeMenuCreator(swipeMenuCreator); //設(shè)置菜單Item點擊監(jiān)聽事件 mRecyclerView.setSwipeMenuItemClickListener(menuItemClickListener);
其中swipeMenuCreator和menuItemClickListener代碼如下:
/** * 菜單創(chuàng)建器。在Item要創(chuàng)建菜單的時候調(diào)用。 */ private SwipeMenuCreator swipeMenuCreator = new SwipeMenuCreator() { @Override public void onCreateMenu(SwipeMenu swipeLeftMenu, SwipeMenu swipeRightMenu, int viewType) { int size = getResources().getDimensionPixelSize(R.dimen.item_height); // 添加左側(cè)的,如果不添加,則左側(cè)不會出現(xiàn)菜單。 { SwipeMenuItem addItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_green)// 點擊的背景。 .setImage(R.mipmap.ic_action_add) // 圖標(biāo)。 .setWidth(size) // 寬度。 .setHeight(size); // 高度。 swipeLeftMenu.addMenuItem(addItem); // 添加一個按鈕到左側(cè)菜單。 SwipeMenuItem closeItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_red) .setImage(R.mipmap.ic_action_close) .setWidth(size) .setHeight(size); swipeLeftMenu.addMenuItem(closeItem); // 添加一個按鈕到左側(cè)菜單。 } // 添加右側(cè)的,如果不添加,則右側(cè)不會出現(xiàn)菜單。 { SwipeMenuItem deleteItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_red) .setImage(R.mipmap.ic_action_delete) .setText("刪除") // 文字,還可以設(shè)置文字顏色,大小等。。 .setTextColor(Color.WHITE) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(deleteItem);// 添加一個按鈕到右側(cè)側(cè)菜單。 SwipeMenuItem closeItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_purple) .setImage(R.mipmap.ic_action_close) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(closeItem); // 添加一個按鈕到右側(cè)菜單。 SwipeMenuItem addItem = new SwipeMenuItem(mContext) .setBackgroundDrawable(R.drawable.selector_green) .setText("添加") .setTextColor(Color.WHITE) .setWidth(size) .setHeight(size); swipeRightMenu.addMenuItem(addItem); // 添加一個按鈕到右側(cè)菜單。 } } }; /** * 菜單點擊監(jiān)聽。 */ private OnSwipeMenuItemClickListener menuItemClickListener = new OnSwipeMenuItemClickListener() { /** * Item的菜單被點擊的時候調(diào)用。 * @param closeable closeable. 用來關(guān)閉菜單。 * @param adapterPosition adapterPosition. 這個菜單所在的item在Adapter中position。 * @param menuPosition menuPosition. 這個菜單的position。比如你為某個Item創(chuàng)建了2個MenuItem,那么這個position可能是是 0、1, * @param direction 如果是左側(cè)菜單,值是:SwipeMenuRecyclerView#LEFT_DIRECTION,如果是右側(cè)菜單,值是:SwipeMenuRecyclerView#RIGHT_DIRECTION. */ @Override public void onItemClick(Closeable closeable, int adapterPosition, int menuPosition, int direction) { closeable.smoothCloseMenu();// 關(guān)閉被點擊的菜單。 if (direction == LRecyclerView.RIGHT_DIRECTION) { Toast.makeText(mContext, "list第" + adapterPosition + "; 右側(cè)菜單第" + menuPosition, Toast.LENGTH_SHORT).show(); } else if (direction == LRecyclerView.LEFT_DIRECTION) { Toast.makeText(mContext, "list第" + adapterPosition + "; 左側(cè)菜單第" + menuPosition, Toast.LENGTH_SHORT).show(); } } };
從上面代碼可以看出,swipeMenuCreator完成了左右菜單的創(chuàng)建,menuItemClickListener實現(xiàn)了菜單的點擊事件。
需要注意的是,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的右邊菜單
這里關(guān)鍵的就是這個position(詳細(xì)請參考demo),先埋下個伏筆,后面介紹。
根據(jù)ViewType顯示菜單效果圖:
根據(jù)ViewType決定SwipeMenu在哪一行出現(xiàn),可以左側(cè),可以右側(cè)。
自定義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; } }
在實現(xiàn)swipeMenuCreator 時,需要根據(jù)ItemViewType值來決定是否創(chuàng)建左右菜單。
private SwipeMenuCreator swipeMenuCreator = new SwipeMenuCreator() { @Override public void onCreateMenu(SwipeMenu swipeLeftMenu, SwipeMenu swipeRightMenu, int viewType) { // 根據(jù)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),與菜單結(jié)合
效果圖:
關(guān)鍵代碼:
mRecyclerView.setLongPressDragEnabled(true);// 開啟拖拽功能 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監(jiān)聽拖拽,更新UI。
onItemMoveListener具體如下:
/** * 當(dāng)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); // 當(dāng)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) { // 當(dāng)Item被滑動刪除掉的時候,在這里是無效的,因為這里沒有啟用這個功能。 // 使用Menu時就不用使用這個側(cè)滑刪除啦,兩個是沖突的。 } };
注意下面代碼:
final int adjFromPosition = mLRecyclerViewAdapter.getAdapterPosition(true, fromPosition); final int adjToPosition = mLRecyclerViewAdapter.getAdapterPosition(true, toPosition);
關(guān)于position的位置,為了大家使用方便,特在LRecyclerViewAdapter中提供了一個方法getAdapterPosition(boolean isCallback, int position)。
isCallback 含義:position是否接口回調(diào)中帶來的
position 含義:如果不是接口回調(diào),就是用戶自己指定的position
getAdapterPosition(boolean isCallback, int position)只用于非LRecyclerViewAdapter提供的接口。
舉例說明:
setOnItemMoveListener不是 LRecyclerViewAdapter自帶接口(也就是內(nèi)部方法),需要調(diào)用getAdapterPosition方法獲得正確的position
如setOnItemClickLitener 是 LRecyclerViewAdapter自帶接口,接口里面自帶了position,用戶就不必調(diào)用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效果圖:
注意:
滑動刪除和滑動菜單是互相沖突的,兩者只能出現(xiàn)一個。
關(guān)鍵代碼:
mRecyclerView.setLongPressDragEnabled(true); mRecyclerView.setItemViewSwipeEnabled(true);// 開啟滑動刪除 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監(jiān)聽拖拽,更新UI
按照配置就可以實現(xiàn)滑動刪除。
指定某個Item不能拖拽或者不能滑動刪除效果圖:
關(guān)鍵代碼:
mRecyclerView.setLongPressDragEnabled(true); mRecyclerView.setItemViewSwipeEnabled(true);// 開啟滑動刪除。 mRecyclerView.setOnItemMoveListener(onItemMoveListener);// 監(jiān)聽拖拽,更新UI。 mRecyclerView.setOnItemMovementListener(onItemMovementListener);
其中,onItemMovementListener具體實現(xiàn)如下:
/** * 當(dāng)Item被移動之前。 */ public static OnItemMovementListener onItemMovementListener = new OnItemMovementListener() { /** * 當(dāng)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;// 返回?zé)o效的方向。 } 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;// 返回?zé)o效的方向。 } @Override public int onSwipeFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder) { // 我們讓第一個不能滑動刪除。 if (targetViewHolder.getAdapterPosition() == 0) { return OnItemMovementListener.INVALID;// 返回?zé)o效的方向。 } 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;// 其它均返回?zé)o效的方向。 } };
onItemMoveListener具體實現(xiàn)如下:
/** * 當(dāng)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; } // 當(dāng)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, "現(xiàn)在的第" + adjPosition + "條被刪除。"); } };
通過代碼中的注釋,就可以明白了,一切盡在代碼中。
用SwipeMenuLayout實現(xiàn)你自己的側(cè)滑效果圖:
這個與LRecyclerView關(guān)系不大,但是與SwipeMenu關(guān)系密切。為了實現(xiàn)滑動菜單的功能,定義了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來實現(xiàn)的。
項目地址:https://github.com/jdsjlzx/LR...,歡迎Star!
ThanksSwipeRecyclerView 作者:嚴(yán)振杰
別看他年齡小,也很牛?。?/p>
如果你覺得這篇文章對你有用,那么贊一個或者留個言吧!
另外下載Demo有意外收獲?。?/p>
如果你對LRecyclerView有什么好的想法或者建議,期待你的留言!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/65018.html
摘要:支持復(fù)雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動,還可以支持粘貼頭部類似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。十分方便實現(xiàn)復(fù)雜的布局頁面,結(jié)構(gòu)上層次分明,便于維護。 目錄介紹 1.復(fù)雜頁面庫介紹 2.本庫優(yōu)勢亮點 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個header和footer 2.3 支持側(cè)滑功能和拖拽移動 2.4 其他亮點介紹 3.如...
摘要:支持復(fù)雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動,還可以支持粘貼頭部類似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。支持粘貼頭部的需求效果,這種效果類似微信好友分組的那種功能界面。 目錄介紹 1.復(fù)雜頁面庫介紹 2.本庫優(yōu)勢亮點 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個header和footer 2.3 支持側(cè)滑功能和拖拽移動 2.4 其他亮點介紹 ...
摘要:系列,自定義實現(xiàn)知乎首頁仿今日頭條最強頂部導(dǎo)航指示器,支持種模式系列之一使用打造千變?nèi)f化的指示器優(yōu)雅的為添加和實現(xiàn)快速滑動實現(xiàn)條目拖拽排序與滑動刪除高仿網(wǎng)易新聞首頁添加,刪除,排序類似大眾點評美團等應(yīng)用的城市選擇器那些酷炫的開源庫整理 Material Design系列,自定義Behavior實現(xiàn)Android知乎首頁 showImg(http://img.blog.csdn.net/...
閱讀 588·2023-04-26 00:33
閱讀 3609·2021-11-24 09:39
閱讀 3214·2021-09-22 15:34
閱讀 2426·2019-08-23 18:07
閱讀 2982·2019-08-23 18:04
閱讀 3830·2019-08-23 16:06
閱讀 2960·2019-08-23 15:27
閱讀 1670·2019-08-23 14:32