【致谢】:qifengdeqingchen
【博客地址】:http://blog.csdn.net/qifengdeqingchen/article/details/51659735

1、需求:

要实现一个类似淘宝、京东的商品详情页面。首先是在看一些前辈的思路,查看之后,发现博主qifengdeqingchen的文章不错,然后去下载下来查看demo。

2、查阅资料

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

3、发现问题:

我在scrollView2中添加一个TabLayout+ViewPager,然后在添加两个Fragment,在fragment中写一个scrollview.这时候发现在Fragment中只可以向下滑动,当想要去向上滑动的时候,就滑动到了scrollView1中。

4、解决问题:

首先来看一下前辈的代码,如下:

public class PullUpToLoadMore extends ViewGroup {  public static String TAG = PullUpToLoadMore.class.getName();  MyScrollView topScrollView, bottomScrollView;  VelocityTracker velocityTracker = VelocityTracker.obtain();  Scroller scroller = new Scroller(getContext());  int currPosition = 0;  int position1Y;  int lastY;  public int scaledTouchSlop;//最小滑动距离  int speed = 200;  boolean isIntercept;  public boolean bottomScrollVIewIsInTop = false;  public boolean topScrollViewIsBottom = false;  public PullUpToLoadMore(Context context) {  super(context);  init();  }  public PullUpToLoadMore(Context context, AttributeSet attrs) {  super(context, attrs);  init();  }  public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init();  }  private void init() {  post(new Runnable() {  @Override  public void run() {  topScrollView = (MyScrollView) getChildAt(0);  bottomScrollView = (MyScrollView) getChildAt(1);  topScrollView.setScrollListener(new MyScrollView.ScrollListener() {  @Override  public void onScrollToBottom() {  topScrollViewIsBottom = true;  }  @Override  public void onScrollToTop() {  }  @Override  public void onScroll(int scrollY) {  }  @Override  public void notBottom() {  topScrollViewIsBottom = false;  }  });  bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {  @Override  public void onScrollToBottom() {  }  @Override  public void onScrollToTop() {  }  @Override  public void onScroll(int scrollY) {  if (scrollY == 0) {  bottomScrollVIewIsInTop = true;  } else {  bottomScrollVIewIsInTop = false;  }  }  @Override  public void notBottom() {  }  });  position1Y = topScrollView.getBottom();  scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();  }  });  }  @Override  public boolean dispatchTouchEvent(MotionEvent ev) {  //防止子View禁止父view拦截事件  this.requestDisallowInterceptTouchEvent(false);  return super.dispatchTouchEvent(ev);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {  int y = (int) ev.getY();  switch (ev.getAction()) {  case MotionEvent.ACTION_DOWN:  lastY = y;  break;  case MotionEvent.ACTION_MOVE:  //判断是否已经滚动到了底部  if (topScrollViewIsBottom) {  int dy = lastY - y;  //判断是否是向上滑动和是否在第一屏  if (dy > 0 && currPosition == 0) {  if (dy >= scaledTouchSlop) {  isIntercept = true;//拦截事件  lastY=y;  }  }  }  if (bottomScrollVIewIsInTop) {  int dy = lastY - y;  //判断是否是向下滑动和是否在第二屏  if (dy < 0 && currPosition == 1) {  if (Math.abs(dy) >= scaledTouchSlop) {  isIntercept = true;  }  }  }  break;  }  return isIntercept;  }  @Override  public boolean onTouchEvent(MotionEvent event) {  int y = (int) event.getY();  velocityTracker.addMovement(event);  switch (event.getAction()) {  case MotionEvent.ACTION_MOVE:  int dy = lastY - y;  if (getScrollY() + dy < 0) {  dy = getScrollY() + dy + Math.abs(getScrollY() + dy);  }  if (getScrollY() + dy + getHeight() > bottomScrollView.getBottom()) {  dy = dy - (getScrollY() + dy - (bottomScrollView.getBottom() - getHeight()));  }  scrollBy(0, dy);  break;  case MotionEvent.ACTION_UP:  isIntercept = false;  velocityTracker.computeCurrentVelocity(1000);  float yVelocity = velocityTracker.getYVelocity();  if (currPosition == 0) {  if (yVelocity < 0 && yVelocity < -speed) {  smoothScroll(position1Y);  currPosition = 1;  } else {  smoothScroll(0);  }  } else {  if (yVelocity > 0 && yVelocity > speed) {  smoothScroll(0);  currPosition = 0;  } else {  smoothScroll(position1Y);  }  }  break;  }  lastY = y;  return true;  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  super.onMeasure(widthMeasureSpec, heightMeasureSpec);  measureChildren(widthMeasureSpec, heightMeasureSpec);  }  @Override  protected void onLayout(boolean changed, int l, int t, int r, int b) {  int childCount = getChildCount();  int childTop = t;  for (int i = 0; i < childCount; i++) {  View child = getChildAt(i);  child.layout(l, childTop, r, childTop + child.getMeasuredHeight());  childTop += child.getMeasuredHeight();  }  }  //通过Scroller实现弹性滑动  private void smoothScroll(int tartY) {  int dy = tartY - getScrollY();  scroller.startScroll(getScrollX(), getScrollY(), 0, dy);  invalidate();  }  @Override  public void computeScroll() {  if (scroller.computeScrollOffset()) {  scrollTo(scroller.getCurrX(), scroller.getCurrY());  postInvalidate();  }  }
}  

