Android打造专属自定义SlidingMenu

/**
       在众多的App中都用到了SlidingMenu,使用SlidingMenu不仅可以增加显示的内容,也让用户体验更多的舒适,当然现在github上有相应的SlidingMenu的库在其它的博客也有很多的关于SlidingMenu的介绍,也当然此文章也会有很多和别人重复,但是相信坚持总结、坚持学习,总有一天能写出不一样的文章,fighting!!

 */

首先附上github上第三方的库

              https://github.com/jfeinstein10/SlidingMenu

然后开始我们的自定义SlidingMenu类之旅,在开始之前我们先明确自定义类继承什么呢?要是使用ViewGroup的话会比较麻烦因为你需要在类里面进行测量,在很多自定义的控件中都会继承其子类来实现相应的功能例如FrameLayout和HorizontalScrollView等等。

Part 1、继承HorizontalScrollView实现

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                int dx = getScrollX();//(1)
                if (dx > menuWidth / 2) {
                    smoothScrollTo(menuWidth, 0);
                } else {
                    smoothScrollTo(0, 0);
                }
                return true;//(2)
        }
        return super.onTouchEvent(ev);
    }

tips:

这里使用的smoothScrollTo而不是scrollTo,纯粹是为了体验更加的平滑。

(1)、getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量。

(2)、这里应该返回true来屏蔽掉下面的super.onTouchEvent(ev)方法,不然的话就没有任何的效果

ok,效果~

这样简易的侧滑就搞定了~

如果你想要在添加一些酷炫的动画效果的话需要重写

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        float scale = l * 1.0f / menuWidth; // 1 ~ 0
        float fraction = 1 - scale;
当滚动发生的时候会不断的去执行,里面也有变化量得到的方法,其实要想实现动画效果此时只需要一个变化量那一切动画so easy!

平移缩放等等

ViewHelper.setTranslationX(menuContent, evaluate(fraction,menuWidth*0.5f, 0));
        ViewHelper.setScaleX(menuContent, evaluate(fraction, 0.5f, 1.0f));
        ViewHelper.setScaleY(menuContent, evaluate(fraction, 0.5f, 1.0f));
最后在加上颜色渐变的效果

        getBackground().setColorFilter((Integer) evaluateColor(fraction, Color.BLACK, Color.TRANSPARENT), PorterDuff.Mode.DST_OUT);
tips:

1、nineoldandroid库

    compile 'com.nineoldandroids:library:2.4.0'
2、Android提供的差值器

如:颜色渐变

   /**
     * 颜色变化过渡
     * @param fraction
     * @param startValue
     * @param endValue
     * @return
     */
    public Object evaluateColor(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int) ((startA + (int) (fraction * (endA - startA))) << 24) |
                (int) ((startR + (int) (fraction * (endR - startR))) << 16) |
                (int) ((startG + (int) (fraction * (endG - startG))) << 8) |
                (int) ((startB + (int) (fraction * (endB - startB))));
    }
ok,效果~

这样就实现了继承HorizontalScrollView的侧滑菜单~

Part 2 继承FrameLayout实现

当然我们也可以通过继承FrameLayout或者ViewGroup来实现,针对上面的侧滑接下来要说的这个大致是一样的只不过增加了一个ViewDragHelper类

        dragHelper = ViewDragHelper.create(this, new DragCallBack());
    }
    class DragCallBack extends ViewDragHelper.Callback {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }
        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }
        @Override
        public int getViewHorizontalDragRange(View child) {
            return range;
        }
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // left = oldLeft + dx;
            if (child == mainContent) {
                left = fixLeft(left);
            }
            return left;
        }
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            int newLeft = left;
            if (changedView == leftContent) {
                newLeft = mainContent.getLeft() + dx;
            }
            newLeft = fixLeft(newLeft);
            if (changedView == leftContent) {
                leftContent.layout(0, 0, mWidth, mHeight);
                mainContent.layout(newLeft, 0, newLeft + mWidth, mHeight);
            }
            //执行动画
            animPerform(newLeft);
            // 为了兼容低版本, 每次修改值之后, 进行重绘
            invalidate();
        }
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            // View releasedChild 被释放的子View
            // float xvel 水平方向的速度, 向右为+
            // float yvel 竖直方向的速度, 向下为+

            // 判断执行 关闭/开启
            if (xvel == 0 && mainContent.getLeft() > range / 2.0f) {
                open();
            } else if (xvel > 0) {
                open();
            } else {
                close();
            }
        }
