基于谷歌官方NavigationView实现QQ样式边侧滑抽屉样式缩进缩出

简介: 基于谷歌官方NavigationView实现QQ样式边侧滑抽屉样式缩进缩出本文是三个系列文章中的第三篇,在附录文章1、2中,分别针对DrawerLayout和SlidingMenu实现了QQ样式的边侧滑抽屉样式缩进缩出。


基于谷歌官方NavigationView实现QQ样式边侧滑抽屉样式缩进缩出

本文是三个系列文章中的第三篇,在附录文章1、2中,分别针对DrawerLayout和SlidingMenu实现了QQ样式的边侧滑抽屉样式缩进缩出。由于在实际的项目中,为了实现这种边侧滑抽屉效果,不同开发者采取的技术路线和标准控件选型不同,为了在此基础上加以改造以实现QQ样式的边侧滑缩进缩出抽屉效果,我分别写三篇文章加以说明,另外,在SlidingMenu、DrawerLayout和NavigationView基础上实现QQ样式的边侧滑抽屉缩进缩出虽实现原理大致相同,但细节地方差别还是不小,故分篇介绍。本文将在NavigationView基础上实现QQ样式的边侧滑抽屉缩进缩出技术。
具体的NavigationView使用细节请参考附录文章4。本文不再展开对NavigationView的具体使用做说明。

写一个主布局activity_main.xml布局文件:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/ic_launcher">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F44336">

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="打开 " />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="主界面"
            android:textSize="50sp" />
    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/header"
        app:itemIconTint="#ff5252"
        app:itemTextColor="#42a5f5"
        app:menu="@menu/menu_main">
    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>


NavigationView需要加载一个额外的“头布局”作为头部内容,这一点儿比较常用,现在通用的设计与开发,通常会在左边边侧滑出来的菜单顶部放置用户的头像或醒目信息,res/layout/header.xml代码文件:

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

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Zhang Phil" />

</LinearLayout>


MainActivity.java代码文件:

package zhangphil.apptest;

/**
 * Created by Phil on 2016/4/14.
 */

import android.app.Activity;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.Toast;

import com.nineoldandroids.view.ViewHelper;


public class MainActivity extends Activity {

    private DrawerLayout drawerLayout;
    private NavigationView navigationView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        navigationView = (NavigationView) findViewById(R.id.navigationView);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);

        drawerLayout.setScrimColor(Color.TRANSPARENT);

        setNavigationViewSize(navigationView, 0.6f, 0.8f);

        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {
                menuItem.setChecked(true);

                // 关闭
                drawerLayout.closeDrawers();

                String t = menuItem.getTitle() + "";
                Toast.makeText(getApplicationContext(), t, Toast.LENGTH_SHORT).show();

                return true;
            }
        });

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // 由Button也可以打开
                // 从左边打开
                drawerLayout.openDrawer(GravityCompat.START);
            }
        });


        drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {

            @Override
            public void onDrawerClosed(View v) {

            }

            @Override
            public void onDrawerOpened(View v) {

            }

            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {

                // 主体窗口
                View mainFrame = drawerLayout.getChildAt(0);

                // 这个就是隐藏起来的边侧滑菜单栏
                View leftMenu = drawerView;

                addQQStyleSlide(mainFrame, leftMenu, slideOffset);
            }

            @Override
            public void onDrawerStateChanged(int arg0) {

            }
        });
    }

    //此处将控制NavigationView侧滑出的高度、宽度已经重心位置(居中?靠上?靠下?)
    private void setNavigationViewSize(NavigationView nv, float w_percent, float h_percent) {
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

        //宽度默认是MATCH_PARENT,
        //NavigationView的宽度
        int width = (int) (displayMetrics.widthPixels * w_percent);

        //NavigationView的高度
        int height = (int) (displayMetrics.heightPixels * h_percent);

        //高度默认是MATCH_PARENT,如果不打算打满屏幕高度:DrawerLayout.LayoutParams.MATCH_PARENT,
        // 那么比如可以设置成屏幕高度的80%(即0.8f)
        DrawerLayout.LayoutParams params = new DrawerLayout.LayoutParams(width, height);

        //主要要设置center,否则侧滑出来的菜单栏将从下往上绘制相应高度和宽度而不是居中
        params.gravity = Gravity.START | Gravity.CENTER_VERTICAL;

        nv.setLayoutParams(params);
    }

    // 实现边侧滑的核心代码
    private void addQQStyleSlide(View mainFrame, View leftMenu, float slideOffset) {
        //GAP的值决定左边侧滑出来的宽度和右边的主界面之间在侧滑过程以及侧滑结束后的间距。
        //如果不设置此值或者设置为0,则将恢复成Android系统默认的样式,即侧滑出来的界面和主界面之间紧密贴在一起。
        int GAP = 100;

        float leftScale = 0.5f + 0.5f * slideOffset;
        float rightScale = 1 - 0.2f * slideOffset;

        ViewHelper.setScaleX(leftMenu, leftScale);
        ViewHelper.setScaleY(leftMenu, leftScale);
        ViewHelper.setAlpha(leftMenu, 0.5f + 0.5f * slideOffset);
        ViewHelper.setTranslationX(mainFrame, (leftMenu.getMeasuredWidth() + GAP) * slideOffset);
        ViewHelper.setPivotX(mainFrame, 0);
        ViewHelper.setPivotY(mainFrame, mainFrame.getMeasuredHeight() / 2);
        mainFrame.invalidate();
        ViewHelper.setScaleX(mainFrame, rightScale);
        ViewHelper.setScaleY(mainFrame, rightScale);

        // 该处主要是为了使背景的颜色渐变过渡。
        // 如果失效,则可能是因为Android DrawerLayout的NavigationView绘制背景的图层互相之间遮盖导致。
        //此处不关乎重点实现,作为代码在未来的复用,仍然保留,当然也可以删掉!
        getWindow().getDecorView().getBackground().setColorFilter(evaluate(slideOffset, Color.BLACK, Color.TRANSPARENT),
                PorterDuff.Mode.SRC_OVER);
    }

    private Integer evaluate(float fraction, Object startValue, Integer 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))));
    }
}


