欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-03 21:23:16
1.概述   最近一直都在带实习生做项目,发现自己好久没有写博客了,这几天更新会比较频繁,今天玩qq的时候发现qq主页菜单滑动效果早就变了,实在忍不住晚上就来实现一下了!...

1.概述

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

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

2.实现 

  2.1. 实现的方式多种多样
  2.1.1 自定义viewgroup ,处理其ontouch事件
  2.1.2 framelayout + 手势处理类gesturedetector
  2.2.3 使用google自带的drawerlayout 对其进行修改
  2.2.4 继承自水平滚动horizontalscrollview
大家可以看一下这个,这种方式继承自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;
 }
}

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

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

  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();
 }
 }
}

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

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

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或是酷狗的侧滑效果可以自己改改。

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

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