简单的侧滑菜单实现

本文参考自郭霖和鸿洋的多篇文章,无法逐一列举了

  1. 实现思路

    利用自定义的HorizontalScrollView实现。 HorizontalScrollView中管理两个视图,一个视图为“菜单”,另一个为“正文”。初始时“菜单”部分在屏幕可视区域以外。当利用HorizontalScrollView的滑动机制进行水平滑动时,将隐藏在屏幕外的“菜单”部分“拖入”屏幕可视区域。

  2. 效果增强

    以自定义的方式继承HorizontalScrollView并改写了其中的一些方法,可以在侧滑时增加一些滑动效果。比如滑动中“正文”的逐步缩小,“菜单”的逐步放大以及透明度的变化等。

  3. 实现步骤
    1. 初步示意图

      初始时只会在屏幕中看见正文区域

      随着向右“滑动”,“菜单”会出现在屏幕的可视区域内

    2. 代码实现

      写一个自定义的View继承自HorizontalScrollView

    MySlidingMenu extends HorizontalScrollView

    然后利用自定义的MySlidingMenu构建MainActivity中的布局

     <com.tarena.myviewtest.view.MySlidingMenu
            android:id="@+id/msm_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@mipmap/img_frame_background"
            app:menu_padding="100dp">
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal">
                <include
                    layout="@layout/left_menu_layout"
                />
    
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@mipmap/qq">
            </LinearLayout>
            </LinearLayout>
        </com.tarena.myviewtest.view.MySlidingMenu>

    其中left_menu_layout就是一个简单的LinearLayout,罗列了几个TextView形式的菜单项,正文区域是一幅图片

  4. 方法重写

    为了实现初始时“菜单”部分在屏幕可视区域的左侧,需要重写MySlidingMenu的一些方法。这些方法包括:

    onMeasure方法:在这里要确认一下菜单区域和正文区域的大小

    onLayout方法:在这里完成对MySlidingMenu中内容的“摆放”。

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        wrapper = (LinearLayout) this.getChildAt(0);
        menu = wrapper.getChildAt(0);
        content = wrapper.getChildAt(1);
        menuWidth = screenWidth - menuRightPadding;
        menu.getLayoutParams().width = menuWidth;
        content.getLayoutParams().width = screenWidth;

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

在onMeasure方法中screenWidth是屏幕的宽度:

 DisplayMetrics outMetrics = new DisplayMetrics();
        ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(outMetrics);
        screenWidth = outMetrics.widthPixels;

menuRightPadding是“菜单”打开后,菜单距离屏幕右侧的距离。该值可以被当做一个自定义属性在布局文件中由使用者传入。默认值为80dp

 TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.MySlidingMenu);
        menuRightPadding = t.getDimensionPixelSize(R.styleable.MySlidingMenu_menu_padding,
                (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics()));
        t.recycle();

在确定了“菜单”部分的宽度后,在onLayout方法中调用scrollTo方法,该方法就是将MySlidingMenu的“内容区域”的左边缘移动到MySlidingMenu左边缘的左侧,距离恰好是“菜单”的宽度。这样就保证了“菜单”恰好位于屏幕可视区域之外。

此时就可以运行代码,实现“菜单”的侧滑了。

  1. 效果增强

    基本效果实现了,接下来利用代码来实现效果的增强:

    如果在滑动过程中松手,菜单已经显示的区域如果大于菜单尺寸的1/2则应该自动的完成菜单显示的后续滑动,反之则应该让菜单完成收起的后续动作。

    上述逻辑写在MySlidingMenu的onTouchEvent中,因为HorizontalScrollView本身实现了一套onTouchEvent的逻辑,这里我们只针对MontionEvent的Action_Up动作即可:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (action == MotionEvent.ACTION_UP) {
            int sx = getScrollX();
            if (sx >= menuWidth / 2) {
                smoothScrollTo(menuWidth, 0);
                isOpen = false;
            } else {
                smoothScrollTo(0, 0);
                isOpen = true;
            }
            return true;
        }
        return super.onTouchEvent(ev);
    }

