一.概述

侧滑菜单现在已经非常流行了,目前大概有这么几种:最普通的侧滑,抽屉侧滑,QQ侧滑

注:本文来自慕课网

二.最普通的侧滑

先上图

代码如下:

 public class MainActivity extends Activity {
private SlidingMenuView mLeftMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLeftMenu = (SlidingMenuView) findViewById(R.id.id_menu);
} public void toggleMenu(View view) {
mLeftMenu.toggle();
}
}

以上是 MainActivity

public class SlidingMenuView extends HorizontalScrollView {
private LinearLayout wapper;// 这是该横向水平滚动条里面的 第一个线性布局,和activity_main.xml对应
private ViewGroup menu; // 左侧菜单区域
private ViewGroup content;// 右边内容区域
private int screenWidth;// 屏幕宽度
private int menuRightPadding = 50; // 菜单距屏幕右侧边框距离,单位dp
private boolean once;
private boolean isOpen;
private int mMenuWidth;//菜单宽度 /** 未使用自定义属性时,调用 */
public SlidingMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wm = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
screenWidth = outMetrics.widthPixels;// 得到屏幕宽度
//dp转成xp
menuRightPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics());//将50dp转成像素值
} /***
* 自定义控件重写方法1 该方法能够测量 子view 以及 自己的宽高 该方法可能被多次执行,所以定义一个标记once,让它只调用一次,不要多次设置宽高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
wapper = (LinearLayout) getChildAt(0);// 初始化该线性布局,因为是第一个所以childAt(0)
menu = (ViewGroup) wapper.getChildAt(0);// 得到菜单布局容器
content = (ViewGroup) wapper.getChildAt(1);// 得到内容布局容器
mMenuWidth = menu.getLayoutParams().width
= screenWidth - menuRightPadding;//菜单宽度
content.getLayoutParams().width = screenWidth;//内容宽度就是 屏幕宽度
wapper.getLayoutParams().width = mMenuWidth + screenWidth;//这句可以不写,因为它是放在水平滚动内部的
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /***
* 自定义控件重写方法2 设置子view 的位置
* 要求content显示 内容区域
* menu 缩到左边
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed){
//设置偏移量,将menu隐藏 ,x为正值 ,表示滚动条向右移动,那么内容区域就向左移动,mMenuWidth是x轴移动宽度
this.scrollTo(mMenuWidth, 0);
}
}
/***
* 自定义控件重写方法3
* 控制手势,因为 HorizontalScrollView能自动控制 手势 按下,移动,所以这里只需要处理 up
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_UP:
// 隐藏在左边的宽度
int scrollX = getScrollX();
if (scrollX >= mMenuWidth / 2){ //大于菜单布局的 1/2 就隐藏菜单
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else{
this.smoothScrollTo(0, 0);//显示出来菜单内容,也就是x轴偏移量scrollX=0
isOpen = true;
}
return true;
}
return super.onTouchEvent(ev);
} /**
* 打开菜单
*/
public void openMenu()
{
if (isOpen)
return;
this.smoothScrollTo(0, 0);//smoothScrollto带有动画效果
isOpen = true;
} public void closeMenu()
{
if (!isOpen)
return;
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} /**
* 切换菜单
*/
public void toggle()
{
if (isOpen)
{
closeMenu();
} else
{
openMenu();
}
} }

以上是自定义HorizontalScrollView ,注释已经非常详细了

<RelativeLayout 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" > <com.example.slidingmenu.SlidingMenuView
android:id="@+id/id_menu"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<!-- 左侧菜单 -->
<include layout="@layout/left_menu"/>
<!-- 真正的内容区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq" > <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="toggleMenu"
android:text="切换菜单" />
</LinearLayout>
</LinearLayout>
</com.example.slidingmenu.SlidingMenuView> </RelativeLayout>

