我们的效果
二、实现思路
使用两个scrollView,两个scrollView 竖直排列,通过自定义viewGroup来控制两个scrollView的竖直排列,以及滑动事件的处理。如下图
三、具体实现
1、继承viewGroup自定义布局View 重写onMeasure()和onLayout方法,在onLayout方法中完成对两个子ScrollView的竖直排列布局,代码如下:
布局文件:
<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.MyScrollViewandroid: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"> <ImageViewandroid:scaleType="fitXY"android:src="@drawable/a1"android:layout_width="match_parent"android:layout_height="180dp" /> <TextViewandroid: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" /> <TextViewandroid: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" /> .............. <LinearLayoutandroid: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.MyScrollViewandroid: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"> <ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/a1" /> <ImageViewandroid: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>代码:
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);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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、处理滑动事件
@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) { //防止子View禁止父view拦截事件 this.requestDisallowInterceptTouchEvent(false); return super.dispatchTouchEvent(ev);}(2)、监听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();}4、完整代码如下
/*** 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() {@Overridepublic void run() { topScrollView = (MyScrollView) getChildAt(0); bottomScrollView = (MyScrollView) getChildAt(1); topScrollView.setScrollListener(new MyScrollView.ScrollListener() {@Overridepublic void onScrollToBottom() { topScrollViewIsBottom = true;}@Overridepublic void onScrollToTop() {}@Overridepublic void onScroll(int scrollY) {}@Overridepublic void notBottom() { topScrollViewIsBottom = false;} }); bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {@Overridepublic void onScrollToBottom() {}@Overridepublic void onScrollToTop() {}@Overridepublic void onScroll(int scrollY) { if (scrollY == 0) {bottomScrollVIewIsInTop = true; } else {bottomScrollVIewIsInTop = false; }}@Overridepublic void notBottom() {} }); position1Y = topScrollView.getBottom(); scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();} });}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) { //防止子View禁止父view拦截事件 this.requestDisallowInterceptTouchEvent(false); return super.dispatchTouchEvent(ev);}@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) {isIntercept = true; }} } break; } return isIntercept;}@Overridepublic 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;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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();}@Overridepublic void computeScroll() { if (scroller.computeScrollOffset()) {scrollTo(scroller.getCurrX(), scroller.getCurrY());postInvalidate(); }} }源码: