UI:实现ScrollView能够下拉刷新效果

能够监听是否滑动到底部和顶部的scrollView

package com.danale.cloud.ui.widget;
import com.danale.cloud.utils.LogUtil;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ScrollView;
public class BottomTopScrollView extends ScrollView {

	public BottomTopScrollView(Context context, AttributeSet attrs,
			int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public BottomTopScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public BottomTopScrollView(Context context) {
		super(context);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int childCount = getChildCount();
		
		//计算子view的高度
		childHeightCount = 0;
		for(int i = 0 ; i < childCount ; i++){
			View childAt = getChildAt(i);
			int measuredHeight = childAt.getMeasuredHeight();
			LayoutParams params = (LayoutParams) childAt.getLayoutParams();
			childHeightCount += measuredHeight + params.topMargin + params.bottomMargin;
		}
	}
	
	private int childHeightCount;
	/**
	 * clampedX : 表示在x方向是否可以移动 ,能移动false ,不能移动 true
	 * clampedY : 表示在y方向是否可以移动
	 * 
	 * 通过上面的参数和scrollxx参数就可以知道其是否滑到底部和滑到顶部
	 */
	@Override
	protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,boolean clampedY) {
		super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
		LogUtil.e("BottomTopScrollView", "childHeightCount : "+childHeightCount);
		if(scrollY <= 0){
			mScrollState = ScrollState.TOP_STATE;
			if(scrollY >= childHeightCount - getMeasuredHeight()){
				mScrollState = ScrollState.BOTH_STATE;//表示scrollview 要比childs要高,不需要scrollview 去滑动
			}
		}else if(scrollY > 0){
			mScrollState = ScrollState.SCROLL_STATE;
			if(scrollY >= childHeightCount - getMeasuredHeight()){
				mScrollState = ScrollState.BOTTOM_STATE;//表示scrollview 要比childs要高,不需要scrollview 去滑动
			}
		}
		LogUtil.e("BottomTopScrollView", "scrollstate : " + mScrollState + "/ scrollY:" + scrollY);
	}
	
	private ScrollState mScrollState;
	
	public ScrollState getScrollState(){
		LogUtil.e("BottomTopScrollView", "childHeightCount : "+childHeightCount + "/ measuredHeight : " + getMeasuredHeight());
		if(childHeightCount <= getMeasuredHeight()){
			return ScrollState.BOTH_STATE;
		}
		return mScrollState;
	}
	
	
	/** 滑动位置的状态  TOP_STATE 到达顶部, BOTTOM_STATE 到达底部 , BOTH_STATE 即到达底部也达到了顶部, SCROLL_STATE 可滑动状态*/
	public enum ScrollState{
		TOP_STATE , BOTTOM_STATE , BOTH_STATE , SCROLL_STATE;
	}
}


PullToRefreshScrollView

package com.danale.cloud.ui.widget;

import com.danale.cloud.R;
import com.danale.cloud.ui.widget.BottomTopScrollView.ScrollState;
import com.danale.cloud.utils.LogUtil;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;
/**
 *	类似于qq中的界面,能够上下的拉动
 */
public class PullToRefreshScrollView extends LinearLayout {

	private BottomTopScrollView mScrollView;
	private float downY;
	private Scroller mScroller;
	private int mScaledTouchSlop;
	private boolean isInControl = false;
	
	private final int REFRESH_MIN_SCROLL_HEIGH = 100;

