仿淘宝商品详情页面Android
2017-03-12 15:03
405 查看
【致谢】:qifengdeqingchen
【博客地址】:http://blog.csdn.net/qifengdeqingchen/article/details/51659735
通过分析我们可以大概了解到,出现在个问题应该是在滑动事件的解决上。在自定义控件中的onInterceptTouchEvent方法中,可能拦截了滑动事件,才导致了问题的出现。于是我在onInterceptTouchEvent方法中做出了改动。当向下滑动时,判断是否在ScrollView2中,分别处理滑动事件。
当页面没有在ScrollView2中,就要让自定义viewGroup中的Scrollview页面切换(这时候父控件拦截OnTouchEvent,不向子控件传递,让父控件滑动)。当页面在ScrollView2中,还要去判断viewpager里边的scrollview是否滑动到了顶部,如果在顶部,要去切换viewgroup中的页面(这时候父控件拦截OnTouchEvent,不向子控件传递,让父控件滑动),如果没有滑动到顶部,就要让viewpager中的scrollview滑动(这时候父控件不拦截OnTouchEvent,向子控件传递,让子控件滑动)。
来看一下ViewPager中的实现:
自定义控件:MyScrollView.java:
xml:
Fragment.java:
【博客地址】: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、详细代码如下:
@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) { 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); } @Override public 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" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="@dimen/px_300" android:text="我是第一个页面,向上滑动一下试试1"/> <TextView android:layout_width="match_parent" android:layout_height="@dimen/px_300" android:text="我是第一个页面,向上滑动一下试试2"/> <TextView android:layout_width="match_parent" android:layout_height="@dimen/px_300" android:text="我是第一个页面,向上滑动一下试试3"/> <TextView android:layout_width="match_parent" android:layout_height="@dimen/px_300" android:text="我是第一个页面,向上滑动一下试试4"/> <TextView android: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; @Override public 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() { @Override public void onScrollToBottom() { } @Override public void onScrollToTop() { } @Override public void onScroll(int scrollY) { //判断时候滑动到了顶部 if (scrollY == 0) { PublicStaticClass.IsTop = true; } else { PublicStaticClass.IsTop = false; } } @Override public void notBottom() { } }); } }
6、最后来上效果图:
7、又发现问题:
在第二页上,左右滑动时,在水平方向上如果出现一点变化,就会滑动到第一页上。这里在onInterceptTouchEvent()方法中做了修改,判断滑动的距离。如果左右滑动距离大于上下滑动距离,我们就认为用户在左右滑动,这时候我们要让子控件获取到事件,去切换fragment。相反,如果上下滑动距离大于左右滑动距离,我们就认为用户在上下滑动,这时候让父控件拦截事件。具体代码如下:@Override public 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中仿淘宝商品详情ViewPager页面数据手动滑动
- Android开发案例 - 淘宝商品详情
- 【Android进阶】Android仿淘宝商品浏览滑(拖)动查看详情界面
- Android开发案例 - 淘宝商品详情【转】
- android:仿淘宝商品详情下拉展示浏览历史
- ios 类似淘宝商品详情页面的效果
- ANDROID仿淘宝商品浏览滑(拖)动查看详情界面
- 仿淘宝商品详情页面标题下拉渐变效果
- android自定义视图之类似淘宝商品详情
- ios仿淘宝商品详情页面粘贴商品规格弹出模板
- Android 仿淘宝商品详情页下拉足迹Demo
- Android自定义控件-仿淘宝ios客户端天猫商品详情界面动效
- 实现淘宝商品详情页面的viewPager滑动到最后一张图片跳转的功能
- Android自定义控件-仿淘宝ios客户端天猫商品详情界面
- Android 仿淘宝商品详情标题栏变色,布局层叠效果
- Android自定义控件-仿淘宝ios客户端天猫商品详情界面动效
- android 自定义ViewGroup实现仿淘宝的商品详情页
- Android 仿淘宝京东商品详情页阻力翻页效果
- android 自定义ViewGroup实现仿淘宝的商品详情页
- android 仿淘宝、京东商品详情页 向上拖动查看图文详情控件