下拉刷新XListView的简单分析

依照这篇博文里的思路分析和理解的

先要理解Scroller,看过的博文:

http://ipjmc.iteye.com/blog/1615828

http://blog.csdn.net/wangjinyu501/article/details/32339379

还要理解View的touch时间传递:

http://www.codekk.com/open-source-project-analysis/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8BView%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92

在实现中遇到的问题:

1、下拉时,下拉区域不会尾随下拉而变化,仅仅显示当中一部分。

图:

解决:採用设置下拉区域的paddind,实现尾随滚动效果。终于图:

2、当下拉超过极限高度后向上滑动时。listview会尾随滑动。

解决方法是通过在onTouchEvent推断这一情况推断这一情况,具体在代码里。

代码:

下拉区域布局文件

<?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="wrap_content"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/xlistview_header_content"
        android:layout_width="fill_parent"
        android:layout_height="60dp"
        android:layout_marginBottom="2dp"
        android:gravity="center_horizontal" >

        <TextView
            android:id="@+id/xlistview_header_hint_textview"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:text="正在载入"
            android:textColor="@android:color/black"
            android:textSize="14sp" />

        <ImageView
            android:id="@+id/xlistview_header_image"
            android:layout_width="30dp"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@id/xlistview_header_hint_textview"
            android:src="@drawable/indicator_arrow" />

        <ProgressBar
            android:id="@+id/xlistview_header_progressbar"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@id/xlistview_header_hint_textview"
            android:visibility="invisible" />
    </RelativeLayout>

</LinearLayout>

下拉区域

package com.example.test;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
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.ProgressBar;
import android.widget.TextView;

public class XListViewHeader extends LinearLayout {

	private static final String HINT_NORMAL = "下拉刷新";
	private static final String HINT_READY = "松开刷新数据";
	private static final String HINT_LOADING = "正在载入...";

	// 正常状态,下拉未超过head高度
	public final static int STATE_NORMAL = 0;
	// 准备刷新状态,也就是箭头方向发生改变之后的状态,可是没有刷新
	public final static int STATE_READY = 1;
	// 刷新状态。箭头变成了progressBar,正在刷新
	public final static int STATE_REFRESHING = 2;
	// 布局容器,也就是根布局
	private LinearLayout mContentLayout;
	// 箭头图片
	private ImageView mImageView;
	// 刷新状态显示
	private ProgressBar mProgressBar;
	// 说明文本
	private TextView mHintTextView;
	// 记录当前的状态
	private int mState = -1;
	// 用于改变箭头的方向的动画
	private Animation mRotateUpAnim;
	private Animation mRotateDownAnim;
	// 动画持续时间
	private final int ROTATE_ANIM_DURATION = 180;

	private int headHeight;
	private Context context;

	public XListViewHeader(Context context) {
		super(context);
		this.context = context;
		init();
	}

	private void init() {
		LinearLayout.LayoutParams lp = new LayoutParams(
				LayoutParams.MATCH_PARENT, 0);// 初始化高度为0
		mContentLayout = (LinearLayout) LayoutInflater.from(context).inflate(
				R.layout.xlistview_header, null);
		mContentLayout.setLayoutParams(lp);
		addView(mContentLayout);

		mImageView = (ImageView) mContentLayout
				.findViewById(R.id.xlistview_header_image);// 箭头图片
		mHintTextView = (TextView) mContentLayout
				.findViewById(R.id.xlistview_header_hint_textview);// 提示文本
		mProgressBar = (ProgressBar) mContentLayout
				.findViewById(R.id.xlistview_header_progressbar);// 进度条
		mRotateUpAnim = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF,
				0.5f, Animation.RELATIVE_TO_SELF, 0.5f);// 箭头向上旋转的动画
		mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);// 动画持续时间
		mRotateUpAnim.setFillAfter(true);// 动画终止时停留在最后,也就是保留动画以后的状态
		mRotateDownAnim = new RotateAnimation(-180, 0,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		mRotateDownAnim.setFillAfter(true);
		setState(STATE_NORMAL);// 初始化设置为正常模式
	}

	public void setState(int state) {
		if (state == mState) {
			return;
		}
		if (state == STATE_REFRESHING) {// 设置为正在刷新状态时,清楚全部动画,箭头隐藏, 进度条显示
			mImageView.clearAnimation();
			mImageView.setVisibility(View.GONE);
			mProgressBar.setVisibility(View.VISIBLE);
		} else {
			mImageView.setVisibility(View.VISIBLE);
			mProgressBar.setVisibility(View.GONE);
		}
		switch (state) {
		case STATE_NORMAL:
			if (mState == STATE_READY) {// 由准备状态变为正常状态。开启向下动画
				mImageView.startAnimation(mRotateDownAnim);
			} else {
				mImageView.clearAnimation();
			}
			mHintTextView.setText(HINT_NORMAL);
			break;
		case STATE_READY:
			if (mState == STATE_NORMAL) {
				mImageView.startAnimation(mRotateUpAnim);
			}
			mHintTextView.setText(HINT_READY);
			break;
		case STATE_REFRESHING:
			mHintTextView.setText(HINT_LOADING);
			break;
		}
		mState = state;
	}

	@SuppressLint("NewApi")
	public void setVisitHeight(int height) {
		if (height < 0) {
			height = 0;
		}
		LinearLayout.LayoutParams lp = (LayoutParams) mContentLayout
				.getLayoutParams();
		lp.height = height;
		mContentLayout.setLayoutParams(lp);
		mContentLayout.setPadding(mContentLayout.getPaddingLeft(), height
				- headHeight, mContentLayout.getPaddingRight(),
				mContentLayout.getPaddingBottom());// 设置padding是为了下拉时,head尾随着下拉。更好看
	}

	public int getVisitHeight() {
		return mContentLayout.getHeight();
	}

	public void show() {
		mContentLayout.setVisibility(View.VISIBLE);
	}

	public void hide() {
		mContentLayout.setVisibility(View.INVISIBLE);
	}

	public int getHeadHeight() {
		return headHeight;
	}

	public void setHeadHeight(int headHeight) {
		this.headHeight = headHeight;
	}

}