通过分析我们可以大概了解到,出现在个问题应该是在滑动事件的解决上。在自定义控件中的onInterceptTouchEvent方法中,可能拦截了滑动事件,才导致了问题的出现。于是我在onInterceptTouchEvent方法中做出了改动。当向下滑动时,判断是否在ScrollView2中,分别处理滑动事件。

当页面没有在ScrollView2中,就要让自定义viewGroup中的Scrollview页面切换(这时候父控件拦截OnTouchEvent,不向子控件传递,让父控件滑动)。当页面在ScrollView2中,还要去判断viewpager里边的scrollview是否滑动到了顶部,如果在顶部,要去切换viewgroup中的页面(这时候父控件拦截OnTouchEvent,不向子控件传递,让父控件滑动),如果没有滑动到顶部,就要让viewpager中的scrollview滑动(这时候父控件不拦截OnTouchEvent,向子控件传递,让子控件滑动)。

5、详细代码如下:

    @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {int y = (int) ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:lastY = y;break;case MotionEvent.ACTION_MOVE://判断是否已经滚动到了底部if (topScrollViewIsBottom) {int dy = lastY - y;//判断是否是向上滑动和是否在第一屏if (dy > 0 && currPosition == 0) {if (dy >= scaledTouchSlop) {isIntercept = true;//拦截事件lastY=y;}}}if (bottomScrollVIewIsInTop) {int dy = lastY - y;//判断是否是向下滑动和是否在第二屏if (dy < 0 && currPosition == 1) {if (Math.abs(dy) >= scaledTouchSlop) {if(PublicStaticClass.IsTop){//如果viewpager里边的scrollview在最顶部,,就让外边的scrollview获取焦点,否则,让最里边的scrollview获取焦点isIntercept = true;}}}}else{int dy = lastY - y;//判断是否是向上滑动和是否在第二屏   如果是在刚到第二屏的时候,向上滑动,也让父控件获取焦点
//                    在onInterceptTouchEvent()方法中,如果返回true,父控件拦截事件,如果返回false,则向下传递if (dy < 0 && currPosition == 1) {if (Math.abs(dy) >= scaledTouchSlop) {if(PublicStaticClass.IsTop){//PublicStaticClass.IsTop  判断fragment中的scrollview时候滑动到了顶部。//如果viewpager里边的scrollview在最顶部,,就让外边的scrollview获取焦点,否则,让最里边的scrollview获取焦点isIntercept = true;}}}}break;}return isIntercept;}

来看一下ViewPager中的实现:

自定义控件:MyScrollView.java:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;/*** Created by baoyunlong on 16/6/8.*/
public class MyScrollView extends ScrollView {private static String TAG=MyScrollView.class.getName();public void setScrollListener(ScrollListener scrollListener) {this.mScrollListener = scrollListener;}private ScrollListener mScrollListener;public MyScrollView(Context context) {super(context);}public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);}public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()){case MotionEvent.ACTION_MOVE:if(mScrollListener!=null){int contentHeight=getChildAt(0).getHeight();int scrollHeight=getHeight();int scrollY=getScrollY();mScrollListener.onScroll(scrollY);if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){mScrollListener.onScrollToBottom();}else {mScrollListener.notBottom();}if(scrollY==0){mScrollListener.onScrollToTop();}}break;}boolean result=super.onTouchEvent(ev);requestDisallowInterceptTouchEvent(false);return result;}public interface ScrollListener{void onScrollToBottom();void onScrollToTop();void onScroll(int scrollY);void notBottom();}
}

