分享一个可下拉刷新的ScrollView

原理:就是动态改变ScrollView header的margin实现

主要的代码:

 http://blog.csdn.net/swust_chenpeng/article/details/39289721

 
public class RefreshScrollView extends ScrollView {  
  
    private final static int SCROLL_DURATION = 400;  
    private final static float OFFSET_RADIO = 1.8f;  
    private int headerHeight = 0;  
    private boolean enableRefresh = true;  
    private boolean refreshing = false;  
    private int lastY;  
    private Scroller scroller = null;  
    private OnRefreshScrollViewListener listener = null;  
    private LinearLayout scrollContainer = null;  
    private ScrollViewHeader headerView = null;  
  
    public RefreshScrollView(Context context) {  
        super(context);  
        // TODO Auto-generated constructor stub  
        if (!isInEditMode()) {  
            initView(context);  
        }  
    }  
  
    public RefreshScrollView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        // TODO Auto-generated constructor stub  
        if (!isInEditMode()) {  
            initView(context);  
        }  
    }  
  
    public RefreshScrollView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        // TODO Auto-generated constructor stub  
        if (!isInEditMode()) {  
            initView(context);  
        }  
    }  
  
    /** 
     * 初始化view 
     */  
    private void initView(Context context) {  
        scroller = new Scroller(context);  
        headerView = new ScrollViewHeader(context);  
        LinearLayout.LayoutParams headerViewParams = new LinearLayout.LayoutParams(  
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);  
        //scrollview只允许嵌套一个子布局  
        scrollContainer = new LinearLayout(context);  
        scrollContainer.addView(headerView, headerViewParams);  
        scrollContainer.setOrientation(LinearLayout.VERTICAL);  
        addView(scrollContainer);  
        //提前获取headerView的高度  
        headerView.getViewTreeObserver().addOnGlobalLayoutListener(  
                new OnGlobalLayoutListener() {  
  
                    @SuppressWarnings("deprecation")  
                    @Override  
                    public void onGlobalLayout() {  
                        // TODO Auto-generated method stub  
                        headerHeight = headerView.getHeight();  
                        headerView.updateMargin(-headerHeight);  
                        headerView.getViewTreeObserver()  
                                .removeGlobalOnLayoutListener(this);  
                    }  
                });  
    }  
  
    /** 
     * 设置内容区域 
     *  
     * @param context 
     * @param resId 
     */  
    public void setupContainer(Context context, View containerView) {  
        scrollContainer.addView(containerView);  
    }  
  
    /** 
     * 设置scroll是否可以刷新 
     *  
     * @param enableRefresh 
     */  
    public void setEnableRefresh(boolean enableRefresh) {  
        this.enableRefresh = enableRefresh;  
    }  
  
    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
        // TODO Auto-generated method stub  
        switch (ev.getAction()) {  
        case MotionEvent.ACTION_DOWN:  
            lastY = (int) ev.getY();  
            break;  
        case MotionEvent.ACTION_MOVE:  
            int deltY = (int) (ev.getY() - lastY);  
            lastY = (int) ev.getY();  
            Logger.d("getScrollY:" + getScrollY());  
            if (getScrollY() == 0  
                    && (deltY > 0 || headerView.getTopMargin() > -headerHeight)) {  
                updateHeader(deltY/OFFSET_RADIO);  
                return true;  
            }   
            break;  
        default:  
            //这里没有使用action_up的原因是,可能会受到viewpager的影响接收到action_cacel事件  
            Logger.d("ev.getAction: " +ev.getAction());  
            if (getScrollY() == 0) {  
                Logger.d("topMargin():" + headerView.getTopMargin());  
                if (headerView.getTopMargin() > 0 && enableRefresh && !refreshing) {  
                    refreshing = true;  
                    headerView.setState(ScrollViewHeader.STATE_REFRESHING);  
                    new Handler().postDelayed(new Runnable() {  
  
                        @Override  
                        public void run() {  
                            // TODO Auto-generated method stub  
                            if(listener != null) {  
                                listener.onRefresh();  
                                refreshing = false;  
                                ShowUtils.shortShow("更新成功");  
                                resetHeaderView();  
                            }  
                        }  
                    }, 3000);  
                }  
                Logger.d("resetHeaderView...");  
                resetHeaderView();  
            }  
            break;  
        }  
        return super.onTouchEvent(ev);  
    }  
  
    /** 
     * 更新headerview的高度,同时更改状态 
     *  
     * @param deltY 
     */  
    public void updateHeader(float deltY) {  
        int currentMargin = (int) (headerView.getTopMargin() + deltY);  
        headerView.updateMargin(currentMargin);  
        if(enableRefresh && !refreshing) {  
            if (currentMargin > 0) {  
                headerView.setState(ScrollViewHeader.STATE_READY);  
            } else {  
                headerView.setState(ScrollViewHeader.STATE_NORMAL);  
            }  
        }  
    }  
  
    /** 
     * 重置headerview的高度 
     */  
    public void resetHeaderView() {  
        int margin = headerView.getTopMargin();  
        if(margin == -headerHeight) {  
            return ;  
        }  
        if(margin < 0 && refreshing) {  
            //当前已经在刷新,又重新进行拖动,但未拖满,不进行操作  
            return ;  
        }  
        int finalMargin = 0;  
        if(margin <= 0 && !refreshing) {  
            finalMargin = headerHeight;  
        }  
        Logger.d("margin: " + margin);  
        Logger.d("finalMargin: " + finalMargin);  
        //松开刷新,或者下拉刷新,又松手,没有触发刷新  
        scroller.startScroll(0, -margin, 0, finalMargin + margin, SCROLL_DURATION);  
          
        invalidate();  
    }  
      
    /** 
     * 开始刷新 
     */  
    public void startRefresh() {  
        refreshing = true;  
        headerView.setState(ScrollViewHeader.STATE_REFRESHING);  
        if(listener != null) {  
            Logger.d("xxx: " + headerHeight);  
            scroller.startScroll(0, 0, 0, headerHeight, SCROLL_DURATION);  
            invalidate();  
            listener.onRefresh();  
        }  
    }  
      
    /** 
     * 停止刷新 
     */  
    public void stopRefresh() {  
        if(refreshing) {  
            refreshing = false;  
            resetHeaderView();  
        }  
    }  
      
    @Override  
    public void computeScroll() {  
        // TODO Auto-generated method stub  
        if(scroller.computeScrollOffset()) {  
            Logger.d("getCurrY: " + scroller.getCurrY());   
            headerView.updateMargin(-scroller.getCurrY());  
            //继续重绘  
            postInvalidate();  
        }  
        super.computeScroll();  
    }  
      
    public void setOnRefreshScrollViewListener(OnRefreshScrollViewListener listener) {  
        this.listener = listener;  
    }  
      
    public interface OnRefreshScrollViewListener {  
        public void onRefresh();  
    }  
}  