listview

package com.example.test;

import android.content.Context;
import android.view.MotionEvent;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;

public class XListView extends ListView {
	private Context context;
	// 滑动时长
	private final static int SCROLL_DURATION = 400;
	// 滑动比例
	private final static float OFFSET_RADIO = 2f;
	// 记录按下点的y坐标
	private float lastY;
	// 用来回滚
	private Scroller scroller;
	private IXListViewListener mListViewListener;
	private XListViewHeader headerView;
	private RelativeLayout headerViewContent;
	// header的高度
	private int headerHeight;
	// 是否可以刷新
	private boolean enableRefresh = true;
	// 是否正在刷新
	private boolean isRefreashing = false;
	// 记录当前手势是向上还是向下
	private int TOUCH_UP = 0, TOUCH_DOWN = 1;
	private int mTouch;

	public XListView(Context context) {
		super(context);
		this.context = context;
		init();
	}

	private void init() {
		scroller = new Scroller(context, new DecelerateInterpolator());
		headerView = new XListViewHeader(context);
		headerViewContent = (RelativeLayout) headerView
				.findViewById(R.id.xlistview_header_content);
		// 获得head的高度
		headerView.getViewTreeObserver().addOnGlobalLayoutListener(
				new OnGlobalLayoutListener() {
					@SuppressWarnings("deprecation")
					@Override
					public void onGlobalLayout() {
						headerHeight = headerViewContent.getHeight();
						headerView.setHeadHeight(headerHeight);
						getViewTreeObserver()
								.removeGlobalOnLayoutListener(this);
					}
				});
		addHeaderView(headerView);
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			lastY = ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			float t = ev.getRawY() - lastY;
			lastY = ev.getRawY();
			if (t > 0) {
				mTouch = TOUCH_DOWN;
			} else {
				mTouch = TOUCH_UP;
			}
			// 当前是第一个item,且手势是向下,就显示下拉条,更新高度
			if (getFirstVisiblePosition() == 0
					&& (headerView.getVisitHeight() > 0 || t > 0)) {
				updateHeaderViewHeight(t / OFFSET_RADIO);
			}
			if (!isRefreashing && mTouch == TOUCH_UP
					&& headerView.getVisitHeight() > 0) {
				return true;// 当下拉高度达到header高度时候,松开就可以刷新。若此刻向上滑,listview会尾随滑动,return
							// true 代表消费这个事件,listview禁止滚动
			}
			break;
		case MotionEvent.ACTION_UP:
			if (getFirstVisiblePosition() == 0) {
				if (enableRefresh && headerView.getVisitHeight() > headerHeight) {
					isRefreashing = true;
					headerView.setState(headerView.STATE_REFRESHING);
					if (mListViewListener != null) {
						mListViewListener.onRefresh();//刷新事件
					}
				}
			}
			resetHeaderHeight();
			break;
		}
		return super.onTouchEvent(ev);
	}

	public void updateHeaderViewHeight(float f) {
		headerView.setVisitHeight((int) f + headerView.getVisitHeight());
		// 未处于刷新状态,更新箭头
		if (enableRefresh && !isRefreashing) {
			if (headerView.getVisitHeight() > headerHeight) {
				headerView.setState(XListViewHeader.STATE_READY);
			}else{
				headerView.setState(XListViewHeader.STATE_NORMAL);
			}
		}
	}

	// 下拉条动态消失
	public void resetHeaderHeight() {
		int height = headerView.getVisitHeight();
		int endheight = 0;
		if (isRefreashing) {
			endheight = headerHeight;
		}
		// y轴方向由 height 到 endheight 。第三个參数是增量,假设不是刷新则高度变为0,假设是,高度变为head原始高度
		scroller.startScroll(0, height, 0, endheight - height, SCROLL_DURATION);
		invalidate();
	}

	public void computeScroll() {
		if (scroller.computeScrollOffset()) {
			// 利用scroller 。设置高度。重复重绘
			headerView.setVisitHeight(scroller.getCurrY());
			postInvalidate();
		}
		super.computeScroll();
	}

	public void stopRefresh() {
		if (isRefreashing == true) {
			isRefreashing = false;
			resetHeaderHeight();
		}
	}

	public void setIxListener(IXListViewListener listener) {
		this.mListViewListener = listener;
	}

	interface IXListViewListener {
		public void onRefresh();// 刷新事件的回调函数
	}
}

