仿酷狗音乐的侧滑菜单效果

话不多说,直接正题!
首先,来看看今天我们要实现的效果:
这里写图片描述

就是这么一个效果!

首先,分析一波:

  1. 有两个布局,一个是菜单栏布局,一个是内容布局

  2. 看效果,当菜单栏慢慢打开时,内容布局有一个缩放的效果,菜单栏布局也有一个缩放的效果,打开的角度越大,放大的值越大,其次,还有一个透明度的渐变效果,最后就是一个抽屉效果(可以看菜单栏布局的右下角的推出按钮,很明显);

再来看看实现该效果的方式:

  1. 最容易想到的,可能是借助DrawerLayout这个工具类来实现了吧
  2. 其次,还有自定义ViewGroup,判断触摸滑动的手势来实现,不过目测处理起来会比较麻烦
  3. 就是今天我们要使用的方法了。继承HorizontalScrollView这个横向滑动View来实现。

下面 直接上代码,按照惯例,会在代码中有大量的注释,如果有问题的,也可以在评论区提出,可以一起交流!毕竟学习使我快乐嘛!哈哈哈哈
1:绘制布局:

<com.justh.dell.kgslidingmenu.SlidingMenu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.justh.dell.kgslidingmenu.MainActivity"
    android:background="@drawable/home_menu_bg"
    app:menuMarginRight="150dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <include layout="@layout/layout_menu"/>

        <include layout="@layout/layout_content"/>


    </LinearLayout>

</com.justh.dell.kgslidingmenu.SlidingMenu>

在自定义这个ViewGroup中,有一个自定义属性,app:menuMarginRight,用来代表菜单栏离右边的距离

MenuView(菜单栏)的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="72dp"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/enter_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="23dp"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/user_head_iv"
                android:layout_width="56dp"
                android:layout_height="56dp"
                android:src="@drawable/morentouxiang" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="22dp"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/user_name_tv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:drawablePadding="10dp"
                    android:drawableRight="@drawable/user_write_paint"
                    android:text="请登录"
                    android:textColor="#c6b178"
                    android:textSize="18dp" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="42dp"
                    android:orientation="horizontal">

                    <TextView
                        android:id="@+id/user_attention_tv"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:drawablePadding="10dp"
                        android:text="关注 0"
                        android:textColor="#c6b178"
                        android:textSize="12dp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="40dp"
                        android:drawablePadding="10dp"
                        android:text="粉丝 0"
                        android:textColor="#c6b178"
                        android:textSize="12dp" />

                </LinearLayout>
            </LinearLayout>
        </LinearLayout>

        <ListView
            android:id="@+id/menu_item_lv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="@null"
            android:dividerHeight="0dp"
            android:layout_marginTop="60dp"/>

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:text="退出"
        android:textColor="#FFFFFF"
        android:layout_height="wrap_content" />

</RelativeLayout>

内容布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#ffffff"
              android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="JUSTH"
        android:textSize="30dp"
        />

</LinearLayout>

自定义ViewGroup的SlidingMenu类:

public class SlidingMenu extends HorizontalScrollView {

    private int mMenuMarginRight = 50;
    private int mMenuWidth;
    private View mMenuView;
    private View mContentView;

    //判断当前菜单栏是否打开
    private boolean isMenuOpen = false;

    //处理手势快速滑动
    private GestureDetector mGestureDetector;

    //判断当前事件是否被拦截
    private boolean isIntercept = false;

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

    public SlidingMenu(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.SlidingMenu);

        mMenuMarginRight = (int) array.getDimension(R.styleable.SlidingMenu_menuMarginRight,dp2px(mMenuMarginRight));

        mMenuWidth = ScreenUtils.getScreenWidth(context) - mMenuMarginRight;
        array.recycle();