代码其实还是比较容易,但是但是,自己还是花了很多时间,脑袋瓜不够灵活呀...

下面是ScrollViewHeader的代码:

 
public class ScrollViewHeader extends RelativeLayout {  
      
    public final static int STATE_NORMAL = 0;  
    public final static int STATE_READY = 1;  
    public final static int STATE_REFRESHING = 2;  
    private final int ROTATE_ANIM_DURATION = 180;  
    private int topMargin = 0;  
    private int state = STATE_NORMAL;  
    private TextView refreshTv = null;  
    private TextView refreshTimeTv = null;  
    private ProgressBar refreshProgress = null;  
    private ImageView refreshArrow = null;  
    private Animation animationUp = null;  
    private Animation animationDown = null;  
      
    public ScrollViewHeader(Context context) {  
        super(context);  
        // TODO Auto-generated constructor stub  
        if(!isInEditMode())   
            initView(context);  
    }  
  
    public ScrollViewHeader(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        // TODO Auto-generated constructor stub  
        if(!isInEditMode())  
            initView(context);  
    }  
  
    public ScrollViewHeader(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        // TODO Auto-generated constructor stub  
        if(!isInEditMode())  
            initView(context);  
    }  
  
    /** 
     * 初始化相关的view 
     */  
    public void initView(Context context) {  
        animationDown = new RotateAnimation(-180f, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);  
        animationDown.setDuration(ROTATE_ANIM_DURATION);  
        animationDown.setFillAfter(true);  
        animationUp = new RotateAnimation(0, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);  
        animationUp.setDuration(ROTATE_ANIM_DURATION);  
        animationUp.setFillAfter(true);  
        setPadding(10, 25, 10, 25);  
        View view = LayoutInflater.from(context).inflate(R.layout.scrollview_header, this, true);  
        refreshTv = (TextView) view.findViewById(R.id.refresh_text);  
        refreshTimeTv = (TextView) view.findViewById(R.id.refresh_time);  
        refreshProgress = (ProgressBar) view.findViewById(R.id.refresh_progress);  
        refreshArrow = (ImageView) view.findViewById(R.id.refresh_arrow);  
    }  
      
