一、淘宝商品详情页效果

先看一下淘宝详情页的效果

我们的效果

二、实现思路

使用两个scrollView,两个scrollView 竖直排列,通过自定义viewGroup来控制两个scrollView的竖直排列,以及滑动事件的处理。如下图

三、具体实现

1、继承viewGroup自定义布局View 重写onMeasure()和onLayout方法,在onLayout方法中完成对两个子ScrollView的竖直排列布局,代码如下:
布局文件:
[java]  view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context="com.baoyunlong.view.pulluptoloadmore.MainActivity">
  6. <com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent"
  9. android:orientation="vertical">
  10. <com.baoyunlong.view.pulluptoloadmore.MyScrollView
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent"
  13. android:fillViewport="true">
  14. <LinearLayout
  15. android:layout_width="match_parent"
  16. android:layout_height="match_parent"
  17. android:orientation="vertical">
  18. <ImageView
  19. android:scaleType="fitXY"
  20. android:src="@drawable/a1"
  21. android:layout_width="match_parent"
  22. android:layout_height="180dp" />
  23. <TextView
  24. android:text="这里是标题"
  25. android:textSize="18dp"
  26. android:layout_marginRight="10dp"
  27. android:layout_marginLeft="10dp"
  28. android:layout_marginTop="10dp"
  29. android:layout_width="match_parent"
  30. android:layout_height="wrap_content" />
  31. <TextView
  32. android:layout_marginTop="10dp"
  33. android:text="子标题"
  34. android:layout_marginLeft="10dp"
  35. android:layout_marginRight="10dp"
  36. android:textSize="18dp"
  37. android:layout_width="match_parent"
  38. android:layout_height="wrap_content" />
  39. ..............
  40. <LinearLayout
  41. android:layout_height="0dp"
  42. android:layout_weight="1"
  43. android:gravity="bottom"
  44. android:layout_width="match_parent">
  45. <TextView
  46. android:layout_width="match_parent"
  47. android:layout_height="wrap_content"
  48. android:height="50dp"
  49. android:background="#b11"
  50. android:gravity="center"
  51. android:text="继续拖动查看图文详情"
  52. android:textColor="#000" />
  53. </LinearLayout>
  54. </LinearLayout>
  55. </com.baoyunlong.view.pulluptoloadmore.MyScrollView>
  56. <com.baoyunlong.view.pulluptoloadmore.MyScrollView
  57. android:layout_width="match_parent"
  58. android:layout_height="match_parent"
  59. android:fillViewport="true">
  60. <LinearLayout
  61. android:layout_width="match_parent"
  62. android:layout_height="match_parent"
  63. android:gravity="center"
  64. android:orientation="vertical">
  65. <ImageView
  66. android:layout_width="wrap_content"
  67. android:layout_height="wrap_content"
  68. android:src="@drawable/a1" />
  69. <ImageView
  70. android:layout_width="wrap_content"
  71. android:layout_height="wrap_content"
  72. android:src="@drawable/a3" />
  73. .........
  74. </LinearLayout>
  75. </com.baoyunlong.view.pulluptoloadmore.MyScrollView>
  76. </com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore>
  77. </RelativeLayout>

代码:

[java]  view plain copy
  1. public class PullUpToLoadMore extends ViewGroup {
  2. public PullUpToLoadMore(Context context) {
  3. super(context);
  4. }
  5. public PullUpToLoadMore(Context context, AttributeSet attrs) {
  6. super(context, attrs);
  7. }
  8. public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {
  9. super(context, attrs, defStyleAttr);
  10. }
  11. @Override
  12. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  13. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  14. measureChildren(widthMeasureSpec, heightMeasureSpec);
  15. }
  16. @Override
  17. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  18. int childCount = getChildCount();
  19. int childTop = t;
  20. for (int i = 0; i < childCount; i++) {
  21. View child = getChildAt(i);
  22. child.layout(l, childTop, r, childTop + child.getMeasuredHeight());
  23. childTop += child.getMeasuredHeight();
  24. }
  25. }
  26. }
2、处理滑动事件 
规则如下 :
(1)、当处于第一屏时 第一个ScrollView已经滑动到底部并且滑动方向是往上滑动,这个时候滑动事件应该交给父view处理也就是拦截事件让onInterceptTouchEvent返回true.然后父view通过scrollBy()方法滚动,显示出第二个scrollView。
      (2)、当处于第二屏时 第二个ScrollView已经滑动到顶部并且滑动方向是往下滑动,这个时候滑动事件交给父view处理,根据滑动事件显示出第一个ScrollView。
      (3)、当手指离开屏幕时,根据滑动速度来决定是回弹到第一个ScrollView还是第二个ScrollView,通过VelocityTracker来获取滑动速度。
