Android 側(cè)滑菜單(側(cè)滑刪除)總結(jié)

前些天又有一個(gè)同學(xué)私信我,問我側(cè)滑刪除功能改如何實(shí)現(xiàn)?時(shí)不時(shí)的就會(huì)收到相似的問題,有空的時(shí)候我會(huì)說(shuō)一下大概的實(shí)現(xiàn)思路或者扔一個(gè)Github 的鏈接,沒空的時(shí)候就會(huì)叫他們自己Google一下,網(wǎng)上有一些現(xiàn)成的開源庫(kù),拿來(lái)自己改一下或者能實(shí)現(xiàn)設(shè)計(jì)給的UI效果的,直接用上就好。

側(cè)滑菜單確實(shí)是一個(gè)比較常見的功能,其中場(chǎng)景較多的就是側(cè)滑刪除,它是iOS列表刪除通用交互方式,比如微信、QQ、蘋果自帶的短信、通訊錄列表等,都有側(cè)滑刪除功能。由于國(guó)內(nèi)Android、iOS通常都是一套設(shè)計(jì),因次,Android端怎么能少得了這個(gè)功能呢?Android 端實(shí)現(xiàn)起來(lái)確實(shí)稍顯麻煩,它需要你掌握自定義View、屬性動(dòng)畫、事件分發(fā)等一些比較深入的知識(shí)點(diǎn)。如果這些知識(shí)點(diǎn)你掌握得不錯(cuò),那么實(shí)現(xiàn)一個(gè)側(cè)滑菜單其實(shí)也不難。本文就講講實(shí)現(xiàn)思路和整理的一些不錯(cuò)的關(guān)于側(cè)滑菜單的開源庫(kù)。

基本實(shí)現(xiàn)思路

通過(guò)自定義View的方式實(shí)現(xiàn)步驟:
1、自定義ViewGroup
2、在onLayout 中,獲取childView并對(duì)他們進(jìn)行布局,這一步比較重要,content 占滿屏幕,菜單View 在屏幕之外,當(dāng)滑動(dòng)的時(shí)候,content滑屏幕,menu 進(jìn)入屏幕,就達(dá)到了我需要的效果,布局草圖如下:

草圖.png

3、重寫dispatchTouchEventonInterceptTouchEvent方法攔截事件和處理滾動(dòng)?;瑒?dòng)效果的實(shí)現(xiàn)既可以用Scroller,也可以用屬性動(dòng)畫ValueAnimator。

以上就是實(shí)現(xiàn)一個(gè)策側(cè)滑單的思路。下面就看一下給大家整理的幾個(gè)不錯(cuò)的庫(kù),思路都是差不多的,只是最后的實(shí)現(xiàn)和封裝有所差異。有興趣的去看看源碼。

整理的一些不錯(cuò)的側(cè)滑菜單庫(kù)
1、SwipeRevealLayout

SwipeRevealLayout 使用簡(jiǎn)單、代碼入侵低,不但支持左右側(cè)滑菜單,還支持上下滑出菜單。可以配合各種布局使用,包括RecyclerViewListView、ScrollView 等,效果很贊

地址:https://github.com/chthai64/SwipeRevealLayout

使用方式:

<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>

adapterclass 中:

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);
                }
            });
        }
    }

效果圖:


demo_all.gif
demo_normal.gif
demo_same.gif
2、SwipeDelMenuLayout

地址:https://github.com/mcxtzhang/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="項(xiàng)目中我是任意復(fù)雜的原ContentItem布局"/>

    <!-- 以下都是側(cè)滑菜單的內(nèi)容依序排列 -->
    <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="標(biāo)記未讀"
        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>

效果圖:


一般布局gif
rv.gif
3、AndroidSwipeLayout

地址:https://github.com/daimajia/AndroidSwipeLayout

出自代碼家大神,功能強(qiáng)大,支持上下左右四個(gè)方向滑出菜單,可單獨(dú)使用,也支持RecyclerViewListView等列表,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.
            }
        });

配合RecyclerViewListView 等列表的使用,請(qǐng)看github給出的 Samples
效果圖:

AndroidSwipe.gif
4、SwipeRecyclerView

地址:https://github.com/yanzhenjie/SwipeRecyclerView

本庫(kù)的一大特色是它滑出的菜單可以是左右排列的,也可以是上下排列,提供多種選擇,不過(guò)侵入性稍微有點(diǎn)高,需要使用本庫(kù)提供的SwipeRecyclerView,但是使用方式與提供的api和原生的RecyclerView是一樣的。還有它通過(guò)代碼來(lái)創(chuàng)建劃出的菜單。如下:

// 設(shè)置監(jiān)聽器。
swipeRecyclerView.setSwipeMenuCreator(mSwipeMenuCreator);

// 創(chuàng)建菜單:
SwipeMenuCreator mSwipeMenuCreator = new SwipeMenuCreator() {
    @Override
    public void onCreateMenu(SwipeMenu leftMenu, SwipeMenu rightMenu, int position) {
        SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
            ...; // 各種文字和圖標(biāo)屬性設(shè)置。
        leftMenu.addMenuItem(deleteItem); // 在Item左側(cè)添加一個(gè)菜單。

        SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
            ...; // 各種文字和圖標(biāo)屬性設(shè)置。
        leftMenu.addMenuItem(deleteItem); // 在Item右側(cè)添加一個(gè)菜單。
        
        // 注意:哪邊不想要菜單,那么不要添加即可。
    }
};

// 菜單點(diǎn)擊監(jiān)聽。
swipeRecyclerView.setOnItemMenuClickListener(mItemMenuClickListener);

OnItemMenuClickListener mItemMenuClickListener = new OnItemMenuClickListener() {
    @Override
    public void onItemClick(SwipeMenuBridge menuBridge, int position) {
        // 任何操作必須先關(guān)閉菜單,否則可能出現(xiàn)Item菜單打開狀態(tài)錯(cuò)亂。
        menuBridge.closeMenu();
        
        // 左側(cè)還是右側(cè)菜單:
        int direction = menuBridge.getDirection();
        // 菜單在Item中的Position:
        int menuPosition = menuBridge.getPosition();
    }
};

效果圖:

1.gif
2.gif
3.gif
5、RecyclerViewUndoSwipe

地址:https://github.com/HoneyNeutrons/RecyclerViewUndoSwipe

一個(gè)可以拖拽和側(cè)滑的UI效果,動(dòng)畫非常炫。

效果圖:

undo.gif

它沒有封裝成庫(kù),是一個(gè)效果demo,具體使用方式和實(shí)現(xiàn),可以去看源碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容