下来刷新的Scrollview

本文介绍了一个名为XScrollView的自定义组件,该组件允许在Android应用中实现下拉刷新功能。通过继承LinearLayout并覆盖触摸事件,XScrollView可以检测用户的下拉操作,并执行刷新逻辑。文章提供了详细的代码实现和使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



import com.reacnn.android.R;
import com.reacnn.android.utils.DateOperation;

import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.Scroller;
import android.widget.TextView;

public class XScrollView extends LinearLayout {
	enum Status {
		NORMAL, DRAGGING, REFRESHING,
	}

	private Status status = Status.NORMAL;

	private final static float MIN_MOVE_DISTANCE = 5.0f;// 最小移动距离,用于判断是否在下拉,设置为0则touch事件的判断会过于平凡。具体值可以根据自己来设定

	private Scroller scroller;
	private View mHeaderView;
	private ImageView mArrowImageView;
	private int mHeaderViewHeight = -60;
	private ImageView bar;
	private TextView downTextView;
	private TextView mHeaderTimeView;

	private IXScrollViewListener refreshListener;// 刷新监听器

	private int lastY;
	private Context mContext;

	private Animation mRotateUpAnim;
	private Animation mRotateDownAnim;
	private final int ROTATE_ANIM_DURATION = 180;

	@Override
	public void onWindowFocusChanged(boolean hasFocus) {
		try {
			AnimationDrawable ad = (AnimationDrawable) bar.getBackground();
			ad.start();
		} catch (Exception e) {
		}
		super.onWindowFocusChanged(hasFocus);
	}

	public XScrollView(Context context) {
		super(context);
		mContext = context;
		init();
	}