以上是 activity_main.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:background="@drawable/img_frame_background"
android:orientation="vertical" > <RelativeLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:id="@+id/ll1"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/img_1" /> <TextView
android:textColor="#ffffff"
android:layout_marginLeft="20dp"
android:layout_gravity="center"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个Item" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll2"
android:layout_below="@+id/ll1"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/img_2" /> <TextView
android:textColor="#ffffff"
android:layout_marginLeft="20dp"
android:layout_gravity="center"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第二个Item" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll3"
android:layout_below="@+id/ll2"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/img_3" /> <TextView
android:textColor="#ffffff"
android:layout_marginLeft="20dp"
android:layout_gravity="center"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第三个Item" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll4"
android:layout_below="@+id/ll3"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/img_4" /> <TextView
android:textColor="#ffffff"
android:layout_marginLeft="20dp"
android:layout_gravity="center"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第四个Item" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll5"
android:layout_below="@+id/ll4"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/img_5" /> <TextView
android:textColor="#ffffff"
android:layout_marginLeft="20dp"
android:layout_gravity="center"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第五个Item" />
</LinearLayout>
</RelativeLayout> </LinearLayout>

上面是菜单布局.

源码地址:https://yunpan.cn/cq6nntbEBNmbW  访问密码 94c5

三.抽屉侧滑

抽屉侧滑,和普通侧滑最大区别是 , menu 菜单部分是静止的,只有内容区域在滑动

代码如下:

package com.example.slidingmenu;

import com.nineoldandroids.view.ViewHelper;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout; public class SlidingMenuView extends HorizontalScrollView {
private LinearLayout wapper;// 这是该横向水平滚动条里面的 第一个线性布局,和activity_main.xml对应
private ViewGroup menu; // 左侧菜单区域
private ViewGroup content;// 右边内容区域
private int screenWidth;// 屏幕宽度
private int menuRightPadding = 50; // 菜单距屏幕右侧边框距离,单位dp
private boolean once;
private boolean isOpen;
private int mMenuWidth;//菜单宽度 public SlidingMenuView(Context context) {
this(context,null,0);
} /** 未使用自定义属性时,调用 */
public SlidingMenuView(Context context, AttributeSet attrs) {
this(context, attrs,0);
} /**
* 当使用了自定义属性时,会调用此构造方法
*/
public SlidingMenuView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//获取自定义属性 ,这个设置后,可以在xml中自定义menu距右边框距离
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyle, 0);
menuRightPadding = ta.getDimensionPixelSize(R.styleable.SlidingMenu_rightPadding, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics()));
ta.recycle(); WindowManager wm = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
screenWidth = outMetrics.widthPixels;// 得到屏幕宽度
} /***
* 自定义控件重写方法1 该方法能够测量 子view 以及 自己的宽高 该方法可能被多次执行,所以定义一个标记once,让它只调用一次,不要多次设置宽高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
wapper = (LinearLayout) getChildAt(0);// 初始化该线性布局,因为是第一个所以childAt(0)
menu = (ViewGroup) wapper.getChildAt(0);// 得到菜单布局容器
content = (ViewGroup) wapper.getChildAt(1);// 得到内容布局容器
mMenuWidth = menu.getLayoutParams().width
= screenWidth - menuRightPadding;//菜单宽度
content.getLayoutParams().width = screenWidth;//内容宽度就是 屏幕宽度
wapper.getLayoutParams().width = mMenuWidth + screenWidth;//这句可以不写,因为它是放在水平滚动内部的
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /***
* 自定义控件重写方法2 设置子view 的位置
* 要求content显示 内容区域
* menu 缩到左边
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed){
//设置偏移量,将menu隐藏 ,x为正值 ,表示滚动条向右移动,那么内容区域就向左移动,mMenuWidth是x轴移动宽度
this.scrollTo(mMenuWidth, 0);
}
}
/***
* 自定义控件重写方法3
* 控制手势,因为 HorizontalScrollView能自动控制 手势 按下,移动,所以这里只需要处理 up
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_UP:
// 隐藏在左边的宽度
int scrollX = getScrollX();
if (scrollX >= mMenuWidth / 2){ //大于菜单布局的 1/2 就隐藏菜单
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else{
this.smoothScrollTo(0, 0);//显示出来菜单内容,也就是x轴偏移量scrollX=0
isOpen = true;
}
return true;
}
return super.onTouchEvent(ev);
} /**
* 打开菜单
*/
public void openMenu()
{
if (isOpen)
return;
this.smoothScrollTo(0, 0);//smoothScrollto带有动画效果
isOpen = true;
} public void closeMenu(){
if (!isOpen)
return;
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} /**
* 切换菜单
*/
public void toggle(){
if (isOpen){
closeMenu();
} else{
openMenu();
}
}
/**
* l是偏移量, 就是getScrollX()
* t 和 oldl,oldt是变化的梯度值
* 为兼容3.0以下使用 nineoldandroids-2.4.0.jar里面的动画
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//滚动发生时,调用属性动画,设置TranslationX
float scale = l * 1.0f / mMenuWidth; // 1 ~ 0()
//设置动画, menu偏移量从 1~0显示
ViewHelper.setTranslationX(menu, mMenuWidth*scale);
}
}

和图片侧滑自定义view很相似,只是这里引入了 ,自定义属性 以及重写了 onScrollChanged

<RelativeLayout 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" > <com.example.slidingmenu.SlidingMenuView
android:id="@+id/id_menu"
app:rightPadding="80dp"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<!-- 左侧菜单 -->
<include layout="@layout/left_menu"/>
<!-- 真正的内容区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq" > <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="toggleMenu"
android:text="切换菜单" />
</LinearLayout>
</LinearLayout>
</com.example.slidingmenu.SlidingMenuView> </RelativeLayout>

以上是Activity_main.xml 只是加入一个 自定义属性:app:rightPadding="80dp" 此处可以任意设置 menu菜单布局距右边框距离

MainActivity没有做任何变动,不再给出. 需要注意的是: 如果是eclipse创建的工程,默认会导入v7包, 会引入一些主题样式, 可能会导致nineoldandroid.jar失效,我的解决方式是要么用android studio创建工程, 要么 把Eclipse创建的工程 的v7包干掉, 然后去掉主题,就好了.

一般情况下,侧护栏做到抽屉侧滑基本就算完成了, 市面很多应用侧滑 基本都是抽屉侧滑. 当然如果想更炫,那就仿QQ侧滑,或者 其他第三方侧滑库

代码地址:https://yunpan.cn/cqMt3ez6Yvm93  访问密码 89d5

四.QQ5.0侧滑

在抽屉侧滑的 自定义View的基础上 ,只需要变动onScrollChanged() 该方法即可

protected void onScrollChanged(int l, int t, int oldl, int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth; // 1 ~ 0 /**
* 区别1:内容区域1.0~0.7 范围变化缩放效果 scale : 1.0~0.0 0.7 + 0.3 * scale
*
* 区别2:菜单的偏移量需要修改
*
* 区别3:菜单的显示时有缩放以及透明度变化 缩放:0.7 ~1.0 1.0 - scale * 0.3 透明度 0.6 ~ 1.0
* 0.6+ 0.4 * (1- scale) ;
*
*/
float rightScale = 0.7f + 0.3f * scale;
float leftScale = 1.0f - scale * 0.3f;
float leftAlpha = 0.6f + 0.4f * (1 - scale); // 调用属性动画,设置TranslationX
ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.8f);
//设置菜单布局的缩放
ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu, leftScale);
ViewHelper.setAlpha(mMenu, leftAlpha);
/** 设置content的缩放的中心点, 如果此处不设置中心点会造成menu菜单直接滑到屏幕右边框
* 因为动画刚开始以mContent内容布局的中心点开始的. 等滑到屏幕右边后
* 要设置中心点 变换到 mContent的 Y轴方向的中心点, X轴为0点
*/
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
//设置 内容布局的 缩放
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale); }