这里在完成滑动时直接调用了HorizontalScrollView的smoothScrollTo方法,这样可以实现一个平滑的滑动过程,而不会像scrollTo那样瞬间完成滑动。

在上面的实现中,“菜单”是从左侧被“拖”出来的,接下来实现一种正文好像覆盖在“菜单”上面的感觉,先看示意图,对比一下两者的差异:

可以明显看出两者的效果差异吧。

要从“拖出”效果转为“覆盖”效果,仅仅需要一行代码:

重写一下父类的onScrollChanged方法即可:

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {

        ViewHelper.setTranslationX(menu, l);
        super.onScrollChanged(l, t, oldl, oldt);
    }

其中ViewHelper是nineoldandroids.jar中的一个类,nineoldandroids不用过多介绍了,它是一个兼容3.0以下版本实现属性动画的一个安卓类库。setTranslationX的意思就是设定“菜单”这个视图的translationX的值。方法中将menu视图的translationX的值设定为了onScrollChanged方法的第一个参数值。这是因为:

当MySlidingMenu的scrollTo方法被调用的时候(scrollBy和smoothScrollTo方法内部也是在调用scrollTo方法),scrollTo方法内部做的事情就是设定好滑动终止时的目标scrollX和scrollY的值以及滑动开始时的scrollX与scrollY的值,然后调用onScrollChanged方法,将这四个值作为onScrollChanged方法的四个参数,因此l参数的意思实际就是当滑动结束时“菜单”视图的scrollX的值。

MySlidingMenu的本身的视图宽度为屏幕的宽度,而MySlidingMenu中管理的内容是“菜单”视图+“正文”视图,内容的宽度是大于MySlidingMenu本身的宽度的,scrollX代表的就是MySlidingMenu现实的内容左边缘与MySlidingMenu本身左边缘的距离。

如果此时不做任何额外的操作,那么“菜单”视图停留在MySlidingMenu左侧边缘的左侧,距离MySlidingMenu左侧边缘scrollX个像素。现在希望它能够出现在可视区域中,也就是让“菜单”视图的左边缘恰好出现在MySlidingMenu的左边缘,那就需要让“菜单”视图从当前自己的左边缘开始再多滑动scrollX个像素的距离。如何滑动呢,就设定“菜单”视图的translationX属性值即可,translationX属性值代表让视图产生移动,视图移动后左侧边缘与视图left属性之间的距离(这部分内容的详情可以参考我的另一篇blogView的坐标系)。所以只要设定“菜单”视图的translationX属性值为滑动结束后的scrollX的值即可,这样每次滑动结束后,利用translationX再让“菜单”视图多滑动scrollX个像素值。这样就实现了每次滑动时,“菜单”视图始终都是左侧与MySlidingMenu的左侧保持一致的效果。

接下来再增加一些滑动中的效果。比如随着滑动,让“内容”区域产生一个由大到小的变化,让“菜单”区域产生一个由小到大的变化,并伴随一个透明度的变化:

这一切的发生都是随着滑动而发生的,因此这里需要找到一个随着滑动而不断变化的比例值:

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    float scale = l*1.0f/menuWidth;
        ViewHelper.setTranslationX(menu, l);
        super.onScrollChanged(l, t, oldl, oldt);
    }

随着滑动l的值会不断发生变化,但是“菜单”的宽度是在onMeasure方法中设定好的,并不会变化,而滑动的整体变化过程或者说l的取值范围就是从0到menuWidth。有了这个scale后,就可以利用它实现各种滑动过程中的变化了:

 @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        //随着滑动,l的值不断变化(从menuWidth到0)。将绝对值值转化为一个比值
        //scale的变化区间是1--->0
        float scale = l*1.0f/menuWidth;
        ViewHelper.setTranslationX(menu, l);
        //随着拖动,content区域由大到小从100%--->70%左右
        ViewHelper.setScaleX(content,0.7f+0.3f*scale);
        ViewHelper.setScaleY(content,0.7f+0.3f*scale);
        ViewHelper.setPivotX(content,0);
        ViewHelper.setPivotY(content,content.getHeight()/2);
        //随着拖动,菜单区域的透明度在变化,变化区间大概是0.7--->1
        ViewHelper.setAlpha(menu,0.5f+0.5f*(1-scale));
        //随着拖动,菜单区域的大小在变化变化区间大概是0.7--->1
        ViewHelper.setScaleX(menu,0.7f+0.3f*(1-scale));
        ViewHelper.setScaleY(menu,0.7f+0.3f*(1-scale));
        super.onScrollChanged(l, t, oldl, oldt);
    }