3、一些细节的处理
(1)、如果仔细看观察淘宝的实现效果你会发现,当你滑动到刚刚看到 “继续拖动,查看图文详情”的时候,手指抬起,然后再按下重新向上拖动你会发现,第二页并不会划出来,而是停留在了“继续拖动,查看图文详情”的底部,京东的效果也是一样。这样用户体验不太好,我们来优化一下。其实通过查看ScrollView的源码可以看出来,这是因为ScrollView类的onTouchEvent方法的默认实现,调用了parent.requestDisallowInterceptTouchEvent(true)方法 阻止了我们拦截事件,导致我们父view的onInterceptTouchEvent方法无法执行,也就拦截不到事件,拦截不到事件我们的onTouchEvent就无法执行,onTouchEvent无法执行,我们写在onTouchEvent里面的滚动逻辑就执行不到了,导致了上面我们看到的划不动的效果。解决方法就是,我们需要重写dispatchTouchEvent()方法,防止子view干扰我们,这样我们滑动的时候就可以一气呵成了。代码如下:
[java]  view plain copy
  1. @Override
  2. public boolean dispatchTouchEvent(MotionEvent ev) {
  3. //防止子View禁止父view拦截事件
  4. this.requestDisallowInterceptTouchEvent(false);
  5. return super.dispatchTouchEvent(ev);
  6. }
      (2)、监听ScrollView滑动事件的问题
ScrollView没有提供滚动事件的监听方法,也就没法判断是否滚动到了顶部,或者底部,这里我们继承ScrollView 自己实现滚动事件监听。
[java]  view plain copy
  1. /**
  2. * Created by baoyunlong on 16/6/8.
  3. */
  4. public class MyScrollView extends ScrollView {
  5. private static String TAG=MyScrollView.class.getName();
  6. public void setScrollListener(ScrollListener scrollListener) {
  7. this.mScrollListener = scrollListener;
  8. }
  9. private ScrollListener mScrollListener;
  10. public MyScrollView(Context context) {
  11. super(context);
  12. }
  13. public MyScrollView(Context context, AttributeSet attrs) {
  14. super(context, attrs);
  15. }
  16. public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
  17. super(context, attrs, defStyleAttr);
  18. }
  19. @Override
  20. public boolean onTouchEvent(MotionEvent ev) {
  21. switch (ev.getAction()){
  22. case MotionEvent.ACTION_MOVE:
  23. if(mScrollListener!=null){
  24. int contentHeight=getChildAt(0).getHeight();
  25. int scrollHeight=getHeight();
  26. int scrollY=getScrollY();
  27. mScrollListener.onScroll(scrollY);
  28. if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){
  29. mScrollListener.onScrollToBottom();
  30. }else {
  31. mScrollListener.notBottom();
  32. }
  33. if(scrollY==0){
  34. mScrollListener.onScrollToTop();
  35. }
  36. }
  37. break;
  38. }
  39. boolean result=super.onTouchEvent(ev);
  40. requestDisallowInterceptTouchEvent(false);
  41. return result;
  42. }
  43. public interface ScrollListener{
  44. void onScrollToBottom();
  45. void onScrollToTop();
  46. void onScroll(int scrollY);
  47. void notBottom();
  48. }
