前些天又有一個同學私信我,問我側滑刪除功能改如何實現?時不時的就會收到相似的問題,有空的時候我會說一下大概的實現思路或者扔一個Github 的鏈接,沒空的時候就會叫他們自己Google一下,網上有一些現成的開源庫,拿來自己改一下或者能實現設計給的UI效果的,直接用上就好。
側滑菜單確實是一個比較常見的功能,其中場景較多的就是側滑刪除,它是iOS列表刪除通用交互方式,比如微信、QQ、蘋果自帶的短信、通訊錄列表等,都有側滑刪除功能。由于國內Android、iOS通常都是一套設計,因次,Android端怎么能少得了這個功能呢?Android 端實現起來確實稍顯麻煩,它需要你掌握自定義View、屬性動畫、事件分發等一些比較深入的知識點。如果這些知識點你掌握得不錯,那么實現一個側滑菜單其實也不難。本文就講講實現思路和整理的一些不錯的關于側滑菜單的開源庫。
基本實現思路
通過自定義View的方式實現步驟:
1、自定義ViewGroup
2、在onLayout 中,獲取childView
并對他們進行布局,這一步比較重要,content
占滿屏幕,菜單View 在屏幕之外,當滑動的時候,content
滑屏幕,menu 進入屏幕,就達到了我需要的效果,布局草圖如下:
3、重寫dispatchTouchEvent
和onInterceptTouchEvent
方法攔截事件和處理滾動。滑動效果的實現既可以用Scroller
,也可以用屬性動畫ValueAnimator
。
以上就是實現一個策側滑單的思路。下面就看一下給大家整理的幾個不錯的庫,思路都是差不多的,只是最后的實現和封裝有所差異。有興趣的去看看源碼。
整理的一些不錯的側滑菜單庫
1、SwipeRevealLayout
SwipeRevealLayout
使用簡單、代碼入侵低,不但支持左右側滑菜單,還支持上下滑出菜單。可以配合各種布局使用,包括RecyclerView
、ListView
、ScrollView
等,效果很贊
使用方式:
<com.chauthai.swipereveallayout.SwipeRevealLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:mode="same_level"
app:dragEdge="left">
<!-- Your secondary layout here -->
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<!-- Your main layout here -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.chauthai.swipereveallayout.SwipeRevealLayout>
在adapter
class 中:
public class Adapter extends RecyclerView.Adapter {
// This object helps you save/restore the open/close state of each view
private final ViewBinderHelper viewBinderHelper = new ViewBinderHelper();
public Adapter() {
// uncomment the line below if you want to open only one row at a time
// viewBinderHelper.setOpenOnlyOne(true);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// get your data object first.
YourDataObject dataObject = mDataSet.get(position);
// Save/restore the open/close state.
// You need to provide a String id which uniquely defines the data object.
viewBinderHelper.bind(holder.swipeRevealLayout, dataObject.getId());
// do your regular binding stuff here
}
}
private class ViewHolder extends RecyclerView.ViewHolder {
private SwipeRevealLayout swipeLayout;
private View frontLayout;
private View deleteLayout;
private TextView textView;
public ViewHolder(View itemView) {
super(itemView);
swipeLayout = (SwipeRevealLayout) itemView.findViewById(R.id.swipe_layout);
frontLayout = itemView.findViewById(R.id.front_layout);
deleteLayout = itemView.findViewById(R.id.delete_layout);
textView = (TextView) itemView.findViewById(R.id.text);
}
public void bind(final String data) {
deleteLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDataSet.remove(getAdapterPosition());
notifyItemRemoved(getAdapterPosition());
}
});
textView.setText(data);
frontLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String displayText = "" + data + " clicked";
Toast.makeText(mContext, displayText, Toast.LENGTH_SHORT).show();
Log.d("RecyclerAdapter", displayText);
}
});
}
}
效果圖:
2、SwipeDelMenuLayout
和SwipeRevealLayout
差不多。
使用方式:
在RecyclerView、ListView 可直接使用,在Adapter 中,在item
布局最外層包上
SwipeMenuLayout
就好。
<?xml version="1.0" encoding="utf-8"?>
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:clickable="true"
android:paddingBottom="1dp">
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:text="項目中我是任意復雜的原ContentItem布局"/>
<!-- 以下都是側滑菜單的內容依序排列 -->
<Button
android:id="@+id/btnTop"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#d9dee4"
android:text="置頂"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/btnUnRead"
android:layout_width="120dp"
android:layout_height="match_parent"
android:background="#ecd50a"
android:clickable="true"
android:text="標記未讀"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/btnDelete"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="@color/red_ff4a57"
android:text="刪除"
android:textColor="@android:color/white"/>
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
效果圖:
3、AndroidSwipeLayout
出自代碼家
大神,功能強大,支持上下左右四個方向滑出菜單,可單獨使用,也支持RecyclerView
和 ListView
等列表,Adapter需要繼承RecylerViewAdapter
或者BaseSwipeAdapter
。
使用:
<com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="80dp">
<!-- Bottom View Start-->
<LinearLayout
android:background="#66ddff00"
android:id="@+id/bottom_wrapper"
android:layout_width="160dp"
android:weightSum="1"
android:layout_height="match_parent">
<!--What you want to show-->
</LinearLayout>
<!-- Bottom View End-->
<!-- Surface View Start -->
<LinearLayout
android:padding="10dp"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--What you want to show in SurfaceView-->
</LinearLayout>
<!-- Surface View End -->
</com.daimajia.swipe.SwipeLayout>
代碼中:
SwipeLayout swipeLayout = (SwipeLayout)findViewById(R.id.sample1);
//set show mode.
swipeLayout.setShowMode(SwipeLayout.ShowMode.LayDown);
//add drag edge.(If the BottomView has 'layout_gravity' attribute, this line is unnecessary)
swipeLayout.addDrag(SwipeLayout.DragEdge.Left, findViewById(R.id.bottom_wrapper));
swipeLayout.addSwipeListener(new SwipeLayout.SwipeListener() {
@Override
public void onClose(SwipeLayout layout) {
//when the SurfaceView totally cover the BottomView.
}
@Override
public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset) {
//you are swiping.
}
@Override
public void onStartOpen(SwipeLayout layout) {
}
@Override
public void onOpen(SwipeLayout layout) {
//when the BottomView totally show.
}
@Override
public void onStartClose(SwipeLayout layout) {
}
@Override
public void onHandRelease(SwipeLayout layout, float xvel, float yvel) {
//when user's hand released.
}
});
配合RecyclerView
和ListView
等列表的使用,請看github
給出的 Samples
效果圖:
4、SwipeRecyclerView
本庫的一大特色是它滑出的菜單可以是左右排列的,也可以是上下排列,提供多種選擇,不過侵入性稍微有點高,需要使用本庫提供的SwipeRecyclerView
,但是使用方式與提供的api和原生的RecyclerView
是一樣的。還有它通過代碼來創建劃出的菜單。如下:
// 設置監聽器。
swipeRecyclerView.setSwipeMenuCreator(mSwipeMenuCreator);
// 創建菜單:
SwipeMenuCreator mSwipeMenuCreator = new SwipeMenuCreator() {
@Override
public void onCreateMenu(SwipeMenu leftMenu, SwipeMenu rightMenu, int position) {
SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
...; // 各種文字和圖標屬性設置。
leftMenu.addMenuItem(deleteItem); // 在Item左側添加一個菜單。
SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
...; // 各種文字和圖標屬性設置。
leftMenu.addMenuItem(deleteItem); // 在Item右側添加一個菜單。
// 注意:哪邊不想要菜單,那么不要添加即可。
}
};
// 菜單點擊監聽。
swipeRecyclerView.setOnItemMenuClickListener(mItemMenuClickListener);
OnItemMenuClickListener mItemMenuClickListener = new OnItemMenuClickListener() {
@Override
public void onItemClick(SwipeMenuBridge menuBridge, int position) {
// 任何操作必須先關閉菜單,否則可能出現Item菜單打開狀態錯亂。
menuBridge.closeMenu();
// 左側還是右側菜單:
int direction = menuBridge.getDirection();
// 菜單在Item中的Position:
int menuPosition = menuBridge.getPosition();
}
};
效果圖:
5、RecyclerViewUndoSwipe
一個可以拖拽和側滑的UI效果,動畫非常炫。
效果圖:
它沒有封裝成庫,是一個效果demo,具體使用方式和實現,可以去看源碼