在豌豆荚的应用详情页中有个ViewPager布局,该布局头部添加了一个可上下收展的view用于显示应用资料。实现思路基本上就是利用ViewDragHelper进行拖动来控制头部的view的布局。当TopView可见时,手势事件被拖动层截获控制上下拖动达到TopView的折叠和展开效果。当TopView不可见时,手势事件交由ViewPager进行控制达到ListView正常滚动,并在ListView的onScroll滚动监听中判断ListView是否触顶。如果触顶则下拉拖动ViewPager显示TopView.
项目已经上传到Github的DragTopLayout.
先看下效果图:
实现过程
1.继承一个FrameLayout,在FrameLayout中控制子View拖动。FrameLayout初始化中实例化一个ViewDragHelper对象。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)">ViewDragHelper.create(<span class="hljs-keyword" style="outline:none!important; font-weight:bold">this</span>, <span class="hljs-number" style="color:#0880;outline:none!important;">1.0</span>f, callback);</code>
2.参数中callback即为拖动过程中所有的事件回调,实现一个ViewDragHelper.Callback()。
Callback中的所用到得方法如下:
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"><span class="hljs-comment" style="color:#888888;outline:none!important;">// 判断child是否是拖动的目标</span> tryCaptureView(View child, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> pointerId) <span class="hljs-comment" style="color:#888888;outline:none!important;">// 拖动位置的处理,可以处理拖动过程中的最高位置或者最低位置</span> clampViewPositionVertical(View child, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> top, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dy) <span class="hljs-comment" style="color:#888888;outline:none!important;">// 拖动后view位置的改变</span> onViewPositionChanged(View view, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> left, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> top, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dx, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dy) <span class="hljs-comment" style="color:#888888;outline:none!important;">// 拖动手势释放后的处理</span> onViewReleased(View releasedChild, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">float</span> xvel, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">float</span> yvel) <span class="hljs-comment" style="color:#888888;outline:none!important;">// 拖动状态的改变</span> onViewDragStateChanged(<span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> state)</code>
3.覆盖onInterceptTouchEvent和onTouchEvent方法,将事件拦截处理。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"> <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">boolean</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">onInterceptTouchEvent</span>(MotionEvent ev) { <span class="hljs-keyword" style="outline:none!important; font-weight:bold">return</span> shouldIntercept && dragHelper.shouldInterceptTouchEvent(ev); } <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">boolean</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">onTouchEvent</span>(MotionEvent event) { dragHelper.processTouchEvent(event); <span class="hljs-keyword" style="outline:none!important; font-weight:bold">return</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">true</span>; }</code>
4.覆盖computeScroll方法,用以实现拖动后的滚动效果
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"> <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">void</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">computeScroll</span>() { <span class="hljs-keyword" style="outline:none!important; font-weight:bold">if</span> (dragHelper.continueSettling(<span class="hljs-keyword" style="outline:none!important; font-weight:bold">true</span>)) { ViewCompat.postInvalidateOnAnimation(<span class="hljs-keyword" style="outline:none!important; font-weight:bold">this</span>); } }</code>
5.简单地拖动差不多实现了,下面就需要在Callback中进行拖动事件的自定义逻辑处理了。
先利用tryCaptureView判断当前touch的view是否是目标拖动view,返回true则拖动处理,false不处理。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"><span class="hljs-keyword" style="outline:none!important; font-weight:bold">return</span> child == dragContentView;</code>
在clampViewPositionVertical方法中处理拖动的最高高度不超过上边界。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"> <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">clampViewPositionVertical</span>(View child, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> top, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dy) { <span class="hljs-keyword" style="outline:none!important; font-weight:bold">return</span> Math.min(topViewHeight, Math.max(top, getPaddingTop())); }</code>
在onViewPositionChanged方法中控制拖动后新位置的处理。因为拖动过程中还需对TopView进行相应地处理,所以在方法内记录拖动的top位置,并在onLayout回调方法中处理最新位置的现实。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"> <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">void</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">onViewPositionChanged</span>(View changedView, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> left, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> top, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dx, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> dy) { <span class="hljs-keyword" style="outline:none!important; font-weight:bold">super</span>.onViewPositionChanged(changedView, left, top, dx, dy); contentTop = top; requestLayout(); }</code>
当释放手势后判断手势方向利用settleCapturedViewAt方法进行处理最终滚动位置。其中yvel参数>0代表快速往下滑动,否则为快速往上滑动。
<code class="language-java hljs " style="font-family:'Source Code Pro',monospace;font-size:undefined; padding:0.5em; color:rgb(0,0,0); display:block; outline:none!important; background-color:rgb(240,240,240)"> <span class="hljs-annotation" style="color:#888888;outline:none!important;">@Override</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">public</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">void</span> <span class="hljs-title" style="color:#8800;outline:none!important; font-weight:bold">onViewReleased</span>(View releasedChild, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">float</span> xvel, <span class="hljs-keyword" style="outline:none!important; font-weight:bold">float</span> yvel) { <span class="hljs-keyword" style="outline:none!important; font-weight:bold">super</span>.onViewReleased(releasedChild, xvel, yvel); <span class="hljs-comment" style="color:#888888;outline:none!important;">// yvel > 0 Fling down || yvel < 0 Fling up</span> <span class="hljs-keyword" style="outline:none!important; font-weight:bold">int</span> top; <span class="hljs-keyword" style="outline:none!important; font-weight:bold">if</span> (yvel > <span class="hljs-number" style="color:#0880;outline:none!important;">0</span> || contentTop > topViewHeight) { top = topViewHeight + getPaddingTop(); } <span class="hljs-keyword" style="outline:none!important; font-weight:bold">else</span> { top = getPaddingTop(); } <span class="hljs-keyword" style="outline:none!important; font-weight:bold">if</span> (wizard.enableSliding) { dragHelper.settleCapturedViewAt(releasedChild.getLeft(), top); } postInvalidate(); }</code>
这样就处理好了拖动的所有事件了。具体代码可参考Github上的项目。
文章转载页http://blog.csdn.net/chenupt/article/details/43228671#comments
相关推荐
标题"listView加viewPager 下拉刷新,上拉加载"表明我们要讨论的是如何在这样一个组合视图中添加下拉刷新和上拉加载的功能。下面将详细讲解这两个功能的实现方法以及相关的技术点。 首先,ListView是Android中常用...
要实现在ViewPager中的下拉刷新,我们可以利用开源库如SwipeRefreshLayout。SwipeRefreshLayout是Google提供的一个支持下拉刷新的布局,它可以包裹一个子View,例如ListView或者RecyclerView,当用户下拉时,会显示...
这个资源专注于利用`ViewPager`和`Fragment`来构建这样的界面,这两种组件是Android SDK中的核心组件,用于实现动态和交互性强的用户界面。接下来,我们将深入探讨这两个组件以及如何结合使用它们来创建一个仿微信的...
在Android应用开发中,"ViewPager+侧滑+下拉刷新"是常见的组合功能,用于创建交互丰富的用户界面。ViewPager主要用于展示可滑动的页面集合,侧滑通常用于实现导航抽屉效果,而下拉刷新则提供了最新的数据更新机制。...
标题“ViewPager嵌套ListView实现上拉和下拉刷新”揭示了一个关键的技术点,即如何在这样的复合组件中集成下拉刷新和上拉加载更多的功能。这种设计允许用户滚动查看更多的内容,同时提供了流畅的用户体验。 首先,...
"仿微信底部 ViewPager+Fragment" 这个标题表明我们将探讨如何实现一个类似于微信应用底部导航栏的功能,该功能通常采用 ViewPager 和 Fragment 的组合。在Android开发中,ViewPager是一个用于展示多个页面并允许...
在仿微信界面的实现中,ViewPager将被用来展示不同的页面,比如聊天列表、朋友圈和个人资料等。每个页面都是一个单独的Fragment,用户可以通过水平滑动在这些页面之间切换。 **Fragment**: Fragment是Android应用...
在Android开发中,"下拉刷新"和"ViewPager的banner滚动"是两个常见的功能,广泛应用于各种应用程序,如新闻客户端、电商应用等。下拉刷新通常用于更新列表数据,而ViewPager则常用来实现图片轮播或者广告栏效果,...
本示例中的“Android 利用CoordinatorLayout实现高仿抖音个人中心 下拉越界回弹 图片放大”就是一个很好的案例,它展示了如何通过 CoordinatorLayout 结合其他组件来构建类似抖音个人中心的下拉回弹以及图片放大效果...
5. **手势检测**:通过集成` GestureDetector`或`SwipeRefreshLayout`,可以实现下拉刷新、上滑加载更多等手势操作。 6. **性能优化**:由于ViewPager可能会加载大量视图,因此需要考虑内存管理和性能优化,例如...
标题中的“仿ViewPager”指的是开发者基于Android平台创建的一个自定义视图组件,它模仿了原生ViewPager的功能,但可能在某些方面进行了定制或优化,以满足特定需求。事件分发应用则表明这个组件着重处理触摸事件的...
"android 仿微信viewpager样式"这个话题是关于如何在Android应用中实现类似微信中ViewPager的滑动切换效果。ViewPager是Android SDK中的一个强大组件,它允许用户通过水平滑动来浏览多个页面,通常用于展示卡片式...
然而,在实际开发中,当`ViewPager`与`ListView`结合使用时,可能会遇到一些问题,比如如何实现在`ListView`中添加上拉刷新和下拉加载更多功能,同时解决两者之间的交互冲突。本篇将详细介绍如何解决这些问题。 ...
网上找了很多仿页面切换的,很多都不好用,这两个项目亲自调可用android2.2,里面有两个项目,一个是 activity 用的,一个是 fragment 用的,下面的滑条没有使用图片,用代码实现,比较实用,可以方便移植到项目中
综上所述,实现“android 仿微信viewpager滑动样式”主要涉及到自定义PageTransformer、滑动监听、指示器的联动、滑动速度控制、动画效果、性能优化以及手势识别等多个方面。通过熟练掌握这些技术,开发者可以为自己...
本文将详细解析如何实现一个仿微信的ViewPager框架,并集成滑动条功能,帮助你深入理解其中的原理。 首先,ViewPager是Android SDK提供的一种用于展示多个视图并可滑动切换的组件,常用于实现页面间的平滑过渡,如...
要重写HorizontalScrollView来仿ViewPager,我们需要关注以下几个关键点: 1. **子视图管理**:ViewPager会根据当前显示的页面和相邻的页面来加载和销毁子视图,以优化性能。我们需要在重写的HorizontalScrollView...
【标题】"仿微信 viewpager 滑动"所涉及的知识点主要集中在Android开发领域,尤其是UI设计和页面滑动效果的实现。ViewPager是Android SDK中的一个组件,它允许用户在多个视图间进行平滑的左右滑动切换,常用于实现...
【仿ViewPager】是一种在Android开发中常见的视图切换组件,它的设计灵感来源于原生的ViewPager,但可能在功能或性能上进行了优化或者扩展。在Android应用程序中,ViewPager通常用于实现页面间的滑动切换,比如在...
高仿土巴兔选择装修风格的效果,这里通过自定义ViewPager来实现,为什么通过ViewPager来实现呢,一是ViewPager很容易实现切换动画效果,二是选择的那一项自动居中。项目地址:...