4、完整代码如下
[java]  view plain copy
  1. /**
  2. * Created by baoyunlong on 16/6/8.
  3. */
  4. public class PullUpToLoadMore extends ViewGroup {
  5. public static String TAG = PullUpToLoadMore.class.getName();
  6. MyScrollView topScrollView, bottomScrollView;
  7. VelocityTracker velocityTracker = VelocityTracker.obtain();
  8. Scroller scroller = new Scroller(getContext());
  9. int currPosition = 0;
  10. int position1Y;
  11. int lastY;
  12. public int scaledTouchSlop;//最小滑动距离
  13. int speed = 200;
  14. boolean isIntercept;
  15. public boolean bottomScrollVIewIsInTop = false;
  16. public boolean topScrollViewIsBottom = false;
  17. public PullUpToLoadMore(Context context) {
  18. super(context);
  19. init();
  20. }
  21. public PullUpToLoadMore(Context context, AttributeSet attrs) {
  22. super(context, attrs);
  23. init();
  24. }
  25. public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {
  26. super(context, attrs, defStyleAttr);
  27. init();
  28. }
  29. private void init() {
  30. post(new Runnable() {
  31. @Override
  32. public void run() {
  33. topScrollView = (MyScrollView) getChildAt(0);
  34. bottomScrollView = (MyScrollView) getChildAt(1);
  35. topScrollView.setScrollListener(new MyScrollView.ScrollListener() {
  36. @Override
  37. public void onScrollToBottom() {
  38. topScrollViewIsBottom = true;
  39. }
  40. @Override
  41. public void onScrollToTop() {
  42. }
  43. @Override
  44. public void onScroll(int scrollY) {
  45. }
  46. @Override
  47. public void notBottom() {
  48. topScrollViewIsBottom = false;
  49. }
  50. });
  51. bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {
  52. @Override
  53. public void onScrollToBottom() {
  54. }
  55. @Override
  56. public void onScrollToTop() {
  57. }
  58. @Override
  59. public void onScroll(int scrollY) {
  60. if (scrollY == 0) {
  61. bottomScrollVIewIsInTop = true;
  62. } else {
  63. bottomScrollVIewIsInTop = false;
  64. }
  65. }
  66. @Override
  67. public void notBottom() {
  68. }
  69. });
  70. position1Y = topScrollView.getBottom();
  71. scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  72. }
  73. });
  74. }
  75. @Override
  76. public boolean dispatchTouchEvent(MotionEvent ev) {
  77. //防止子View禁止父view拦截事件
  78. this.requestDisallowInterceptTouchEvent(false);
  79. return super.dispatchTouchEvent(ev);
  80. }
  81. @Override
  82. public boolean onInterceptTouchEvent(MotionEvent ev) {
  83. int y = (int) ev.getY();
  84. switch (ev.getAction()) {
  85. case MotionEvent.ACTION_DOWN:
  86. lastY = y;
  87. break;
  88. case MotionEvent.ACTION_MOVE:
  89. //判断是否已经滚动到了底部
  90. if (topScrollViewIsBottom) {
  91. int dy = lastY - y;
  92. //判断是否是向上滑动和是否在第一屏
  93. if (dy > 0 && currPosition == 0) {
  94. if (dy >= scaledTouchSlop) {
  95. isIntercept = true;//拦截事件
  96. lastY=y;
  97. }
  98. }
  99. }
  100. if (bottomScrollVIewIsInTop) {
  101. int dy = lastY - y;
  102. //判断是否是向下滑动和是否在第二屏
  103. if (dy < 0 && currPosition == 1) {
  104. if (Math.abs(dy) >= scaledTouchSlop) {
  105. isIntercept = true;
  106. }
  107. }
  108. }
  109. break;
  110. }
  111. return isIntercept;
  112. }
  113. @Override
  114. public boolean onTouchEvent(MotionEvent event) {
  115. int y = (int) event.getY();
  116. velocityTracker.addMovement(event);
  117. switch (event.getAction()) {
  118. case MotionEvent.ACTION_MOVE:
  119. int dy = lastY - y;
  120. if (getScrollY() + dy < 0) {
  121. dy = getScrollY() + dy + Math.abs(getScrollY() + dy);
  122. }
  123. if (getScrollY() + dy + getHeight() > bottomScrollView.getBottom()) {
  124. dy = dy - (getScrollY() + dy - (bottomScrollView.getBottom() - getHeight()));
  125. }
  126. scrollBy(0, dy);
  127. break;
  128. case MotionEvent.ACTION_UP:
  129. isIntercept = false;
  130. velocityTracker.computeCurrentVelocity(1000);
  131. float yVelocity = velocityTracker.getYVelocity();
  132. if (currPosition == 0) {
  133. if (yVelocity < 0 && yVelocity < -speed) {
  134. smoothScroll(position1Y);
  135. currPosition = 1;
  136. } else {
  137. smoothScroll(0);
  138. }
  139. } else {
  140. if (yVelocity > 0 && yVelocity > speed) {
  141. smoothScroll(0);
  142. currPosition = 0;
  143. } else {
  144. smoothScroll(position1Y);
  145. }
  146. }
  147. break;
  148. }
  149. lastY = y;
  150. return true;
  151. }
  152. @Override
  153. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  154. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  155. measureChildren(widthMeasureSpec, heightMeasureSpec);
  156. }
  157. @Override
  158. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  159. int childCount = getChildCount();
  160. int childTop = t;
  161. for (int i = 0; i < childCount; i++) {
  162. View child = getChildAt(i);
  163. child.layout(l, childTop, r, childTop + child.getMeasuredHeight());
  164. childTop += child.getMeasuredHeight();
  165. }
  166. }
  167. //通过Scroller实现弹性滑动
  168. private void smoothScroll(int tartY) {
  169. int dy = tartY - getScrollY();
  170. scroller.startScroll(getScrollX(), getScrollY(), 0, dy);
  171. invalidate();
  172. }
  173. @Override
  174. public void computeScroll() {
  175. if (scroller.computeScrollOffset()) {
  176. scrollTo(scroller.getCurrX(), scroller.getCurrY());
  177. postInvalidate();
  178. }
  179. }
  180. }

