原理:就是动态改变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个文件...
时间: 2024-10-06 00:45:04