以上就是 所有侧滑的过程分析.

仿QQ5.0侧滑菜单的更多相关文章

  1. 安卓开发笔记——关于开源项目SlidingMenu的使用介绍(仿QQ5.0侧滑菜单)

    记得去年年末的时候写过这个侧滑效果,当时是利用自定义HorizontalScrollView来实现的,效果如下: 有兴趣的朋友可以看看这篇文件<安卓开发笔记——自定义HorizontalScro ...

  2. 【转】仿QQ5.0侧滑菜单ResideMenu

    本文由孙国威 原创.如需转载,请注明出处! 原文:http://blog.csdn.net/manoel/article/details/39013095 为了后续对这个项目进行优化,比如透明度动画. ...

  3. DragLayout: QQ5.0侧拉菜单的新特效

    一.项目概要 1.1 项目效果如图: 1.2 需要使用到的技术   ViewDragHelper: 要实现和QQ5.0侧滑的特效,需要借助谷歌在2013年I/O大会上发布的ViewDragHelper ...

  4. 使用DrawerLayout实现QQ5.0侧拉菜单效果

    在上一篇文章中,我们介绍了怎么使用DrawerLayout来实现一个简单的侧拉菜单(使用DrawerLayout实现侧拉菜单),也就是我们常说的抽屉效果,GitHub上类似效果的实现方式非常多,实现出 ...

  5. Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现

    有一段时间没有写博客了,最近比较忙,没什么时间写,刚好今天有点时间, 我就分享下,侧滑菜单的实现原理,一般android侧滑的实现原理和步骤如下:(源码下载在下面最后给出哈) 1.使用ViewGrou ...

  6. 安卓开发笔记——自定义HorizontalScrollView控件(实现QQ5.0侧滑效果)

    对于滑动菜单栏SlidingMenu,大家应该都不陌生,在市场上的一些APP应用里经常可以见到,比如人人网,FaceBook等. 前段时间QQ5.0版本出来后也采用了这种设计风格:(下面是效果图) 之 ...

  7. 仿qq最新侧滑菜单

    为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sungu ...

  8. 仿QQ5.0以上新版本侧滑效果

    1.此效果使用了csdn大神孙国威的代码案例在此感谢附上参考博客地址: http://blog.csdn.net/manoel/article/details/39013095/#plain 2.sl ...

  9. iOS开发资源:几个类似Path 2.0侧滑菜单的效果实现

    IIViewDeckController/ViewDeck 类似 Path 2.0 的视图左右滑动的效果,可向左或者向右顺滑的滑动.支持ARC和non-ARC,默认ARC. https://githu ...

