Android仿QQ6.0主页面侧滑效果

1.概述

  最近一直都在带实习生做项目,发现自己好久没有写博客了,这几天更新会比较频繁,今天玩QQ的时候发现QQ主页菜单滑动效果早就变了,实在忍不住晚上就来实现一下了!

2.实现 

  2.1. 实现的方式多种多样
  2.1.1 自定义ViewGroup ,处理其onTouch事件
  2.1.2 FrameLayout + 手势处理类GestureDetector
  2.2.3 使用Google自带的DrawerLayout 对其进行修改
  2.2.4 继承自水平滚动HorizontalScrollView
大家可以看一下这个http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0909/6612.html,这种方式继承自ViewGroup,个人觉得还行但是还是比较繁琐要处理的东西也比较多,那么我就用最后一种2.2.4的方式实现,有人说直接去网上下载一个源代码就可以了,这我就只能GG了。

  2.3. 自定义SlidingMenu extends HorizontalScrollView 然后写好布局文件这个和ScrollView的用法一样,只不过是横向滚动的

/**
 * description:
 * 仿QQ5.0主页面侧滑的自定View
 * Created by 曾辉 on 2016/11/1.
 * QQ:240336124
 * Email: 240336124@qq.com
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 public SlidingMenu(Context context) {
 super(context);
 }

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

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

2.4. 运行起来之后发现布局不对,完全乱了明明都是match_parent可是就是不行那么我们就需要用代码指定菜单和内容的宽度:

菜单的宽度 = 屏幕的宽度 - 自定义的右边留出的宽度
内容的宽度 = 屏幕的宽度

/**
 * description:
 * 仿QQ5.0主页面侧滑的自定View
 * Created by 曾辉 on 2016/11/1.
 * QQ:240336124
 * Email: 240336124@qq.com
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private View mMenuView;
 private View mContentView;
 private int mMenuWidth;

 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);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding,dip2px(50));
 // 计算菜单的宽度 = 屏幕的宽度 - 自定义右边留出的宽度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();
 }

 /**
 * 把dip 转成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());
 }

 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();

 // 1.获取根View也就是外层的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if(containerChildCount>2){
  // 里面只允许放置两个布局 一个是Menu(菜单布局) 一个是Content(主页内容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允许两个布局,菜单布局和主页内容布局");
 }

 // 2.获取菜单和内容布局
 mMenuView = container.getChildAt(0);
 mContentView = container.getChildAt(1);

 // 3.指定内容和菜单布局的宽度
 // 3.1 菜单的宽度 = 屏幕的宽度 - 自定义的右边留出的宽度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 3.2 内容的宽度 = 屏幕的宽度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 /**
 * 获取屏幕的宽度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }
}

目前的效果就是可以滑动,并且菜单和主页面内容的布局宽度正常

  2.5 接下来一开始就让菜单滑动到关闭状态,手指滑动抬起判断菜单打开和关闭并做相应的处理 onLayout() onTouch() smoothScrollTo(),当手指快速的时候切换菜单的状态利用GestureDetector 手势处理类:

 /**
 * description:
 * 仿QQ5.0主页面侧滑的自定View
 * Created by 曾辉 on 2016/11/1.
 * QQ:240336124
 * Email: 240336124@qq.com
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private View mMenuView;
 private View mContentView;
 private int mMenuWidth;
 // 手势处理类 主要用来处理手势快速滑动
 private GestureDetector mGestureDetector;

 // 菜单是否打开
 private boolean mMenuIsOpen = 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);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding, dip2px(50));
 // 计算菜单的宽度 = 屏幕的宽度 - 自定义右边留出的宽度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();

 // 实例化手势处理类
 mGestureDetector = new GestureDetector(context,new GestureListener());
 }

 /**
 * 把dip 转成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
 }

 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();

 // 1.获取根View也就是外层的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if (containerChildCount > 2) {
  // 里面只允许放置两个布局 一个是Menu(菜单布局) 一个是Content(主页内容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允许两个布局,菜单布局和主页内容布局");
 }

 // 2.获取菜单和内容布局
 mMenuView = container.getChildAt(0);
 mContentView = container.getChildAt(1);

 // 3.指定内容和菜单布局的宽度
 // 3.1 菜单的宽度 = 屏幕的宽度 - 自定义的右边留出的宽度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 3.2 内容的宽度 = 屏幕的宽度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {

 // 处理手指快速滑动
 if(mGestureDetector.onTouchEvent(ev)){
  return mGestureDetector.onTouchEvent(ev);
 }

 switch (ev.getAction()) {
  case MotionEvent.ACTION_UP:
  // 手指抬起获取滚动的位置
  int currentScrollX = getScrollX();
  if (currentScrollX > mMenuWidth / 2) {
   // 关闭菜单
   closeMenu();
  } else {
   // 打开菜单
   openMenu();
  }
  return false;
 }
 return super.onTouchEvent(ev);
 }

 /**
 * 打开菜单
 */
 private void openMenu() {
 smoothScrollTo(0, 0);
 mMenuIsOpen = true;
 }

 /**
 * 关闭菜单
 */
 private void closeMenu() {
 smoothScrollTo(mMenuWidth, 0);
 mMenuIsOpen = false;
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 // 布局指定后会从新摆放子布局,当其摆放完毕后,让菜单滚动到不可见状态
 if (changed) {
  scrollTo(mMenuWidth, 0);
 }
 }

 /**
 * 获取屏幕的宽度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }

 private class GestureListener extends GestureDetector.SimpleOnGestureListener{
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  // 当手指快速滑动时候回调的方法
  Log.e("TAG",velocityX+"");
  // 如果菜单打开 并且是向左快速滑动 切换菜单的状态
  if(mMenuIsOpen){
  if(velocityX<-500){
   toggleMenu();
   return true;
  }
  }else{
  // 如果菜单关闭 并且是向右快速滑动 切换菜单的状态
  if(velocityX>500){
   toggleMenu();
   return true;
  }
  }

  return false;
 }
 }

 /**
 * 切换菜单的状态
 */
 private void toggleMenu() {
 if(mMenuIsOpen){
  closeMenu();
 }else{
  openMenu();
 }
 }
}

