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

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

程序员文章站 2024-03-04 16:37:41
qq5.0侧滑效果实现方案有很多方式,今天我们使用viewdraghelper来实现一下。 先上效果图: ①自定义控件slidingmenu继承framelay...

qq5.0侧滑效果实现方案有很多方式,今天我们使用viewdraghelper来实现一下。

先上效果图:

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

①自定义控件slidingmenu继承framelayout,放在framelayout上面的布局一层叠着者一层,通过getchildat()可以很方便的获取到任意一层,进而控制此布局的变化。

public class slidingmenu extends framelayout {

 private viewdraghelper mviewdraghelper;

 private int mheight;// 当前控件的高度
 private int mwidhth;// 当前控件的宽度
 private int mrange; // 菜单移动的距离

 private viewgroup mmenu;// 菜单内容
 private viewgroup mcontent; // 主页面内容

 private boolean isopen = 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);

 // 初始化viewdraghelper
 mviewdraghelper = viewdraghelper.create(this, callback);
 }
}

②接下来我们在布局文件中使用我们自定的slidingmenu,根据布局,我们一步一步实现slidingmenu.

<?xml version="1.0" encoding="utf-8"?>
<com.yitong.myslidingmenu2.view.slidingmenu
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/main_slidingmenu"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@mipmap/bg"
 android:orientation="horizontal"
 tools:context="com.yitong.myslidingmenu2.mainactivity">

 <include layout="@layout/left_menu"/>

 <linearlayout
 android:id="@+id/main_content"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@mipmap/qq"
 android:orientation="horizontal">

 <button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:onclick="click"
  android:text="切换菜单"/>

 </linearlayout>
</com.yitong.myslidingmenu2.view.slidingmenu>

③如果想实现侧滑,自定义控件中必须包含两个布局,在我们的slidingmenu中的onfinishinflate方法中加以判断,并且获取菜单和主页面。在onsizechanged获取到菜单滑出的宽和高。

@override
protected void onfinishinflate() {
 super.onfinishinflate();

 if (getchildcount() < 2) {
  throw new illegalstateexception("使用slidingmenu中必须包含两个view");
 }
 if (!(getchildat(0) instanceof viewgroup && getchildat(1) instanceof viewgroup)) {
  throw new illegalstateexception("子view必须是viewgroup的子类");
 }

 mmenu = (viewgroup) getchildat(0);
 mcontent = (viewgroup) getchildat(1);
 }

 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh) {
 super.onsizechanged(w, h, oldw, oldh);
 mheight = getmeasuredheight();
 mwidhth = getmeasuredwidth();
 mrange = (int) (mwidhth * 0.8);
 }

④使用viewdraghelper,需要把当前控件的时间交给viewdraghelper处理。

@override
public boolean onintercepthoverevent(motionevent event) {
 // 把触摸事件传递给viewdraghelper
 return mviewdraghelper.shouldintercepttouchevent(event);
}

@override
public boolean ontouchevent(motionevent event) {
 try {
 mviewdraghelper.processtouchevent(event);// 让viewdragehelper处理触摸事件
 } catch (exception e) {
 e.printstacktrace();
 }
 return true;
}

⑤viewdraghelper的关键代码

private callback callback = new callback() {

 @override
 public boolean trycaptureview(view child, int pointerid) {
 return true;// child:当前被拖拽的view.返回true表示当前view可以被拖拽
 }

 @override
 public int getviewhorizontaldragrange(view child) {
 return mrange;// 返回拖拽的距离,并不对拖拽进行限制,决定了动画的执行速度
 }

 @override
 public int clampviewpositionhorizontal(view child, int left, int dx) { // 根据建议值,修订水平方向移动的距离
 if (child == mcontent) { // ①滑动主页面内容,当超过屏幕预留宽度时,不再滑动。②向左滑动不能为负
  left = fixcontentslidrange(left);
 }
 return left;
 }

 @override
 public void onviewpositionchanged(view changedview, int left, int top, int dx, int dy) {// 当view的位置改变时调用,可以在此方法中添加一些view特效
 super.onviewpositionchanged(changedview, left, top, dx, dy);
 // 当我们滑动菜单内容时,保持菜单内容不动,转化为主页面内容移动
 int movecontentleft = left;// 主页面内容左边的距离
 if (changedview == mmenu) {
  movecontentleft = mcontent.getleft() + left;
  mmenu.layout(0, 0, mmenu.getheight(), mmenu.getheight());// 强制菜单不移动
 }
 movecontentleft = fixcontentslidrange(movecontentleft);
 mcontent.layout(movecontentleft, 0, movecontentleft + mcontent.getwidth(), mcontent.getheight());

 animshow(movecontentleft);// 菜单打开时,一些动画

 invalidate();// 重绘界面,兼容低版本
 }

 @override
 public void onviewreleased(view releasedchild, float xvel, float yvel) {// 当view松手时触发,处理自动平滑动画
 super.onviewreleased(releasedchild, xvel, yvel);
 if (xvel > 0) { // 水平速度+
  open();
 } else if (xvel == 0 && mcontent.getleft() > mrange / 2.0f) { // 手指在菜单滑出一半多时抬起
  open();
 } else {
  close();
 }
 }
};

 /**
 * 修订主页面的滑动距离
 */
 private int fixcontentslidrange(int left) {
 if (left > mrange) {
  return mrange;
 } else if (left < 0) {
  return 0;
 }
 return left;
 }