	public XScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init();
	}

	/**
	 * 初始化
	 * 
	 * @MethodDescription init
	 * @exception
	 * @since 1.0.0
	 */
	private void init() {
		mHeaderViewHeight = getPixelByDip(mContext, mHeaderViewHeight);
		scroller = new Scroller(mContext);
		mHeaderView = LayoutInflater.from(mContext).inflate(
				R.layout.control_xlistview_header, null);
		mArrowImageView = (ImageView) mHeaderView
				.findViewById(R.id.xlistview_header_arrow);
		bar = (ImageView) mHeaderView
				.findViewById(R.id.xlistview_header_progressbar);
		downTextView = (TextView) mHeaderView
				.findViewById(R.id.xlistview_header_hint_textview);
		mHeaderTimeView = (TextView) mHeaderView
				.findViewById(R.id.xlistview_header_time);

		LayoutParams lp = new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, -mHeaderViewHeight);
		lp.topMargin = mHeaderViewHeight;
		lp.gravity = Gravity.CENTER;
		addView(mHeaderView, lp);

		mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
		mRotateUpAnim.setFillAfter(true);
		mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
		mRotateDownAnim.setFillAfter(true);
	}

	private String mtime = "";

	/**
	 * set last refresh time
	 * 
	 * @param time
	 */
	public void setRefreshTime(String time) {
		this.mtime = time;
		mHeaderTimeView.setText(time);
	}

	public String GetRefreshTime() {
		return this.mtime;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (status == Status.REFRESHING)
			return false;
		int y = (int) event.getRawY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			lastY = y;
			break;
		case MotionEvent.ACTION_MOVE:
			int m = y - lastY;
			doMovement(m);
			this.lastY = y;
			break;
		case MotionEvent.ACTION_UP:
			fling();
			break;
		}
		return true;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent e) {
		int action = e.getAction();
		int y = (int) e.getRawY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			lastY = y;
			break;
		case MotionEvent.ACTION_MOVE:
			int m = y - lastY;
			this.lastY = y;
			if (m > MIN_MOVE_DISTANCE && canScroll()) {
				return true;
			}
			break;
		case MotionEvent.ACTION_UP:
			break;
		case MotionEvent.ACTION_CANCEL:
			break;
		}
		return false;
	}

	/**
	 * up事件处理
	 */
	private void fling() {
		LinearLayout.LayoutParams lp = (LayoutParams) mHeaderView
				.getLayoutParams();
		if (lp.topMargin > 0) {
			status = Status.REFRESHING;
			refresh();
		} else {
			status = Status.NORMAL;
			returnInitState();
		}
	}

	private void returnInitState() {
		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mHeaderView
				.getLayoutParams();
		int i = lp.topMargin;
		scroller.startScroll(0, i, 0, mHeaderViewHeight);
		invalidate();
	}

	/**
	 * 执行刷新
	 * 
	 * @MethodDescription refresh
	 * @exception
	 * @since 1.0.0
	 */
	private void refresh() {
		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mHeaderView
				.getLayoutParams();
		int i = lp.topMargin;
		mArrowImageView.clearAnimation();
		mArrowImageView.setVisibility(View.INVISIBLE);
		bar.setVisibility(View.VISIBLE);
		downTextView.setText(R.string.xlistview_header_hint_loading);
		scroller.startScroll(0, i, 0, 0 - i);
		invalidate();
		if (refreshListener != null) {
			refreshListener.onRefresh();
		}
	}

	/**
	 * 
	 */
	@Override
	public void computeScroll() {
		if (scroller.computeScrollOffset()) {
			int i = this.scroller.getCurrY();
			LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.mHeaderView
					.getLayoutParams();
			int k = Math.max(i, mHeaderViewHeight);
			lp.topMargin = k;
			this.mHeaderView.setLayoutParams(lp);
			postInvalidate();
		}
	}

	/**
	 * 下拉move事件处理
	 * 
	 * @param moveY
	 */
	private void doMovement(int moveY) {
		status = Status.DRAGGING;
		LinearLayout.LayoutParams lp = (LayoutParams) mHeaderView
				.getLayoutParams();
		float f1 = lp.topMargin;
		float f2 = moveY * 0.3F;
		int i = (int) (f1 + f2);
		lp.topMargin = i;
		mHeaderView.setLayoutParams(lp);
		mHeaderView.invalidate();
		invalidate();
		mHeaderTimeView.setVisibility(View.VISIBLE);
		downTextView.setVisibility(View.VISIBLE);
		mArrowImageView.setVisibility(View.VISIBLE);
		bar.setVisibility(View.GONE);
		if (lp.topMargin > 0) {
			mArrowImageView.clearAnimation();
			mArrowImageView.startAnimation(mRotateUpAnim);
			downTextView.setText(R.string.xlistview_header_hint_ready);
		} else {
			mArrowImageView.startAnimation(mRotateDownAnim);
			downTextView.setText(R.string.xlistview_header_hint_normal);
		}
	}

	/**
	 * 设置监听
	 * 
	 * @MethodDescription setRefreshListener
	 * @param listener
	 * @exception
	 * @since 1.0.0
	 */
	public void setIXScrollViewListener(IXScrollViewListener listener) {
		this.refreshListener = listener;
	}

	/**
	 * 结束刷新事件
	 */
	public void finishRefresh() {
		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.mHeaderView
				.getLayoutParams();
		int i = lp.topMargin;
		mArrowImageView.setVisibility(View.VISIBLE);
		mHeaderTimeView.setVisibility(View.VISIBLE);
		downTextView.setVisibility(VISIBLE);
		bar.setVisibility(GONE);
		setRefreshTime(DateOperation.GetSysCurrentTime());
		scroller.startScroll(0, i, 0, mHeaderViewHeight);
		invalidate();
		status = Status.NORMAL;
	}

	/**
	 * 此方法兼容两种子布局的判断,listview,scrollview 主要作用是判断两个子View是否滚动到了最上面,若是,则表示此次touch
	 * move事件截取然后让layout来处理,来移动下拉视图,反之则不然
	 * 
	 * @MethodDescription canScroll
	 * @return
	 * @exception
	 * @since 1.0.0
	 */
	private boolean canScroll() {
		View childView;
		if (getChildCount() > 1) {
			childView = this.getChildAt(1);
			if (childView instanceof ListView) {
				int top = ((ListView) childView).getChildAt(0).getTop();
				int pad = ((ListView) childView).getListPaddingTop();
				if ((Math.abs(top - pad)) < 3
						&& ((ListView) childView).getFirstVisiblePosition() == 0) {
					return true;
				} else {
					return false;
				}
			} else if (childView instanceof ScrollView) {
				if (((ScrollView) childView).getScrollY() == 0) {
					return true;
				} else {
					return false;
				}
			}

		}
		return false;
	}

	public static int getPixelByDip(Context c, int pix) {
		float f1 = c.getResources().getDisplayMetrics().density;
		float f2 = pix;
		return (int) (f1 * f2 + 0.5F);
	}

	/**
	 * 刷新监听接口
	 * 
	 * @author Nono
	 * 
	 */
	public interface IXScrollViewListener {
		public void onRefresh();
	}

}

调用:

<?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.reacnn.android.view.listview.XScrollView
        android:id="@+id/xScrollView1"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:orientation="vertical" >

        <ScrollView
            android:id="@+id/scrollView1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <Button
                    android:id="@+id/button1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Button" />

                <Button
                    android:id="@+id/button1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Button" />

                <Button
                    android:id="@+id/button1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Button" />

                <Button
                    android:id="@+id/button1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Button" />
            </LinearLayout>
        </ScrollView>
    </com.reacnn.android.view.listview.XScrollView>

</LinearLayout>



import com.reacnn.android.R;
import com.reacnn.android.view.listview.XScrollView;
import com.reacnn.android.view.listview.XScrollView.IXScrollViewListener;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;

public class FrmAScrollViewTestActivity extends Activity implements
		IXScrollViewListener {

	private XScrollView mScrollView = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_activity);
		mScrollView = (XScrollView) findViewById(R.id.xScrollView1);
		mScrollView.setIXScrollViewListener(this);
	}

	@SuppressLint("HandlerLeak")
	Handler handler = new Handler() {
		public void handleMessage(Message message) {
			super.handleMessage(message);
			mScrollView.finishRefresh();
			Toast.makeText(FrmAScrollViewTestActivity.this, "刷新完成",
					Toast.LENGTH_SHORT).show();
		};
	};

	@Override
	public void onRefresh() {
		handler.sendEmptyMessageDelayed(1, 2000);
	}
}


headview的相关内容见前面的下拉刷新的LIstView


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值