android 仿淘宝、京东商品详情页 向上拖动查看图文详情控件相关推荐

  1. Android仿淘宝京东商品规格参数颜色筛选

    Android 选择商品属性sku 最近项目中使用SKU属性查询,类似淘宝京东商品的选择,在网上查询了弄了几个源码看看,发现还是实现不了多属性选择问题,再原基础上改动相当费事,所以想干脆自己处理这个问 ...

  2. Android 仿淘宝京东商品详情页阻力翻页效果

    原文链接:http://code.taobao.org/p/android-example/diff/46/trunk/%E5%95%86%E5%9F%8E%E8%AF%A6%E6%83%85/src ...

  3. Android 仿淘宝京东商品详情视频+图片与图片第一帧获取

    近日项目有个新需求就是把原本的商品详情只有图片展示,改为视频+图片方式展示. 此博客只提供记录,与思路具体根据自己需求实现.首先想到的是Google搜索下别人的实现方式来参考实现发现不怎么适合项目需求 ...

  4. 仿淘宝京东商品规格属性选择的最简单实现

    仿淘宝京东商品规格属性选择的最简单实现 商城里面的规格选择,网上大部分是自定义控件实现的,显得很是麻烦,而我的实现方式是大家最常用的控件RecyclerView,特点是性能好,简单.废话不多说,先看实 ...

  5. android向上拖动查看图文详情控件

    摘自:http://blog.csdn.net/qifengdeqingchen/article/details/51659735 一.淘宝商品详情页效果 先看一下淘宝详情页的效果 我们的效果 二.实 ...

  6. Android 仿淘宝京东等我的订单界面及任意列表拓展

    概述 目前像淘宝及展示列表等都有多个item展示的需求,可能大多数如果没做过,第一眼就是ListView去嵌套ListView,虽然这样是可以完成,但是这样做会导致手机过度绘制,为什么呢?因为当一个I ...

  7. vue仿淘宝京东商品多条件筛选(vue实现)

    <template><div id="warp">你选择的是:<mark v-for="(item,index) in arr"& ...

  8. Android 仿淘宝商品详情页下拉足迹Demo

    DropDownMultiPager 仿淘宝等商品详情页下拉足迹效果SimpleDemo 可colne之后看MainActivity的调用,方便二次开发 依赖 compile 'com.nineold ...

  9. Android仿淘宝、京东Banner滑动查看图文详情

    文章目录 写在前面 效果图 原理分析 核心代码 源码地址 写在前面 本文基于 ViewPager2 实现的 Banner 效果,进而实现了仿淘宝.京东Banner滑动至最后一页时继续滑动来查看图文详情 ...

最新文章

  1. 基于Nginx实现10万+并发,你应该做的Linux内核优化
  2. linux安装hadoop记录
  3. CG CTF WEB 起名字真难
  4. android sharedUserId 共享用户
  5. php 微信转账,php实现微信公众号企业转账功能
  6. mysql 提交乱码问题_mysql数据库乱码问题
  7. 【科普】联邦知识蒸馏概述与思考
  8. CCF 201403-5 任务调度
  9. java树广度优先_如何在功能上生成树广度优先 . (使用Haskell)
  10. 软件测试 PreDay 决策表
  11. python识别文字坐标_python识别图片上的文字并返回文字在图片中的坐标
  12. JAVA第一次授课心得_关于第一次java课的感想
  13. 分享一款光彩四射的CSS3按钮集合
  14. android点击按钮执行adb命令,Android 按键事件及adb命令模拟
  15. LogLog Counting
  16. 图像的transformation与registration
  17. 2022-2028全球与中国健康资讯交换(HIE)市场现状及未来发展趋势
  18. Python|用turtle画笔画爱心
  19. 弘辽科技:拼多多活动价格建议价格太低了怎么办?
  20. 电脑文件夹拒绝访问,如何解决?

热门文章

  1. 服务器虚拟化知识点的总结以及了解虚拟化
  2. 通用学术英语重点词汇表41-50词
  3. 洋河股份Q3增收不增利:销售费用上涨,净利润降超一成
  4. 工程师姓什么很重要!别再叫我 “X 工”!!!
  5. 如何查看linux服务器字符集,Linux字符集查看与设置
  6. PART16 TypeScript高级类型
  7. NOIP2017游记兼OI半程回忆录
  8. java支付宝网页授权_手机浏览器怎么调用支付宝进行用户授权呢?
  9. MTK9612方案电视STR开机后屏黑有声的问题分析
  10. uni-app页面中使用本地背景图片