tips:

1、

        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }
根据返回值来决定当前的child是否可以拖拽,child:当前拖拽的View;poterId:多点触控的id

2、

       public void onViewCaptured(View capturedChild, int activePointerId) {
当child被捕获时,基本上没有多大用可以忽略

3、

        @Override
        public int getViewHorizontalDragRange(View child) {
            return range;
        }
得到水平拖拽的范围,这个值不会实际起作用,通过查看源码可知只是在滑动速度上有一定的作用

4、

     public int clampViewPositionHorizontal(View child, int left, int dx) {
根据建议值修正要移动的位置,left=oldleft+dx;  注意:此时还没有发生移动

5、

        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
当View位置发生改变的时候要处理的逻辑(动画、重绘界面等)  注意:此时已经发生移动

6、

        public void onViewReleased(View releasedChild, float xvel, float yvel) {
当View被释放的时候执行此方法,可以在这里面执行一些动画

创建了ViewDragHelper之后,只需要在onTouch和onIntercept方法里面将事件授权给ViewDragHelper

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 传递给mDragHelper
        return dragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        dragHelper.processTouchEvent(event);
        return true;
    }
这样也可以进行滑动了,但是通过滑动你会发现效果并不是像上面那样平滑,原因是上面HorizontalScrollView里面有smoothScrollTo方法,而在ViewGroup或FrameLayout里面却没有,为了也实现平滑的移动应使用Scroller类,由于ViewDragHelper类里面有Scroller,所以只需要使用ViewDragHelper提供的方法即可

        if (dragHelper.smoothSlideViewTo(mainContent, 0, 0)) {
            //ViewCompat.postInvalidateOnAnimation(this);
            invalidate();
        }
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (dragHelper.continueSettling(true)) {
            //  如果返回true, 动画还需要继续执行
            //ViewCompat.postInvalidateOnAnimation(this);
            invalidate();
        }
    }

tips:

 public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
参数一看便知,这里调用invalidate方法,实际内部是回调了computeScroll()方法,然后通过在computeScroll方法里面调用invalidate实现递归效果从而达到平滑移动的效果。

最后在实现动画效果上和part1是一样的,在onViewPositionChanged方法里面添加即可.

效果~


Part 3 使用android.support.v4.widget.DrawerLayout实现

布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
    tools:context="com.andly.administrator.andlyviewpager.drawer.DrawerActivity">


    <include
        layout="@layout/hsv_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <include
        layout="@layout/hsv_menu"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"/>

</android.support.v4.widget.DrawerLayout>
为DrawerLayout设置监听事件

        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
        mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
             @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                float fraction = slideOffset;
                View mainContent = mDrawerLayout.getChildAt(0);
                View menuContent = drawerView;
                ViewHelper.setTranslationX(menuContent,evaluate(fraction, menuContent.getMeasuredWidth()/2,0));
                ViewHelper.setScaleX(menuContent,evaluate(fraction,0.5f,1.0f));
                ViewHelper.setScaleY(menuContent,evaluate(fraction,0.5f,1.0f));

                ViewHelper.setScaleY(mainContent,evaluate(fraction,1.0f,0.8f));
                ViewHelper.setScaleY(mainContent,evaluate(fraction,1.0f,0.8f));
                ViewHelper.setTranslationX(mainContent,evaluate(fraction,0,menuContent.getMeasuredWidth()));
                mDrawerLayout.getBackground().setColorFilter((Integer) evaluateColor(fraction,Color.BLACK,Color.TRANSPARENT), PorterDuff.Mode.DST_OUT);
            }

            @Override
            public void onDrawerOpened(View drawerView) {

            }

            @Override
            public void onDrawerClosed(View drawerView) {
                //mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT);
            }

            @Override
            public void onDrawerStateChanged(int newState) {

            }
        });
tips:

1、

    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
关闭向右侧滑的效果

2、

public void onDrawerSlide(View drawerView, float slideOffset) {
当不断滑动的时候将不断的执行此方法,你只需要将需要执行的动画添加到这里即可

效果~



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值