声明:请勿转载 否则子孙世世代代在第三世界做软件开发

该篇文章摘自google Android 框架设计者Adam Powell的博客

原文链接:Each Navigation Drawer hides a ViewDragHelper - Flavien Laurent

代码下载:https://github.com/flavienlaurent/flavienlaurent.com/tree/master/viewdraghelper 

效果:

 
 
在google 2013的I/O开发者大会上介绍了新的layout:SlidingPaneLayout和 DrawerLayout
SlidingPaneLayout是这样一个view:可以把view从底部拖动到顶部,反之亦然。现在在google大多数的应用程序中都用到了这两个layout ,ViewDragHelper更方便和容易管理view拖动。(以下简称VDH)。
 
在接下来的文章中,我将介绍关于ViewDragHelper的东西,有时候写一个自定义的layout并且可以拖动它的子view不是一件容易的事情。首先我在附件中贴出这些view效果展示,然后将以代码的方式介绍这些layout是怎么工作的。
 
API DESIGN 关于ViewDragHelper的技术要点:
 
1: ViewDragHelper.Callback 通常用来作为VHD和父试图之间的通讯通道
2:有一个静态工厂方法可以用来创建VDH的实例。
3:你也可以配置你view的拖动方向
4:拖动依然可以从边缘检测到,即使没有view被捕获到(嘛意思?)
 
记得去阅读官方文档: ViewDragHelperViewDragHelper.Callback
 
阅读源码:VDH和它的callback方法在support-v4 library库中也是受支持的。可以阅读他们的源码: ViewDragHelper and ViewDragHelper.Callback.
 
它内部还用到了一些公共的fragmework的接口方法: VelocityTracker用来跟踪滑动事件,Scroller用来滑动一个View当有需要的时候。建议尽量多多的去阅读官方文档,因为首先官方文档介绍的动写都很有意思,其次你也可以通过官方文档上了解到它们的工作原理,这样用起来去也更顺手。

使用VDH

在本节中,我将给你介绍一些在VDH中欧给你配置的例子,我们会从一些初始化的工作做起,并且介绍一些常用的配置。
 
VDH’s initialization
自定义的ViewGroup继承了 LinearLayout,并且她包括了一个简单的子View。
 1 public class DragLayout extends LinearLayout {
 2 
 3 private final ViewDragHelper mDragHelper;
 4 private View mDragView;
 5 
 6 public DragLayout(Context context) {
 7   this(context, null);
 8 }
 9 
10 public DragLayout(Context context, AttributeSet attrs) {
11   this(context, attrs, 0);
12 }
13 
14 public DragLayout(Context context, AttributeSet attrs, int defStyle) {
15   super(context, attrs, defStyle);
16 }

 创建一个VDH和它的callback,记住:你可以给它指定一个滑动时候的灵敏度,官方文档上表示值越大,值越大,灵敏度也就越高,正常的大小是1.0f。

public DragLayout(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());
}

最重要的方式是调用VDH的onInterceptTouchonTouch.

public boolean onInterceptTouchEvent(MotionEvent ev) {
  final int action = MotionEventCompat.getActionMasked(ev);
  if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
      mDragHelper.cancel();
      return false;
  }
  return mDragHelper.shouldInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
  mDragHelper.processTouchEvent(ev);
  return true;
}

现在你可以通过配置Callback方法去改变VDH的行为了。

只能横向滑动:之可以去实现clampViewPositionHorizontal允许横向的滑动,记住:官方文档上说,默认的情况下你如果没有显示的去配置是只能允许横向滑动的。你必须指定margins参数和 parent padding参数。下面的这种情况是不允许的

public int clampViewPositionHorizontal(View child, int left, int dx) {
  Log.d("DragLayout", "clampViewPositionHorizontal " + left + "," + dx);

  final int leftBound = getPaddingLeft();
  final int rightBound = getWidth() - mDragView.getWidth();

  final int newLeft = Math.min(Math.max(left, leftBound), rightBound);

  return newLeft;
}

效果图:

横向滚动预览

纵向滑动:实现clampViewPositionVertical允许纵向滑动,记住官方文档上说默认情况下是不允许纵向滑动的。你必须指定margins参数和 parent padding参数。下面的这种情况是不允许的

@Override
public int clampViewPositionVertical(View child, int top, int dy) {
  final int topBound = getPaddingTop();
  final int bottomBound = getHeight() - mDragView.getHeight();

  final int newTop = Math.min(Math.max(top, topBound), bottomBound);

  return newTop;
}

效果图:

纵向滑动效果图

捕获或者是不捕获一个view

实现tryCaptureView去允许子view能不能被滑动,比如这里有两个子view,但是只能有一个子view被滑动。

@Override
public boolean tryCaptureView(View child, int pointerId) {
  return child == mDragView1;
}

效果图:

只有一个子view可以被捕获到

 滑动范围:

实现getViewHorizontalDragRange or getViewVerticalDragRange来返回横向或者是纵向滑动的范围,这里是以像素为单位的。这个范围会被VDH用到,当你调用smoothSlideViewTo或者是settleCapturedViewAt去计算滚动的距离,并且,它也可以用来检查横向和纵向触摸滚动.

边缘拖动:这个功能通常用在DrawerLayout with EDGE_LEFT and EDGE_RIGHT.

你可以去配置VDH允许其进行边缘滚动的检查

mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

实现onEdgeTouched,这时当前被滚动的子view就会被捕捉到。

@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
    super.onEdgeTouched(edgeFlags, pointerId);
    Toast.makeText(getContext(), "edgeTouched", Toast.LENGTH_SHORT).show();
}

实现onEdgeDragStarted,当一个真正的拖动开始的时候,并且这是一个子view是不会被捕获到的,除非你给他制定一个子视图。

@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
    mDragHelper.captureChildView(mDragView2, pointerId);
}

效果图:

 

实战操作:

最近在我的手机上,我收到了youtube的更新,在更新之前,比较让人讨厌的是我不能同时看视频和搜索下一个视频,VDH很好的解决了这个问题。下面是效果图并且效果图之后贴上主要的代码。

 

转载于:https://www.cnblogs.com/nicecock/p/3523538.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