This article will introduce to you the DEMO details of the Android imitation Taobao and Jingdong product details page. Drag up to view graphic details. Use two scrollViews. Two scrollViews are arranged vertically. The vertical position of the two scrollViews is controlled by customizing the viewGroup. Arrangement, and handling of sliding events. Friends who are interested in dragging to view picture and text details in android should learn together
1. Taobao product details page effect
Our effect
2. Implementation ideas
Use two scrollViews , two scrollViews are arranged vertically, and the vertical arrangement of the two scrollViews is controlled by customizing the viewGroup, as well as the processing of sliding events. As shown below
3. Specific implementation
1. Inherit the viewGroup custom layout View and override the onMeasure() and onLayout methods. In the onLayout method Complete the vertical layout of the two sub-ScrollViews. The code is as follows:
Layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.baoyunlong.view.pulluptoloadmore.MainActivity"> <com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.baoyunlong.view.pulluptoloadmore.MyScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:scaleType="fitXY" android:src="@drawable/a1" android:layout_width="match_parent" android:layout_height="180dp" /> <TextView android:text="这里是标题" android:textSize="18dp" android:layout_marginRight="10dp" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:layout_marginTop="10dp" android:text="子标题" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:textSize="18dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> .............. <LinearLayout android:layout_height="0dp" android:layout_weight="1" android:gravity="bottom" android:layout_width="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:height="50dp" android:background="#b11" android:gravity="center" android:text="继续拖动查看图文详情" android:textColor="#000" /> </LinearLayout> </LinearLayout> </com.baoyunlong.view.pulluptoloadmore.MyScrollView> <com.baoyunlong.view.pulluptoloadmore.MyScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/a1" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/a3" /> ......... </LinearLayout> </com.baoyunlong.view.pulluptoloadmore.MyScrollView> </com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore> </RelativeLayout>
Code:
public class PullUpToLoadMore extends ViewGroup { public PullUpToLoadMore(Context context) { super(context); } public PullUpToLoadMore(Context context, AttributeSet attrs) { super(context, attrs); } public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @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(); } } }
2. Handling sliding events
The rules are as follows:
(1) When on the first screen The first ScrollView has slid to the bottom and the sliding direction is upward. At this time, the sliding event should be handed over to the parent view for processing, that is, to intercept the event and let onInterceptTouchEvent return true. Then the parent view scrolls through the scrollBy() method to display the second scrollView.
(2) When on the second screen, the second ScrollView has slid to the top and the sliding direction is sliding down. At this time, the sliding event is handed over to the parent view for processing, and the first one is displayed according to the sliding event. ScrollView.
(3) When the finger leaves the screen, decide whether to rebound to the first ScrollView or the second ScrollView based on the sliding speed, and obtain the sliding speed through VelocityTracker.
3. Processing of some details
(1) If you carefully observe the implementation effect of Taobao, you will find that when you slide to the point where you just saw "Continue dragging, view the picture and text details" ", lift your finger, then press and drag upwards again. You will find that the second page will not be drawn out, but will stay at the bottom of "Continue dragging to view picture and text details". JD.com's effect also the same. This user experience is not very good, let’s optimize it. In fact, by looking at the source code of ScrollView, we can see that this is because the default implementation of the onTouchEvent method of the ScrollView class calls the parent.requestDisallowInterceptTouchEvent(true) method to prevent us from intercepting the event, causing the onInterceptTouchEvent method of our parent view to be unable to execute, thus intercepting. If the event cannot be received or the event cannot be intercepted, our onTouchEvent cannot be executed. OnTouchEvent cannot be executed. The scrolling logic we wrote in onTouchEvent cannot be executed, resulting in the inability to scroll effect as we saw above. The solution is that we need to rewrite the dispatchTouchEvent() method to prevent the subview from interfering with us, so that we can complete it in one go when sliding. The code is as follows:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { //防止子View禁止父view拦截事件 this.requestDisallowInterceptTouchEvent(false); return super.dispatchTouchEvent(ev); }
(2) The problem of monitoring ScrollView sliding events
ScrollView does not provide a monitoring method for scrolling events, so there is no There is no way to determine whether it has scrolled to the top or bottom. Here we inherit ScrollView and implement scrolling event monitoring ourselves.
/** * 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(); }
4. The complete code is as follows
/** * Created by baoyunlong on 16/6/8. */ 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(); } } }
Source code:
github address
The above is the detailed description of the Android imitation Taobao and JD.com product details page that the editor introduces to you. Drag up to view the graphic and text details control DEMO. I hope it will be helpful to everyone. , if you have any questions, please leave me a message, and the editor will reply to you in time. I would also like to thank you all for your support of the PHP Chinese website!
For more Android imitation Taobao and Jingdong product details pages, drag up to view graphic and text details control DEMO details. For related articles, please pay attention to the PHP Chinese website!