xml:

<com.qfdqc.views.pulltoloadmoreview.utils.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/oneScrollview"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="@dimen/px_300"android:text="我是第一个页面,向上滑动一下试试1"/><TextViewandroid:layout_width="match_parent"android:layout_height="@dimen/px_300"android:text="我是第一个页面,向上滑动一下试试2"/><TextViewandroid:layout_width="match_parent"android:layout_height="@dimen/px_300"android:text="我是第一个页面,向上滑动一下试试3"/><TextViewandroid:layout_width="match_parent"android:layout_height="@dimen/px_300"android:text="我是第一个页面,向上滑动一下试试4"/><TextViewandroid:layout_width="match_parent"android:layout_height="@dimen/px_300"android:text="我是第一个页面,向上滑动一下试试5"/></LinearLayout>
</com.qfdqc.views.pulltoloadmoreview.utils.MyScrollView>

Fragment.java:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import com.qfdqc.views.pulltoloadmoreview.R;
import com.qfdqc.views.pulltoloadmoreview.utils.MyScrollView;
import com.qfdqc.views.pulltoloadmoreview.utils.PublicStaticClass;public class OneFragment extends Fragment {View mView;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {mView = inflater.inflate(R.layout.fragment_one, container, false);initView();return mView;}private void initView() {MyScrollView oneScrollView= (MyScrollView) mView.findViewById(R.id.oneScrollview);oneScrollView.setScrollListener(new MyScrollView.ScrollListener() {@Overridepublic void onScrollToBottom() {}@Overridepublic void onScrollToTop() {}@Overridepublic void onScroll(int scrollY) {//判断时候滑动到了顶部if (scrollY == 0) {PublicStaticClass.IsTop = true;} else {PublicStaticClass.IsTop = false;}}@Overridepublic void notBottom() {}});}
}

6、最后来上效果图:

7、又发现问题:

在第二页上,左右滑动时,在水平方向上如果出现一点变化,就会滑动到第一页上。这里在onInterceptTouchEvent()方法中做了修改,判断滑动的距离。如果左右滑动距离大于上下滑动距离,我们就认为用户在左右滑动,这时候我们要让子控件获取到事件,去切换fragment。相反,如果上下滑动距离大于左右滑动距离,我们就认为用户在上下滑动,这时候让父控件拦截事件。具体代码如下:

    @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {int y = (int) ev.getY();int x = (int) ev.getX();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:lastY = y;lastX = x;break;case MotionEvent.ACTION_MOVE://判断是否已经滚动到了底部if (topScrollViewIsBottom) {int dy = lastY - y;//判断是否是向上滑动和是否在第一屏if (dy > 0 && currPosition == 0) {if (dy >= scaledTouchSlop) {isIntercept = true;//拦截事件lastY=y;lastX=x;}}}if (bottomScrollVIewIsInTop) {int dy = lastY - y;//判断是否是向下滑动和是否在第二屏if (dy < 0 && currPosition == 1) {if (Math.abs(dy) >= scaledTouchSlop) {if(PublicStaticClass.IsTop){//如果viewpager里边的scrollview在最顶部,,就让外边的scrollview获取焦点,否则,让最里边的scrollview获取焦点isIntercept = true;}}}}else{int dy = lastY - y;//上下滑动的距离int dx = lastX - x;//左右滑动的距离//判断是否是向上滑动和是否在第二屏   如果是在刚到第二屏的时候,向上滑动,也让父控件获取焦点
//                    在onInterceptTouchEvent()方法中,如果返回true,父控件拦截事件,如果返回false,则向下传递if (dy < 0 && currPosition == 1) {if (Math.abs(dy) >= scaledTouchSlop) {if(PublicStaticClass.IsTop){//如果viewpager里边的scrollview在最顶部,,就让外边的scrollview获取焦点,否则,让最里边的scrollview获取焦点//这里加一个判断,如果左右滑动的距离小于上下滑动的距离,我们认为用户在上下滑动//如果左右滑动的距离大于上下滑动的距离,我们认为用户在左右滑动//上下滑动时,让父控件拦截事件//左右滑动时,让子控件拦截事件if(Math.abs(dy)>Math.abs(dx)){//上下滑动isIntercept = true;}else{//左右滑动isIntercept = false;}}}}}break;}return isIntercept;}

8、github已经更新,项目地址:

https://github.com/LiQinglin007/PullToLoadMoreView-master

仿淘宝商品详情页面Android相关推荐

  1. ios仿淘宝商品详情页面粘贴商品规格弹出模板

  2. Android开发之仿淘宝商品详情页

    看到有人在问如何实现淘宝商品详情页效果,手痒了就撸了一个,献上效果图 大致梳理一下思路,这里不提供源码 状态栏透明使用开源库StatusBarCompat,为了兼容手机4.4 dependencies ...

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

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

  4. 仿淘宝商品详情-点击显示大图,可滑动

    现在在做一个商城类的项目: 大家都用过淘宝,需求就是要求仿淘宝的效果做一个, 直接上图 用到了一个项目PhotoView 大家运行一下看最后一个项目,把单一的图片显示改成VIewpager就好.

  5. android app实现轮播的图片视频播放video,仿淘宝商品详情的视频播放(android)

    这段时间在学习开发android app 记录一下实现仿淘宝图片视频切换的功能,直接拿来用即可,大家有什么问题可以共同交流 先看一下目录结构吧 思路: ViewPager 分别实现三个类型的滑动–fr ...

  6. 移动端实现swiper轮播的图片视频播放video,仿淘宝商品详情的视频播放(兼容ios和android)

    前段时间项目里需要,实现仿淘宝图片视频切换的功能,在网上找了很久,根据网上所收集的信息,最后整合实现项目需求,这里兼容了ios和android,直接拿来用即可,这里是用来记录学习使用的,大家有什么问题 ...

  7. Android之仿淘宝商品详情浏览效果

    一:先来几张效果图,没有弄gif动画,也就是商品详情滑动到底部继续上滑查看图文详情. 二:实现步骤: 1.自定义一个父容器ScrollViewContainer装载两个ScrollView. pack ...

  8. 仿淘宝商品详情页图片滑动并且数字也跟着变化

    今天遇到需求需要做个淘宝那样的商品详情页如图(这里只差放图片了)支持移动端,当然用的是swiper.js支持左右滑动 上代码 html代码 <div class="swiper-con ...

  9. 仿淘宝商品详情页TabLayout+ListView

    第一次写博客,我是一名Android的小码农写代码也有三四年了.有点好玩的跟大家分享一下 项目对商品详情页改版有新需求.顶部是一个渐变的Title包括"宝贝","详情&q ...

最新文章

  1. SQL Date 函数
  2. 史上最全的ubuntu16.04安装nvidia驱动+cuda9.0+cuDnn7.0
  3. 数字、字符串、列表类型及常用内置方法
  4. Follow My Logic 1048 PKU
  5. npkill(安全快速的清理电脑上的 node_modules)
  6. python解析原理_Python 中 -m 的典型用法、原理解析与发展演变
  7. Win10提示没有权限使用网络资源问题解决
  8. 树莓派串口通信编码_树莓派和STM32通过USB和串口通信记录
  9. 智能优化算法——遗传算法(C语言实现)
  10. Arquillian测试框架快速上手教程(四)- 使用Arquillian + Drone + Selenium + Graphene 进行Web自动化测试
  11. C语言函数定义和函数调用
  12. PhpStorm 2016.2 Mac破解版
  13. 人工智能对图书馆未来的影响,主要包含哪三个方面?
  14. 电感和磁珠有哪些区别
  15. python 定时运行 定时关闭_Python脚本用于定时关闭网易云音乐PC客户端
  16. 哈尔滨工业大学深圳计算机学院院长,哈工大计算机学院院长徐晓飞来访我院
  17. 艺赛旗RPA8.0-用户体验提升抢先看(一)
  18. 机器视觉中的像素、分辨率、灰度值等概念
  19. Vue项目使用splitpanes插件(垂直水平分割窗口)
  20. 谷歌浏览器(Google Chrome) v83.0.4103.97 正式版介绍及下载

热门文章

  1. Excel快速打印底端标题,教你一招,肯定行!
  2. 诸暨机器人餐厅价格_一起吃垮诸暨这家牛排自助餐厅!50+款自助,人均低至45元!...
  3. 【文献研究】轴辐式航线网络设计—Liner hub-and-spoke shipping network design
  4. 如何使用谷歌浏览器开发者工具中的Performance分析网页性能
  5. 阿里云蔡英华:云智一体,让产业全面迈向智能
  6. 常见的中间件及其特点
  7. 全自动过滤器:应用生物膜法利用全自动过滤器降解有机物
  8. 贪心算法实现活动安排问题
  9. 基于OpenCV实现对图片及视频中感兴趣区域颜色识别
  10. Romberg求积分算法