	public PullToRefreshScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mScroller = new Scroller(context);
		mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
	}
	
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		View view = findViewById(R.id.danale_cloud_id_pull_to_refresh_scrollview);
		if(!(view instanceof BottomTopScrollView)){
			throw new IllegalArgumentException("must be used by scrollview to viewgroup's child view !");
		}
		mScrollView = (BottomTopScrollView) view;
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		LayoutParams layoutParams = (LayoutParams) mScrollView.getLayoutParams();
		layoutParams.height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
		layoutParams.weight = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		LogUtil.e("PullToRefreshScrollView", "onTouchEvent " + event.getX());
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			downY = event.getY();
			return true;
			
		case MotionEvent.ACTION_MOVE:
			float moveY = event.getY();
			float dY = (moveY - downY)/1.5f;
			scrollBy(0, (int) -dY);
			downY = moveY;
			isInControl = false;
			break;
		
		case MotionEvent.ACTION_UP:
			float downY = event.getY();
			float scrollY = getScrollY();
			handlerPullToRefresh(scrollY);
			mScroller.startScroll(0, (int)scrollY, 0, (int)-scrollY, (int)Math.abs(scrollY));
			invalidate();
			break;

		default:
			break;
		}
		return super.onTouchEvent(event);
	}
	
	private void handlerPullToRefresh(float scrollY) {
		if(scrollY < -REFRESH_MIN_SCROLL_HEIGH && mListener != null){
			mListener.onRefresh();
		}
	}

	@Override
	public void computeScroll() {
		if(mScroller.computeScrollOffset()){
			scrollTo(0, mScroller.getCurrY());
			invalidate();
		}
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			downY = ev.getX();
			break;
			
		case MotionEvent.ACTION_MOVE:
			float moveY = ev.getY();
			float dY = moveY - downY;
			int scrollY = getScrollY();
			
			if(Math.abs(dY) > mScaledTouchSlop){
				if(!isInControl && dY > 0 && (ScrollState.TOP_STATE.equals(mScrollView.getScrollState()) ||
						ScrollState.BOTH_STATE.equals(mScrollView.getScrollState())) && scrollY == 0){ // 上滑 ,满足该条件可下拉刷新
					isInControl = true;
					ev.setAction(MotionEvent.ACTION_CANCEL);
					MotionEvent ev2 = MotionEvent.obtain(ev);
					dispatchTouchEvent(ev);
					
					ev2.setAction(MotionEvent.ACTION_DOWN);
					return dispatchTouchEvent(ev2);
				}else if(!isInControl && dY < 0 &&(ScrollState.BOTTOM_STATE.equals(mScrollView.getScrollState()) ||
						ScrollState.BOTH_STATE.equals(mScrollView.getScrollState())) && scrollY == 0){//下滑,满足该条件可上拉加载
					isInControl = true;
					ev.setAction(MotionEvent.ACTION_CANCEL);
					MotionEvent ev2 = MotionEvent.obtain(ev);
					dispatchTouchEvent(ev);
					
					ev2.setAction(MotionEvent.ACTION_DOWN);
					return dispatchTouchEvent(ev2);
				}
			}
			break;

		default:
			break;
		}
		return super.dispatchTouchEvent(ev);
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		LogUtil.e("PullToRefreshScrollView","onInterceptTouchEvent");
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			downY = ev.getY();
			break;
			
		case MotionEvent.ACTION_MOVE:
			float moveY = ev.getY();
			float dY = moveY - downY;
			if(Math.abs(dY) > mScaledTouchSlop){
				if(dY > 0 && (ScrollState.TOP_STATE.equals(mScrollView.getScrollState()) ||
						ScrollState.BOTH_STATE.equals(mScrollView.getScrollState()))){ // 上滑 ,满足该条件可下拉刷新
					return true;
				}else if(dY < 0 &&(ScrollState.BOTTOM_STATE.equals(mScrollView.getScrollState()) ||
						ScrollState.BOTH_STATE.equals(mScrollView.getScrollState()))){//下滑,满足该条件可上拉加载
					return true;
				}
			}
			break;
			
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}
	
	public interface OnPullToRefreshListener{
		public void onRefresh();
	}
	
	private OnPullToRefreshListener mListener;
	public void setOnPullToRefreshListener(OnPullToRefreshListener listener){
		this.mListener = listener;
	}
}


布局相关的问题

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.drawable_ui.view.PullToRefreshScrollView
        android:id="@+id/pull_to_refresh_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <com.example.drawable_ui.view.BottomTopScrollView
            android:id="@id/id_pull_to_refresh_scrollview"
            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="200dp"
                    android:background="#ffa22c"
                    android:gravity="center_vertical"
                    android:text="sdfadaddddad" 
                    android:clickable="true"
                    android:onClick="clickTv3"  />
		若干个textview....
            </LinearLayout>
        </com.example.drawable_ui.view.BottomTopScrollView>
    </com.example.drawable_ui.view.PullToRefreshScrollView>

</LinearLayout>

values 文件加下 ids.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>    
    <item name="id_pull_to_refresh_scrollview" type="id"></item>
</resources>

在代码中设置setOnPullToRefreshListener(OnPullToRefreshListener listener),就可以实现下拉刷新了

你可能感兴趣的:(UI:实现ScrollView能够下拉刷新效果)