到了这一步之后我们就可以切换菜单了,并且处理了手指快速滑动,迫不及待的看下效果

2.6. 实现菜单左边抽屉样式的动画效果,监听滚动回调的方法onScrollChanged() 这个就非常简单了一句话就搞定,效果就不看了一起看终极效果吧

@Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 super.onScrollChanged(l, t, oldl, oldt);

 // l 是 当前滚动的x距离 在滚动的时候会不断反复的回调这个方法
 Log.e(TAG,l+"");

 mMenuView.setTranslationX(l*0.8f);
 }

2.7. 实现菜单右边菜单的阴影透明度效果,这个打算在主页面内容布局上面加一层阴影,用ImageView即可,那么我们的内容View就需要换了

/**
 * description:
 * 仿QQ5.0主页面侧滑的自定View
 * Created by 曾辉 on 2016/11/1.
 * QQ:240336124
 * Email: 240336124@qq.com
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private static final String TAG = "HorizontalScrollView";
 private Context mContext;

 // 4.给菜单和内容View指定宽高 - 左边菜单View
 private View mMenuView;

 // 4.给菜单和内容View指定宽高 - 菜单的宽度
 private int mMenuWidth;
 // 5.3 手势处理类 主要用来处理手势快速滑动
 private GestureDetector mGestureDetector;
 // 5.3 菜单是否打开
 private boolean mMenuIsOpen = false;

 // 7(4). 主页面内容View的布局包括阴影ImageView
 private ViewGroup mContentView;
 // 7.给内容添加阴影效果 - 阴影的ImageView
 private ImageView mShadowIv;

 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);
 //4.1 计算左边菜单的宽度
 //4.1.1 获取自定义的右边留出的宽度
 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding, dip2px(50));
 // 4.1.2 计算菜单的宽度 = 屏幕的宽度 - 自定义右边留出的宽度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();

 // 5.3 实例化手势处理类
 mGestureDetector = new GestureDetector(context,new GestureListener());

 this.mContext = context;
 }

 /**
 * 把dip 转成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
 }

 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();
 // 4.2 指定菜单和内容View的宽度
 // 4.2.1.获取根View也就是外层的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if (containerChildCount > 2) {
  // 里面只允许放置两个布局 一个是Menu(菜单布局) 一个是Content(主页内容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允许两个布局,菜单布局和主页内容布局");
 }

 // 4.2.2.获取菜单和内容布局
 mMenuView = container.getChildAt(0);

 // 7.给内容添加阴影效果
 // 7.1 先new一个主内容布局用来放 阴影和LinearLayout原来的内容布局
 mContentView = new FrameLayout(mContext);
 ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams(
  ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);

 // 7.2 获取原来的内容布局,并把原来的内容布局从LinearLayout中异常
 View oldContentView = container.getChildAt(1);
 container.removeView(oldContentView);

 // 7.3 把原来的内容View 和 阴影加到我们新创建的内容布局中
 mContentView.addView(oldContentView);
 // 7.3.1 创建阴影ImageView
 mShadowIv = new ImageView(mContext);
 mShadowIv.setBackgroundColor(Color.parseColor("#99000000"));
 mContentView.addView(mShadowIv);

 // 7.4 把包含阴影的新的内容View 添加到 LinearLayout中
 container.addView(mContentView);

 // 4.2.3.指定内容和菜单布局的宽度
 // 4.2.3.1 菜单的宽度 = 屏幕的宽度 - 自定义的右边留出的宽度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 4.2.3.2 内容的宽度 = 屏幕的宽度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 /**
 * 5.处理手指抬起和快速滑动切换菜单
 */
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
 // 5.3 处理手指快速滑动
 if(mGestureDetector.onTouchEvent(ev)){
  return mGestureDetector.onTouchEvent(ev);
 }

 switch (ev.getAction()) {
  case MotionEvent.ACTION_UP:
  // 5.1 手指抬起获取滚动的位置
  int currentScrollX = getScrollX();
  if (currentScrollX > mMenuWidth / 2) {
   // 5.1.1 关闭菜单
   closeMenu();
  } else {
   // 5.1.2 打开菜单
   openMenu();
  }
  return false;
 }
 return super.onTouchEvent(ev);
 }

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 super.onScrollChanged(l, t, oldl, oldt);

 // l 是 当前滚动的x距离 在滚动的时候会不断反复的回调这个方法
 Log.e(TAG,l+"");
 // 6. 实现菜单左边抽屉样式的动画效果
 mMenuView.setTranslationX(l*0.8f);

 // 7.给内容添加阴影效果 - 计算梯度值
 float gradientValue = l * 1f / mMenuWidth;// 这是 1 - 0 变化的值

 // 7.给内容添加阴影效果 - 给阴影的View指定透明度 0 - 1 变化的值
 float shadowAlpha = 1 - gradientValue;
 mShadowIv.setAlpha(shadowAlpha);
 }

 /**
 * 5.1.2 打开菜单
 */
 private void openMenu() {
 smoothScrollTo(0, 0);
 mMenuIsOpen = true;
 }

 /**
 * 5.1.1 关闭菜单
 */
 private void closeMenu() {
 smoothScrollTo(mMenuWidth, 0);
 mMenuIsOpen = false;
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 // 布局指定后会从新摆放子布局,当其摆放完毕后,让菜单滚动到不可见状态
 if (changed) {
  scrollTo(mMenuWidth, 0);
 }
 }

 /**
 * 获取屏幕的宽度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }

 /**
 * 5.3 处理手指快速滑动
 */
 private class GestureListener extends GestureDetector.SimpleOnGestureListener{
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  // 当手指快速滑动时候回调的方法
  Log.e(TAG,velocityX+"");
  // 5.3.1 如果菜单打开 并且是向左快速滑动 切换菜单的状态
  if(mMenuIsOpen){
  if(velocityX<0){
   toggleMenu();
   return true;
  }
  }else{
  // 5.3.2 如果菜单关闭 并且是向右快速滑动 切换菜单的状态
  if(velocityX>0){
   toggleMenu();
   return true;
  }
  }
  return false;
 }
 }

 /**
 * 切换菜单的状态
 */
 private void toggleMenu() {
 if(mMenuIsOpen){
  closeMenu();
 }else{
  openMenu();
 }
 }
}