代码运行后的效果如图所示:

还可以再增加一点效果。此时的效果是随着拖动“菜单”视图恰好每次都是出现在MySlidingMenu的左边缘。如果每次不让“菜单”视图都移动scrollX的距离,而是移动的少一点,这样在MySlidingMenu的滑动过程除了上述已经有的效果外,还可以再带着一点“菜单”平滑拖出的效果。

只需要修改setTranslationX部分即可,原先移动l,现在让l乘以一个比例值,就可以不移动scrollX了:

 @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {

        //随着滑动,l的值不断变化(从menuWidth到0)。将绝对值值转化为一个比值
        //scale的变化区间是1--->0
        float scale = l*1.0f/menuWidth;
        //ViewHelper.setTranslationX(menu, l);
        ViewHelper.setTranslationX(menu, l*0.7f);
        //随着拖动,content区域由大到小
        //但是并不是到0,大概是从100%--->70%左右
        ViewHelper.setScaleX(content,0.7f+0.3f*scale);
        ViewHelper.setScaleY(content,0.7f+0.3f*scale);
        ViewHelper.setPivotX(content,0);
        ViewHelper.setPivotY(content,content.getHeight()/2);
        //随着拖动,菜单区域的透明度在变化
        //变化区间大概是0.7--->1
        ViewHelper.setAlpha(menu,0.5f+0.5f*(1-scale));
        //随着拖动,菜单区域的大小在变化
        //变化区间大概是0.7--->1
        ViewHelper.setScaleX(menu,0.7f+0.3f*(1-scale));
        ViewHelper.setScaleY(menu,0.7f+0.3f*(1-scale));

        super.onScrollChanged(l, t, oldl, oldt);

    }

看一下这次的运行效果:

可以看到“菜单”区域除了透明度、大小变化之外,还有了侧拉效果。

该策滑菜单的基本实现需要掌握自定义View的基本知识,以及scrollTo的用法。在效果增强部分,需要先理解View中的几个坐标点的差异包括left,scrollX,translationX等,这样才能逐步实现效果。

时间: 2024-11-13 07:54:13

简单的侧滑菜单实现的相关文章

Android 自定义控件打造史上最简单的侧滑菜单

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39185641 ,本文出自[张鸿洋的博客] 侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最

Android 实现形态各异的双向侧滑菜单 自定义控件来袭

1.概述 关于自定义控件侧滑已经写了两篇了~~今天决定把之前的单向改成双向,当然了,单纯的改动之前的代码也没意思,今天不仅 会把之前的单向改为双向,还会多添加一种侧滑效果,给大家带来若干种形态各异的双向侧滑菜单,不过请放心,代码会很简单~~然后根据这若干种,只要你喜 欢,相信你可以打造任何绚(bian)丽(tai)效果的双向侧滑菜单~~ 首先回顾一下,之前写过的各种侧滑菜单,为了不占据篇幅,就不贴图片了: 1.最普通的侧滑效果,请参考:Android 自定义控件打造史上最简单的侧滑菜单 2.仿Q

android组件之DrawerLayout(抽屉导航)-- 侧滑菜单效果

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/41696291 一. 介绍 导航抽屉显示在屏幕的最左侧,默认情况下是隐藏的,当用户用手指从边缘向另一个滑动的时候,会出现一个隐藏的面板,当点击面板外部或者向原来的方向滑动的时候,抽屉导航就会消失了! 好了,这个抽屉就是DrawerLayout,该类位于V4包中. android.support.v4.widget.DrawerLayout. 二. 使用 抽屉导航的实现步骤非常简单.只要

