仿QQ5.0侧滑菜单
一.概述
侧滑菜单现在已经非常流行了,目前大概有这么几种:最普通的侧滑,抽屉侧滑,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侧滑菜单的更多相关文章
- 安卓开发笔记——关于开源项目SlidingMenu的使用介绍(仿QQ5.0侧滑菜单)
记得去年年末的时候写过这个侧滑效果,当时是利用自定义HorizontalScrollView来实现的,效果如下: 有兴趣的朋友可以看看这篇文件<安卓开发笔记——自定义HorizontalScro ...
- 【转】仿QQ5.0侧滑菜单ResideMenu
本文由孙国威 原创.如需转载,请注明出处! 原文:http://blog.csdn.net/manoel/article/details/39013095 为了后续对这个项目进行优化,比如透明度动画. ...
- DragLayout: QQ5.0侧拉菜单的新特效
一.项目概要 1.1 项目效果如图: 1.2 需要使用到的技术 ViewDragHelper: 要实现和QQ5.0侧滑的特效,需要借助谷歌在2013年I/O大会上发布的ViewDragHelper ...
- 使用DrawerLayout实现QQ5.0侧拉菜单效果
在上一篇文章中,我们介绍了怎么使用DrawerLayout来实现一个简单的侧拉菜单(使用DrawerLayout实现侧拉菜单),也就是我们常说的抽屉效果,GitHub上类似效果的实现方式非常多,实现出 ...
- Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现
有一段时间没有写博客了,最近比较忙,没什么时间写,刚好今天有点时间, 我就分享下,侧滑菜单的实现原理,一般android侧滑的实现原理和步骤如下:(源码下载在下面最后给出哈) 1.使用ViewGrou ...
- 安卓开发笔记——自定义HorizontalScrollView控件(实现QQ5.0侧滑效果)
对于滑动菜单栏SlidingMenu,大家应该都不陌生,在市场上的一些APP应用里经常可以见到,比如人人网,FaceBook等. 前段时间QQ5.0版本出来后也采用了这种设计风格:(下面是效果图) 之 ...
- 仿qq最新侧滑菜单
为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sungu ...
- 仿QQ5.0以上新版本侧滑效果
1.此效果使用了csdn大神孙国威的代码案例在此感谢附上参考博客地址: http://blog.csdn.net/manoel/article/details/39013095/#plain 2.sl ...
- iOS开发资源:几个类似Path 2.0侧滑菜单的效果实现
IIViewDeckController/ViewDeck 类似 Path 2.0 的视图左右滑动的效果,可向左或者向右顺滑的滑动.支持ARC和non-ARC,默认ARC. https://githu ...
随机推荐
- [android视频教程] 传智播客android开发视频教程
本套视频共有67集,是传智播客3G-Android就业班前8天的的课程量.本套视频教程是黎活明老师在2011年底对传智播客原来的Android核心基础课程精心重新录制的,比早期的Android课程内容 ...
- Java学习|HTTP请求头
https://www.cnblogs.com/honghong87/articles/6941436.html 常见http请求报文头属性 Accept:告诉服务端,客户端接受什么类型的响 ...
- Caddy源码阅读(二)启动流程与 Event 事件通知
Caddy源码阅读(二)启动流程与 Event 事件通知 Preface Caddy 是 Go 语言构建的轻量配置化服务器.https://github.com/caddyserver/caddy C ...
- There’s More Than One Way To Do It!
There’s More Than One Way To Do It!
- JavaScript浮点数运算的精度问题
之前在做浮点数计算时,偶然发现计算结果有误差,度娘了解了下,补充整理了下. 误差是什么样子的呢?举例 console.log(0.1+0.2); // 0.30000000000000004 事实上在 ...
- Python学习 之 计算机基础
第一章 计算机基础 1.1 硬件 计算机基本的硬件由:CPU / 内存 / 主板 / 硬盘 / 网卡 / 显卡 等组成,只有硬件但硬件之间无法进行交流和通信 1.2 操作系统 操作系统用于协同或控制硬 ...
- 操作MySQL-数据库的安装及Pycharm模块的导入
操作MySQL-数据库的安装及Pycharm模块的导入 1.基于pyCharm开发环境,在CMD控制台输入依次输入以下步骤: (1)pip3 install PyMySQL < 安装 PyMy ...
- 使用react定义组件的两种方式
react组件的两种方式:函数定义,类定义 在定义一个组件之前,首先要明白一点:react元素(jsx)是react组件的最基本的组成单位 组件要求: 1,为了和react元素进行区分,组件名字首必须 ...
- Filter(过滤器)(有待补充)
Filter(过滤器) 一.Filter(过滤器)简介 Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的 ...
- c3p0,dbcp与druid 三大连接池的区别[转]
说到druid,这个是在开源中国开源项目中看到的,说是比较好的数据连接池.于是乎就看看.扯淡就到这. 下面就讲讲用的比较多的数据库连接池.(其实我最先接触的是dbcp这个) 1)DBCP DBCP是一 ...