    /** 
     * 设置scrollviewHeader的状态 
     * @param state 
     */  
    public void setState(int state) {  
        if(this.state == state) {  
            return ;  
        }  
        switch (state) {  
        case STATE_NORMAL:  
            refreshTv.setText("下拉刷新");  
            refreshArrow.setVisibility(View.VISIBLE);  
            refreshProgress.setVisibility(View.INVISIBLE);  
            if(this.state == STATE_READY) {  
                refreshArrow.startAnimation(animationDown);  
            } else if(this.state == STATE_REFRESHING) {  
                refreshArrow.clearAnimation();  
            }  
            break;  
        case STATE_READY:  
            refreshTv.setText("松开刷新");  
            refreshArrow.setVisibility(View.VISIBLE);  
            refreshProgress.setVisibility(View.INVISIBLE);  
            refreshArrow.startAnimation(animationUp);  
            break;  
        case STATE_REFRESHING:  
            refreshTv.setText("正在加载...");  
            refreshProgress.setVisibility(View.VISIBLE);  
            refreshArrow.clearAnimation();  
            refreshArrow.setVisibility(View.INVISIBLE);  
            break;  
        default:  
            break;  
        }  
        this.state = state;  
    }  
      
    /** 
     * 更新header的margin 
     * @param margin 
     */  
    public void updateMargin(int margin) {  
        //这里用Linearlayout的原因是Headerview的父控件是scrollcontainer是一个linearlayout   
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) this.getLayoutParams();  
        params.topMargin = margin;  
        topMargin = margin;  
        setLayoutParams(params);  
    }  
      
    /** 
     * 获取header的margin 
     * @return 
     */  
    public int getTopMargin() {  
        return topMargin;  
    }  
}  

header的布局文件,scrollview_header

<?xml version="1.0" encoding="utf-8"?>  
<merge xmlns:android="http://schemas.android.com/apk/res/android" >  
  
    <LinearLayout  
        android:id="@+id/refresh_des"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true"  
        android:gravity="center"  
        android:orientation="vertical" >  
  
        <TextView  
            android:id="@+id/refresh_text"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="下拉刷新" />  
  
        <TextView  
            android:id="@+id/refresh_time"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="5分钟前更新" />  
    </LinearLayout>  
  
    <ProgressBar  
        android:id="@+id/refresh_progress"  
        android:layout_width="30dip"  
        android:layout_height="30dip"  
        android:layout_centerVertical="true"  
        android:layout_marginRight="10dip"  
        android:layout_toLeftOf="@id/refresh_des"  
        android:visibility="invisible" />  
  
    <ImageView  
        android:id="@+id/refresh_arrow"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerVertical="true"  
        android:layout_marginRight="10dip"  
        android:layout_toLeftOf="@id/refresh_des"  
        android:src="@drawable/arrow" />  
  
</merge>  

好了,相关的源码就只有3个文件...

原文地址:https://www.cnblogs.com/lbangel/p/4108898.html