首页 > 代码库 > 分享一个可下拉刷新的ScrollView

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