我们来看一下最后的效果吧,最终代码量不是很多啦,需要的请下载源码,如果是实现QQ5.0或是酷狗的侧滑效果可以自己改改。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android程序开发之使用Design包实现QQ动画侧滑效果和滑动菜单导航

    Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件.最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2.这不得不说是一个良心之作. 使用方法很简单,只需要添加一句依赖 compile 'com.android

  • Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一)

    QQ是大家离不开的聊天工具,方便既实用,自从qq更新至6.0之后,侧滑由原来的划出后主面板缩小变成了左右平滑,在外观上有了很大的提升,于是我就是尝试理解下里面的各种逻辑,结合相关资料,研究研究. 知道这里面的一个主要类是ViewDragHelper,那么首先我们要先来了解一下这个ViewDragHelper类,正所谓打蛇打七寸,我们就先来看看官方文档怎么介绍的,有什么奇特的功能. 首先继承: java.lang.Object android.support.v4.widget.ViewDragH

  • Android自定义view系列之99.99%实现QQ侧滑删除效果实例代码详解

    首先声明本文是基于GitHub上"baoyongzhang"的SwipeMenuListView修改而来,该项目地址: https://github.com/baoyongzhang/SwipeMenuListView 可以说这个侧滑删除效果是我见过效果最好且比较灵活的项目,没有之一!!! 但是在使用它之前需要给大家提两点注意事项: 1,该项目支持Gradle dependence,但是目前作者提供的依赖地址对应的项目不是最新的项目,依赖过后的代码与demo中使用的不一致,会提示没有B

  • 基于Android实现仿QQ5.0侧滑

    本课程将带领大家通过自定义控件实现QQ5.0侧滑菜单,课程将循序渐进,首先实现最普通的侧滑菜单,然后引入属性动画与拖动菜单效果相结合,最终实现QQ5.0侧滑菜单效果.通过本课程大家会对侧滑菜单有更深层次的了解,通过自定义控件和属性动画打造千变万化的侧滑菜单效果 效果图如下所示: package com.example; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android

  • Android高仿QQ6.0侧滑删除实例代码

    推荐阅读: 先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(TextView也可以),然后我们可以向左侧滑动,然后显示出来,然后对delete(删除键)实现监听,就可以了哈.好了那就来看看代码怎么实现的吧. 首先和之前一样 自定义View,初始化ViewDragHelper: package com.example.removesidepull; import android.content.Context; import android.support.v4.wi

  • Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码

    (一).前言: 这两天QQ进行了重大更新(6.X)尤其在UI风格上面由之前的蓝色换成了白色居多了,侧滑效果也发生了一些变化,那我们今天来模仿实现一个QQ6.X版本的侧滑界面效果.今天我们还是采用神器ViewDragHelper来实现. 本次实例具体代码已经上传到下面的项目中,欢迎各位去star和fork一下. https://github.com/jiangqqlmj/DragHelper4QQ FastDev4Android框架项目地址:https://github.com/jiangqqlm

  • Android基于ViewDragHelper仿QQ5.0侧滑界面效果

    QQ5.0侧滑效果实现方案有很多方式,今天我们使用ViewDragHelper来实现一下. 先上效果图: ①自定义控件SlidingMenu继承FrameLayout,放在FrameLayout上面的布局一层叠着者一层,通过getChildAt()可以很方便的获取到任意一层,进而控制此布局的变化. public class SlidingMenu extends FrameLayout { private ViewDragHelper mViewDragHelper; private int m

  • Android滑动优化高仿QQ6.0侧滑菜单(滑动优化)

     推荐阅读:Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一) 但是之前的实现,只是简单的可以显示和隐藏左侧的菜单,但是特别生硬,而且没有任何平滑的趋势,那么今天就来优化一下吧,加上平滑效果,而且可以根据手势滑动的方向来判断是否是显示和隐藏. 首先先来实现手势判断是否隐藏和显示 这里就要用到了一个方法了,如下: 这个是ViewDradHelper里面的方法: /** * 当view被释放的时候处理的事情(松手) * * @param releasedChild 被释放的

  • Android自定义布局实现仿qq侧滑部分代码

    自定义布局实现仿qq侧滑部分Android代码,供大家参考,具体内容如下 源码DEMO地址:https://github.com/applelili/ImitationQQ 实现说明: 通过自定义布局实现: SlidingLayout继承于 HorizontalScrollView /** * Created by Administrator on 2017/3/29. */ public class SlidingLayout extends HorizontalScrollView{ /**

  • Android使用DrawerLayout实现仿QQ双向侧滑菜单

    1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面,这玩意用起来的确方便,于是简单写了个demo,高仿QQ5.2双向侧滑,分享给大家. 首先看看效果图: DrawerLayout用起来真的很方便,下面一起看看用法~ 2.DrawerLayout的使用 直接将DrawerLayout作为根布局,然后其内部第一个View为内容区域,第二个View为左侧

随机推荐