嗯嗯,一句代码就搞定 RecycleView 侧滑菜单、添加头部底部、加载更多

很早就萌生了将这种方案封装为一个开源库的想法,旨在实现调用方式最简单,且又不失可定制性.本库最大的特点的是采用了 Glide 简洁明了的链式调用方式,一句代码即可添加侧滑菜单.头部底部等. 特性: 1.自定义侧滑菜单布局 2.添加头部.底部 3.轻松实现加载更多 4.设置 item 间距 5.多种 item 类型 6.支持 LinearLayout 及 GridLayout 7.一句代码实现所有功能 效果: 左侧滑菜单.右侧滑菜单.自定义菜单布局:      头部.多头部:      底部.多底

两种主流的实现侧滑菜单控件的学习总结

第一次开始研究侧滑菜单实现还是QQ加入这个功能之后吸引的我,当时就觉得这个侧滑菜单的想法简直独具匠心,使用侧滑菜单的好处必须明显,它可以无形的使我们的屏幕利用更大化,你可以假想自己的屏幕比现实还要大,那个侧滑菜单就藏在看不见的屏幕里,当我们用侧滑手势之后,就将它们从看不见的屏幕里拉入真实屏幕中,当我们使用完菜单后,又可以将它们收回到看不见的屏幕中...这让本来空间就有限的手机屏幕,屏幕利用率得到大大的提高.后来通过自己在网络博客论坛的寻觅,发现了两种比较便捷的能帮助我们实现侧滑菜单效果的控件:

Android 侧滑菜单的简单实现(SlidingMenu)二

在上一篇博文中已经简单的实现了侧滑菜单,代码也很简单,就几行代码. 这篇文章依然讲侧滑菜单,与前一篇文章不同的是,这篇文章用不同的代码方式来实现侧滑菜单. 在前面的文章中已经用了在Activity中通过SlidingMenu构造方法直接设置侧滑菜单,这里换成通过Activity继承SlidingActivity来实现侧滑. 代码如下: public class MainActivity extends SlidingActivity 重写onCreate()方法: @Override publi

Android 侧滑菜单的简单实现(SlidingMenu)

在我还没有学习Android的时候就用过侧滑菜单的APP,当时第一个感觉是:哇塞,这效果不错!当然,现在自己都已经学Android了,这效果当然也要做出来啊~ SlidingMenu是一种比较新的设置界面或配置界面的效果(我觉得已经不新了耶~),在主界面左滑或者右滑出现设置界面效果,能方便的进行各种操作.很多优秀的应用都采用了这种界面方案,像facebook.人人网.everynote.Google+等等.效果如下图: 其实网上已经有很多写SlidingMenu使用的文章了.不过,别人始终是别人

Adapter类控件使用之DrawerLayout(官方侧滑菜单)的简单使用

(一)概述 本节给大家带来基础UI控件部分的最后一个控件:DrawerLayout,官方给我们提供的一个侧滑菜单控件,和上一节的ViewPager一样,3.0以后引入,低版本使用它,需要v4兼容包,既然Google为我们提供了这个控件,为何不用咧,而且在 Material Design设计规范中,随处可见的很多侧滑菜单的动画效果,大都可以通过Toolbar + DrawerLayout来实现~,本节我们就来探究下这个DrawerLayout的一个基本用法~还有人喜欢把他 称为抽屉控件~ (二)使

Android滑动菜单特效实现,仿人人客户端侧滑效果,史上最简单的侧滑实现

本文首发于CSDN博客,转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8714621 人人客户端有一个特效还是挺吸引人的,在主界面手指向右滑动,就可以将菜单展示出来,而主界面会被隐藏大部分,但是仍有左侧的一小部分同菜单一起展示. 据说人人客户端的这个特效是从facebook客户端模仿来的,至于facebook是不是又从其它地方模仿来的就不得而知了.好,今天我们就一起来实现这个效果,总之我第一次看到这个特效是在人人客户端看到的,我