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