/** 伴随动画 */
private void animshow(int movecontentleft) {
 float percent = movecontentleft * 1.0f / mrange;// 0~1

 /**
 * 分析:
 * 菜单区域:位移动画,缩放动画,渐变动画
 * 内容区域:缩放动画
 * 背景区域:亮度变化
 */
 viewhelper.settranslationx(mmenu, evaluate(percent, -mrange / 1.2f, 0));// 位移动画
 viewhelper.setscalex(mmenu, evaluate(percent, 0.6f, 1.0f));// 缩放动画
 viewhelper.setscaley(mmenu, evaluate(percent, 0.6f, 1.0f));
 viewhelper.setalpha(mmenu, evaluate(percent, 0.1f, 1.0f));// 渐变动画

 viewhelper.setpivotx(mcontent, 0);// 缩放中心
 viewhelper.setpivoty(mcontent, mheight / 2);
 viewhelper.setscalex(mcontent, evaluate(percent, 1.0f, 0.9f));// 缩放动画
 viewhelper.setscaley(mcontent, evaluate(percent, 1.0f, 0.9f));

 getbackground().setcolorfilter((integer)(colorevaluate(percent, color.black, color.transparent)), porterduff.mode.src_over);// 亮度变化
}

/** 估值器,根据开始数字和结束数字,随着百分比的变化得到一个数值,详情见floatevaluator */
 private float evaluate(float fraction, number startvalue, number endvalue) {
 float startfloat = startvalue.floatvalue();
 return startfloat + fraction * (endvalue.floatvalue() - startfloat);
 }

 /** 颜色取值,根据初始颜色和结束颜色,随着百分的变化取出不同的颜色,详情见argbevaluator */
 private object colorevaluate(float fraction, object startvalue, object 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))));
 }

⑥我们提供一个打开/关闭菜单方法,供使用者调用。

 /** 菜单切换 */
 public void toggle() {
 if(isopen) {
  close();
 } else {
  open();
 }
 }

 /**
 * 打开菜单
 */
 private void open() {
 if (mviewdraghelper.smoothslideviewto(mcontent, mrange, 0)) {// 判断主页面是否滑动到指定位置
  viewcompat.postinvalidateonanimation(this);// 会触发computescroll
 }
 isopen = true;
 }

 /**
 * 关闭菜单
 */
 private void close() {
 if (mviewdraghelper.smoothslideviewto(mcontent, 0, 0)) {// 判断主页面是否滑动到指定位置
  viewcompat.postinvalidateonanimation(this);// 会触发computescroll
 }
 isopen = false;
 }

 @override
 public void computescroll() {
 super.computescroll();
 if (mviewdraghelper.continuesettling(true)) {// 持续执行动画,如果返回则表示动画还没有执行完
  viewcompat.postinvalidateonanimation(this);
 }
 }

==================至此我们的slidingmenu就定义完毕=====================

我们在mainactivity中使用

public class mainactivity extends activity {

 private slidingmenu mslidingmenu;

 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 requestwindowfeature(window.feature_no_title);
 setcontentview(r.layout.activity_main);
 initview();
 }

 private void initview() {
 mslidingmenu = (slidingmenu) findviewbyid(r.id.main_slidingmenu);
 }

 public void click(view view) {
 mslidingmenu.toggle();
 }
}


更多学习内容,可以点击《android侧滑效果汇总》学习。

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