随机推荐

  1. 开园第一篇---有关tensorflow加载不同模型的问题

    写在前面 今天刚刚开通博客,主要想法跟之前某位博主说的一样,希望通过博客园把每天努力的点滴记录下来,也算一种坚持的动力.我是小白一枚,有啥问题欢迎各位大神指教,鞠躬~~ 换了新工作,目前手头是OCR项 ...

  2. java 购物商城小项目训练

    java web 模拟购物车练习(项目一) 首页(index.jsp) <div align="center" class="index"> < ...

  3. mysql的引擎问题,主键和外键的创建问题,以及创建外键不成功,却创建了一个索引

    mysql的引擎问题: 需要知道的三个引擎:InnoDB--是一个事务处理引擎,不支持全文检索,支持事务操作,即DML操作: Memory--是一个数据存储在内存,速度很快,功能上等同于MyIsam, ...

  4. 配置Windows Server 2008环境

    上一章已经把Windows Server2008操作系统安装完毕,接下来配置一下Windows Server环境.配置网络和共享中心.配置桌面环境.配置用户IE设置.安装Telnet远程工具.配置文件 ...

  5. 普通Apache的安装与卸载

    Apache安装与卸载ctrl+F快捷查找 1.下载apache 64位解压 官网:http://httpd.apache.org/ 文件使用记事本或者sublime2.修改 打开apache目录下的 ...

  6. ggplot2: how to check the color and coreponding value pairs

    The way to check the color and coreponding value pairs in ggplot2 To see what colors are used to mak ...

  7. Java笔记(持续更新中)

    Java语言的特点: 面向对象(封装,继承,多态) 平台无关性(JVM运行.class文件) 语言(泛型,Lambda) 类库(集合,并发,网络,IO/NIO) JRE(Java运行环境,JVM,类 ...

  8. MySQL MGR集群单主模式的自动搭建和自动化故障修复

    随着MySQL MGR的版本的升级以及技术成熟,在把MHA拉下神坛之后, MGR越来越成为MySQL高可用的首选方案.MGR的搭建并不算很复杂,但是有一系列手工操作步骤,为了简便MGR的搭建和故障诊断 ...

  9. java 局部变量成员变量区别

    首先,成员变量可直接初始化(即赋值),也可不赋值,不赋值java按照以下类型自动赋值 局部变量调用前必须初始化(赋值),java不会自动处理 局部变量可以和成员变量重名(但不建议),如果在当前对象的方 ...

  10. git之旅,畅游git的世界

    今天小铭酱带大家探索一下git的奥秘! 1.初步探索 首先我在一个空的文件夹新建了一个名叫hello.html文件,文件内容只有一句话“hello git”.我们先引入git,看看git能为我们它能干 ...