分享一个可下拉刷新的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个文件...

你可能感兴趣的:(scrollview)