NavigationView需要加载的menu菜单代码文件,res/menu/menu_main.xml代码文件:

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

    <item
        android:checkableBehavior="single"
        android:title="第一组菜单">
        <item
            android:id="@+id/open"
            android:icon="@mipmap/ic_launcher"
            android:title="打开"/>
        <item
            android:id="@+id/close"
            android:icon="@mipmap/ic_launcher"
            android:title="关闭"/>
        <item
            android:id="@+id/create"
            android:icon="@mipmap/ic_launcher"
            android:title="新建"/>
    </item>
    <item android:title="第二组菜单">
        <menu>
            <item
                android:id="@+id/exit"
                android:icon="@mipmap/ic_launcher"
                android:title="退出"/>
            <item
                android:id="@+id/about"
                android:icon="@mipmap/ic_launcher"
                android:title="关于"/>
        </menu>
    </item>
</menu>


代码运行结果
初始静止状态:



开始从左往右侧滑过程中的断续截图:



边侧滑结束,抽屉完全打开,静止状态:


附录文章:
1,《基于谷歌官方实现QQ样式边侧滑抽屉缩进缩出技术》链接地址:http://blog.csdn.net/zhangphil/article/details/51074334
2,《改进Android SlidingMenu实现QQ样式边侧滑抽屉技术》链接地址:http://blog.csdn.net/zhangphil/article/details/51044699
3,《基于Android官方DrawerLayout实现抽屉导航菜单》链接地址:http://blog.csdn.net/zhangphil/article/details/48710453 
4,《Android Material Design: NavigationView抽屉导航菜单》链接地址:http://blog.csdn.net/zhangphil/article/details/48931221

相关文章
|
9月前
|
小程序
去掉微信小程序按钮边框
去掉微信小程序按钮边框
231 1
|
Android开发
关于安卓竖直滚动文字自定义控件的探索
安卓竖直滚动文字自定义控件
94 0
我的Qt作品(4)实现可折叠和伸缩的自定义Widget--抽屉控件
我的Qt作品(4)实现可折叠和伸缩的自定义Widget--抽屉控件
694 0
我的Qt作品(4)实现可折叠和伸缩的自定义Widget--抽屉控件
|
iOS开发
uwp - ContentDialog - 自定义仿iphone提示框,提示框美化
原文:uwp - ContentDialog - 自定义仿iphone提示框,提示框美化 为了实现我想要的效果花费了我很长时间,唉,当初英语不好好学,翻官网翻了半天才找到,分享给刚入门的新手。   首先看一张图片示例,我们要模仿的dialog就是长这样的:     做出来的效果图: 【代码】 XAML【MainPage.
1275 0
通通玩blend美工(6)上——仿iPhone滚动选择器的ListBox(UI设计)
原文:通通玩blend美工(6)上——仿iPhone滚动选择器的ListBox(UI设计)       好久没更新博客了,由于项目比较紧,期间收到不少园友的短消息,感谢大家对我的支持~~。   相信各位都在自己的神机中看到过各种滚动选择器,偶们项目经理就是个iPhone迷,前几天一直抬着个手机对我说"这个炫,做这个...".于是就有了这个选择器。
1034 0
|
Android开发
【Android视图效果】仿QQ空间滑动改变标题栏颜色
最近在倒腾公司之前的项目,发现之前的界面是个白色标题栏,不是很美观,所以做了些改进。 先看效果图 165815uykp80g8y3goo5vz.gif 简单说下思路,整个布局大体上是ScrollView里面包含了一个ImageView和RecyclerView,所以先得到ImageView的高度,当ScrollView向上滑动时,设置标题栏的背景色、文字颜色,当超过ImageView的高度时,设置其背景为白色,字体为黑色。
1132 0
|
Android开发
Android 优化个人封装仿网易新闻可滑动标题栏 TabLayout (文字或图标)
      小菜在向朋友推荐了自己修改封装的仿网易顶部滑动标题栏 TabSlideLayout 滑动内容可以是文字也可以是网络图标,其原型为 FlycoTabLayout,但是因为年代很久远,小菜当时技术太渣,存在一些小问题,后期做过一些优化,今天趁机会整理一下。
2999 0
实现滑动菜单(富文本版本)
所谓的滑动菜单就是将一些菜单选项隐藏起来,而不是放置在主屏幕上,然后可以通过滑动的方式将菜单显示出来。这种方式既节省了屏幕空间,又实现了非常好的动画效果。
692 0
|
Android开发 Kotlin 数据格式
ScrollView滑动—仿微博主页标题栏渐变悬浮及Fragment实现多个内容页面切换
作为一名热爱学习的Android开发工程si,刷微博的时候居然还想着技术呢,觉得自己也是够够了........哈哈哈 image.png 进入今天的正题,微博主页大家肯定是看过的,先看一下微博的效果。
1972 0
[微信小程序]button按钮去除边框圆角
微信小程序中的button默认样式有圆角 如果是直接设置style: 申请退款 然而,并没有什么卵用。。
2187 0