mainactivity

package com.example.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ArrayAdapter;

import com.example.test.XListView.IXListViewListener;

public class MainActivity extends Activity {
	private XListView xListView;
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			xListView.stopRefresh();
		}
	};

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		xListView = new XListView(this);
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_expandable_list_item_1);
		xListView.setAdapter(adapter);
		for (int i = 0; i < 10; i++) {
			adapter.add("text" + i);
		}
		setContentView(xListView);
		xListView.setIxListener(new IXListViewListener() {
			public void onRefresh() {
				new Thread() {
					public void run() {
						try {
							Thread.sleep(2000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						handler.sendEmptyMessage(0);
					}
				}.start();
			}
		});
	}
}

下载

csdn博文编辑不能撤销么。写的东西都没了

时间: 2024-11-15 19:12:26

下拉刷新XListView的简单分析的相关文章

IOS UIWebView 下拉刷新功能的简单实现

1.运行效果图 2.swift 代码的实现 import UIKit class RefreshWebViewController: UIViewController,UIScrollViewDelegate,UIWebViewDelegate{ @IBOutlet weak var webView: UIWebView! //刷新控件view private var header:UIView! //下拉到50时松开刷新 private let pullHeight:CGFloat=50 //

第一篇、实现上拉和下拉刷新

简介: 在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 功能: 1.下拉刷新(用系统自带的刷新控件实现) /** * 集成下拉刷新 */ -(void)setupRefresh { //1.添加刷新控件 UIRefreshControl *control=[[UIRefreshControl alloc]init]; [control addTarget:self action:@selecto

iOS下拉刷新

在iOS开发中,我们经常要用到下拉刷新来加载新的数据.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 1.在TableView里,一打开软件,我们就调用下拉刷新事件. - (void)viewDidLoad { [super viewDidLoad]; // 集成刷新控件 [self setupRefresh]; } /** * 集成下拉刷新 */ -(void)setupRefresh { //1.添加刷新控件 UIRefreshControl *control=[[UIR

iOS开发项目篇—30下拉刷新

iOS开发项目篇—30下拉刷新 一.网络监控 当应用所处的网络环境不好的时候,获取不到相应的网络数据,考虑到用户对应用的使用体验,有必要对网络的状况进行监听. 在程序启动完的时候,监控网络 YYAppDelegate.m文件代码: 1 // 2 // YYAppDelegate.m 3 // 4 5 #import "YYAppDelegate.h" 6 #import "YYOAuthViewController.h" 7 #import "YYCont

iOS下拉刷新和上拉刷新

在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 上拉刷新 1.在TableView里,一打开软件,我们就调用下拉刷新事件. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - (void)viewDidLoad {     [super viewDidLoad];     // 集成刷新控件     [self set

Android SwipeRefreshLayout下拉刷新控件源码简单分析

咱们在做Android APP开发的时候经常碰到有下拉刷新和上拉加载跟多的需求,这篇文章咱们先说说下来刷新,咱们就以google的原生的下拉刷新控件SwipeRefreshLayout来看看大概的实现过程. SwipeRefreshLayout是google自己推出的下拉刷新控件.使用起来也非常的简单,在满足条件的情况下下拉的时候会显示一个圆形的loading的动画效果,然后回调到上层,上层自己做刷新的一系列的处理,处理结束后调用SwipeRefreshLayout的setRefreshing(

ListView的下拉刷新和上拉加载--XListView

分析XListView的源码,是因为其他开源控件代码都太多了(主要很多细微的地方都不懂,只能理解个大概),这个控件只是在原生ListView的基础上添加Header和Footer,代码很简单,可以随便折腾. Github地址:Github上搜索这个就行-----XListView-Android 看Header代码: /** * @file XListViewHeader.java * @create Apr 18, 2012 5:22:27 PM * @author Maxwin * @des

Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

前言: 因为公司人员变动原因,导致了博主四个月没有动安卓,一直在做IOS开发,如今接近年前,终于可以花一定的时间放在安卓上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:      因为此效果实现的步骤较多,所以今天博主要实现以上效果的第一步——打造一个通用的下拉刷新控件,具体效果如下: GIF图片比较大,还希望读者能耐心等待一下下从效果图中可以看出,我们的下拉刷新的滑动还是很流畅的,可能大多数开发者用的是XListview或者PullTo

android下拉刷新上拉加载简单的实现方法;

项目中需要用到android下拉刷新和上拉加载:所以学习了一个很简单的很方便的一个例子:自己也写过下拉刷新和上拉加载的功能:但是如果每个界面都要实现这个功能的话非常的麻烦:所以学习了别人很好的demo:然后分享一下: 我的学习步骤: 在网上下载demo:然后把必要的导入到项目中: 在此附上下载源码网址:http://download.csdn.net/detail/android_drawing/8596553 所有的源代码如下: XListViewFooter类 /** * @file XFo