        mGestureDetector = new GestureDetector(context,new GestureDetectorListener());
    }

    /**
     * 指定menuView和contentView的宽度
     *
     * 该方法在布局解析完成之后便会调用
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        //获取到LinearLayout
        ViewGroup container = (ViewGroup) getChildAt(0);

        int childCount = container.getChildCount();
        //子View只能有两个  一个是菜单view 一个是contentview
        if(childCount != 2){
            throw new RuntimeException("childCount must have two!");
        }

        //设置MenuView的宽度
        mMenuView = container.getChildAt(0);

        ViewGroup.LayoutParams menuParams = mMenuView.getLayoutParams();
        menuParams.width = mMenuWidth;
        mMenuView.setLayoutParams(menuParams);

        //设置ContentView的宽度   这里为全屏显示
        mContentView = container.getChildAt(1);
        ViewGroup.LayoutParams contentParams = mContentView.getLayoutParams();
        contentParams.width = ScreenUtils.getScreenWidth(getContext());
        mContentView.setLayoutParams(contentParams);
    }

    /**
     * 随着滑动距离的变化,来缩放以及渐变 平移menuView 和contentView
     * 来达到视觉上的效果
     * @param l
     * @param t
     * @param oldl
     * @param oldt
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        Log.i("JUSTH",l+"");
        //以0.7为基数 缩放contentView
        float contentScale = (float) (0.7 + 0.3 * l*1f/mMenuView.getMeasuredWidth());
        ViewCompat.setPivotX(mContentView,0);
        ViewCompat.setPivotY(mContentView,mContentView.getMeasuredHeight()/2);
        ViewCompat.setScaleX(mContentView,contentScale);
        ViewCompat.setScaleY(mContentView,contentScale);

        //给MenuView设置渐变 基数为0.5
        float menuAlpha = (float) (1 - 0.5*l*1f/mMenuView.getMeasuredWidth());
        Log.i("JUSTH","ALPHA="+menuAlpha);
        ViewCompat.setAlpha(mMenuView,menuAlpha);
        //给MenuView设置缩放
        float menuScale = (float) (1 - 0.3 * l * 1f/mMenuView.getMeasuredWidth());
        ViewCompat.setScaleX(mMenuView,menuScale);
        ViewCompat.setScaleY(mMenuView,menuScale);

        //设置menuView的抽屉效果
        ViewCompat.setTranslationX(mMenuView, 0.25f*l);
    }

    /**
     * 当在滑动的过程中还没关闭的时候抬起手,判断当前应该关闭menuView还是打开menuView
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        //已被事件拦截
        if (isIntercept){
            return true;
        }
        //代表当前为手势快速滑动了
        if(mGestureDetector.onTouchEvent(ev)){
            return true;
        }
        if(ev.getAction() == MotionEvent.ACTION_UP){
            int scrollX = getScrollX();
            if(scrollX > mMenuView.getMeasuredWidth()/2){
                closeMenu();
            }else{
                openMenu();
            }
            //一定要消费事件
            return true;
        }
        return super.onTouchEvent(ev);
    }

    private void closeMenu(){
        smoothScrollTo(mMenuWidth,0);
        isMenuOpen = false;
    }

    private void openMenu(){
        smoothScrollTo(0,0);
        isMenuOpen = true;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        scrollTo(mMenuWidth,0);
    }

    private int dp2px(int dp){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
    }

    //添加手势事件处理

    private class GestureDetectorListener extends GestureDetector.SimpleOnGestureListener {

        //处理手势快速滑动的方法
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            //当手势为左右快速滑动是,则切换状态
            if(Math.abs(velocityX) < Math.abs(velocityY)){
                //上下滑动的距离大于左右滑动的距离 代表当前为上下滑动
                //此时不处理
                return super.onFling(e1, e2, velocityX, velocityY);
            }
            //当velocityX > 0  代表右滑  velocityX < 0 代表左滑
            if(isMenuOpen){
                //当菜单栏打开的时候,快速左滑,关闭菜单栏
                if(velocityX < 0){
                    closeMenu();
                    return true;
                }
            }else {
                if(velocityX > 0){
                    openMenu();
                    return true;
                }
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }
    }

    //处理时间拦截   当菜单栏打开的时候,点击右侧内容页面 关闭菜单栏  且拦截内容页面的所有事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        isIntercept = false;
        if(isMenuOpen){
            int x = (int) ev.getX();
            if(x > mMenuView.getMeasuredWidth()){
                closeMenu();

                isIntercept = true;
                return true;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }
}

好了,到这里就结束了!
最后,上一波最后的效果图:
这里写图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值