教你实现最简单的QQ消息item侧滑菜单

这次跟大家介绍怎么简单的实现类似QQ消息Item的左右滑动菜单的实现。首先见效果图先:

show.gif

这就实现了ListView或RecyclerView加载的item的View实现侧滑菜单。至于这么实现,很简单就是通过继承HorizontalScrollView,再判断滑动的距离以滑到对应的View或菜单。具体如下:
首先,在item的界面布局方面如下:

<?xml version="1.0" encoding="utf-8"?>
<com.example.jack.listviewitemscroll.widget.ScrollListViewItem
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <include layout="@layout/leftbutton"/>
        <include layout="@layout/context_view"/>
        <include layout="@layout/rightbutton"/>
    </LinearLayout>
</com.example.jack.listviewitemscroll.widget.ScrollListViewItem>

就是ScrollListViewItem包裹着LinearLayout里面的三个View,分别是左菜单,内容和右菜单对应的View。最为重点的就是ScrollListViewItem这个类,这就是我们继承HorizontalScrollView类所自定义的控制菜单滑动的类。
这个类的源码如下:

public class ScrollListViewItem extends HorizontalScrollView{

    private static int ScreenWidth=0;
    private static int MenuWidth=0;
    private static int HalfMenuWidth=0;
    private boolean  operateLeft=false;
    private boolean operateRight=false;
    private boolean once;

    ViewGroup left;
    ViewGroup centre;
    ViewGroup right;

    public ScrollListViewItem(Context context) {
        this(context, null);
    }

    public ScrollListViewItem(Context context, AttributeSet attrs) {
        super(context, attrs,0);
    }

    public ScrollListViewItem(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr,0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       if(!once){
           LinearLayout linearLayout=(LinearLayout)getChildAt(0);
           left=(ViewGroup)linearLayout.getChildAt(0);
           centre=(ViewGroup)linearLayout.getChildAt(1);
           right=(ViewGroup)linearLayout.getChildAt(2);

           ScreenWidth= ScreenUtils.getScreenWidth(getContext());
           MenuWidth=ScreenWidth/4;
           HalfMenuWidth=MenuWidth/2;

           left.getLayoutParams().width=MenuWidth;
           centre.getLayoutParams().width=ScreenWidth;
           right.getLayoutParams().width=MenuWidth;
       }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(changed){
            this.scrollTo(MenuWidth,0);
            once=true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch(ev.getAction()){
            case MotionEvent.ACTION_UP:
                //在左侧
                if(operateLeft){
                    if(getScrollX()<HalfMenuWidth){
                        //滑到左最末尾
                        this.scrollTo(0, 0);
                    }else if(getScrollX()>HalfMenuWidth&&getScrollX()<MenuWidth+HalfMenuWidth){
                        //滑到中间
                        this.scrollTo(MenuWidth, 0);
                    }else{
                        this.scrollTo(MenuWidth * 2, 0);
                    }
                }
                //向右侧
                if(operateRight){
                    if(getScrollX()>MenuWidth+HalfMenuWidth){
                        //滑到最右
                        this.scrollTo(MenuWidth + MenuWidth, 0);
                    }else if(getScrollX()>HalfMenuWidth&&getScrollX()<MenuWidth+HalfMenuWidth){
                        //滑到中间
                        this.scrollTo(MenuWidth, 0);
                    }else{
                        //滑到最左
                        this.scrollTo(0, 0);
                    }
                }
                return true;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(l>MenuWidth){
            operateLeft=false;
            operateRight=true;
        }else{
            operateLeft=true;
            operateRight=false;
        }
    }
}

在onMeasure()这个自定义View的测量方法里,我们首先拿到左菜单,内容,右菜单所对用的view,即left,centre,right这三个View,然后获取屏幕的宽度,动态设定菜单的宽度为屏幕宽度的四分之一,而内容的宽度就是整个屏幕的宽度,即

 left.getLayoutParams().width=MenuWidth;
 centre.getLayoutParams().width=ScreenWidth;
 right.getLayoutParams().width=MenuWidth;

然后我们在onLayout()方法里对这三个View进行定位,即让他滑到内容的那个View。

然后回调onScrollChanged(int l, int t, int oldl, int oldt)方法,当l大于菜单宽度时是右侧,当l小于菜单宽度时是右侧。(注:l是屏幕最右边到整个View最右边的距离)

其次就是最重要的onTouchEvent(MotionEvent ev)方法了。(注:是屏幕最右边到整个View最右边的距离).当operateLeft==true的时候,滑动在操作在左侧,当getScrollX()<HalfMenuWidth,即在最左向右滑还不到菜单的二分之一宽度时,恢复原状,即this.scrollTo(0, 0);,当getScrollX()>HalfMenuWidth&&getScrollX()<MenuWidth+HalfMenuWidth,即最左向右滑大于菜单的二分之一宽度但却小于左菜单加右菜单一半的宽度,所以只能滑到内容区域,即this.scrollTo(MenuWidth, 0);,这两种情况除外都会滑到最后边的菜单,所以this.scrollTo(MenuWidth * 2, 0);

同样的道理,当operateRight==true时,getScrollX()>MenuWidth+HalfMenuWidth时,即在最右菜单但滑动的距离小于菜单宽度的一半,所以只能恢复原状即this.scrollTo(MenuWidth + MenuWidth, 0);,当getScrollX()>HalfMenuWidth&&getScrollX()<MenuWidth+HalfMenuWidth时,即滑动大于菜单一半但是却小于左菜单加右菜单一半的宽度,所以是内容区域,即滑动 this.scrollTo(MenuWidth, 0);,除这两种情况都是要滑到最左边的菜单,即 this.scrollTo(0, 0);。到此整个流程就讲完了。

最后奉上源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容