为自己记------android中listview下拉刷新和下拉加载的原理及简单实现
来源:互联网 发布:莆田电视台 网络直播 编辑:程序博客网 时间:2024/05/28 03:01
自定义listview,实现下拉刷新功能和上拉加载功能
1.下拉刷新
实现原理:通过onTouchEvent判断手势,来改变listview的header。
header的状态共4种,自己定义为:none, normal, willrefresh, refreshing ,header在四种状态切换时不仅改变内部组件,同时改变自身的大小。
footer类似
实现:
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.windlu.anywhere.R;
/**
* 自定义的listview,实现上拉刷新和下拉加载
* @author lufeng
*
*/
public class PushAndDownListview extends ListView implements OnScrollListener{
private StateBar headView;//头部view
private StateBar footerView;//脚部view
private int headerContentHeight;//头部view的高度
private int footerContentHeight;//脚部view的高度
private static final int Refresh = 0;//刷新
private static final int Load = 1;//加载
private int Operating=-1;//操作
private PushAndDownListviewRefreshOrLoad mPushAndDownListviewRefreshOrLoad;//加载或刷新的回调接口
public PushAndDownListview(Context context) {
this(context,null);
}
public PushAndDownListview(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
//头部
headView = new StateBar(context);
headView.setStatusStrings(getResources().getString(R.string.pull_to_refresh),
getResources().getString(R.string.release_to_refresh),
getResources().getString(R.string.refreshing));
//测量view的高度
measureView(headView);
headerContentHeight=headView.getMeasuredHeight();
//设置view的toppadding值
headtopPadding(-headerContentHeight);
//添加view
addHeaderView(headView);
//脚部
footerView = new StateBar(context);
footerView.setStatusStrings(getResources().getString(R.string.pull_up_load),
getResources().getString(R.string.release_to_load),
getResources().getString(R.string.loading));
measureView(footerView);
footerContentHeight = footerView.getMeasuredHeight();
footerTopPadding(-footerContentHeight);
addFooterView(footerView);
}
float startY;
boolean isRecordedStartY;//是否已经记录StartY
int firstVisibleItemPosition ;
int LastVisibleItemPosition;
int totalItemCounts;
private boolean isRefreshing;
//主要在该方法中实现下拉刷新效果和上拉加载效果
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts) && Operating == -1&&!isRefreshing){
startY = ev.getY();
isRecordedStartY=true;
return true;
}
break;
case MotionEvent.ACTION_UP:
isRecordedStartY=false;
if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts) && Operating != -1&&!isRefreshing){
if(Operating == Refresh){
if(headView.getStateType()==StateType.willrefresh){
headView.setRefreshStatus(StateType.refreshing);
headtopPadding(0);
doRefreshWork();
}else if(headView.getStateType()==StateType.refreshing){
}else{
RefreshWorkComplete();
// Operating=-1;
// headView.setRefreshStatus(StateType.none);
// headtopPadding(-headerContentHeight);
}
}else if(Operating == Load){
if(footerView.getStateType()==StateType.willrefresh){
footerView.setRefreshStatus(StateType.refreshing);
footerTopPadding(0);
doLoadWork();
}else if(footerView.getStateType()==StateType.refreshing){
}else{
LoadWorkComplete();
// Operating=-1;
// footerView.setRefreshStatus(StateType.none);
// footerTopPadding(-footerContentHeight);
}
}
}
break;
case MotionEvent.ACTION_MOVE:
if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts)&&!isRefreshing){
whenMove(ev);
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
private void doRefreshWork() {
isRefreshing = true;
if(mPushAndDownListviewRefreshOrLoad!=null){
mPushAndDownListviewRefreshOrLoad.Refresh();
}else{
new Handler().postDelayed(new Runnable() {
public void run() {
RefreshWorkComplete();
}
}, 3000);
}
}
private void doLoadWork() {
isRefreshing = true;
if(mPushAndDownListviewRefreshOrLoad!=null){
mPushAndDownListviewRefreshOrLoad.Load();
}else{
new Handler().postDelayed(new Runnable() {
public void run() {
LoadWorkComplete();
}
}, 3000);
}
}
//设置监听
public void setPushAndDownListviewRefreshOrLoadListener(PushAndDownListviewRefreshOrLoad listener){
this.mPushAndDownListviewRefreshOrLoad = listener;
}
//刷新完成后调用
public void RefreshWorkComplete(){
isRefreshing = false;
Operating=-1;
headView.setRefreshStatus(StateType.none);
headtopPadding(-headerContentHeight);
}
//加载完成后调用
public void LoadWorkComplete(){
isRefreshing = false;
Operating = -1;
footerView.setRefreshStatus(StateType.none);
footerTopPadding(-footerContentHeight);
}
private void whenMove(MotionEvent ev){
if(!isRecordedStartY || headView.getStateType()==StateType.refreshing || footerView.getStateType()==StateType.refreshing){
return;
}
float stempY = ev.getY();
int distanceY = (int)(stempY - startY);
if(distanceY > 0 && firstVisibleItemPosition == 0){
//执行刷新状态
doRefresh(distanceY);
}else if(distanceY < 0 && LastVisibleItemPosition==totalItemCounts){
//执行加载状态
doLoad(distanceY);
}
}
private void doRefresh(int distanceY){
Operating = Refresh;
if(distanceY-headerContentHeight < 0){
headView.setRefreshStatus(StateType.normal);
}else if(distanceY-headerContentHeight >= 0){
headView.setRefreshStatus(StateType.willrefresh);
}
headtopPadding(distanceY-headerContentHeight);
}
private void doLoad(int distanceY){
Operating = Load;
if(-(distanceY+footerContentHeight) < 0){
footerView.setRefreshStatus(StateType.normal);
}else if(-(distanceY+footerContentHeight) >= 0){
footerView.setRefreshStatus(StateType.willrefresh);
}
footerTopPadding(-(distanceY+footerContentHeight));
}
/**
* 测量view的方法
* @param view必须使用线性布局
*/
private void measureView(View clild) {
ViewGroup.LayoutParams p = clild.getLayoutParams();//获取layoutparams
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);//宽
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
}
clild.measure(childWidthSpec, childHeightSpec);//measure(0,0)必须使用线性布局,否则报空指针异常,因为线性布局重写了该方法,其他没有从写
}
/**
* 为headview从新设置padding
* @param topPadding
*/
private void headtopPadding(int topPadding) {
headView.setPadding(headView.getPaddingLeft(), topPadding,headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate();
}
private void footerTopPadding(int topPadding){
footerView.setPadding(footerView.getPaddingLeft(), topPadding,footerView.getPaddingRight(), footerView.getPaddingBottom());
footerView.invalidate();
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
this.firstVisibleItemPosition = firstVisibleItem;
this.LastVisibleItemPosition = firstVisibleItem+visibleItemCount;
this.totalItemCounts=totalItemCount;
}
//状态
enum StateType{
none, normal, willrefresh, refreshing
}
//自定义的状态显示view,用于添加到listview的头部和脚部
class StateBar extends LinearLayout{
//状态
StateType mStateType = StateType.none;
//显示的文字
private String normalString;
private String willrefreshString;
private String refreshingString;
public StateBar(Context context) {
super(context);
init(context);
}
public StateBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
//ui控件
ProgressBar progressBar;
TextView tv_state;
TextView tv_updatetime;
private void init(Context context){
LayoutInflater.from(context).inflate(R.layout.view_listviewheadorfoot, this);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
tv_state = (TextView) findViewById(R.id.tv_state);
tv_updatetime = (TextView) findViewById(R.id.tv_updatetime);
//设置状态
setRefreshStatus(mStateType);
}
//设置view的当前状态
public void setRefreshStatus(StateType refreshStatus) {
if (this.mStateType != refreshStatus) {
this.mStateType = refreshStatus;
if(mStateType == StateType.refreshing){
this.progressBar.setVisibility(View.VISIBLE);
}else{
this.progressBar.setVisibility(View.GONE);
}
refreshStatusString();
this.invalidate();
}
}
//刷新状态文字
private void refreshStatusString() {
switch (mStateType) {
case none:
case normal:
tv_state.setText(normalString);
break;
case willrefresh:
tv_state.setText(willrefreshString);
break;
case refreshing:
tv_state.setText(refreshingString);
break;
default:
break;
}
//这里先不做时间设置
tv_updatetime.setText("");
}
public StateType getStateType(){
return mStateType;
}
public void setStatusStrings(String normalString, String willrefreshString, String refreshingString){
this.normalString = normalString;
this.willrefreshString = willrefreshString;
this.refreshingString = refreshingString;
this.refreshStatusString();
}
}
interface PushAndDownListviewRefreshOrLoad{
void Refresh();
void Load();
}
}
有待完善。。。。。。
- 为自己记------android中listview下拉刷新和下拉加载的原理及简单实现
- Android 中 ListView 的 下拉刷新 和 上拉加载 的 重点及学习(一)
- Android 中 ListView 的 下拉刷新 和 上拉加载 的 重点及学习(二)
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- Android中ListView下拉刷新的实现
- 下拉刷新和下拉加载的原理
- Android中PullToRefreshListView的下拉刷新,下拉加载的实现
- Android listview下拉刷新的实现原理及代码--Android事件传递原理的实践
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
- GRE写作必备句型
- iOS开发中的sqlite数据库
- MIUI添加内存调试工具:查看进程中的Bitmap信息
- Xcode调试断点不能停在代码区终极解决方案
- 2012年5月SAT香港真题解析
- 为自己记------android中listview下拉刷新和下拉加载的原理及简单实现
- 手机触摸 事件, 当触摸屏幕时候触发
- UVA 621 Secret Research
- 第一次接触安卓开发
- 使用UiAutomator中swipe(Point[], int)方法绘制解锁图案
- iphone/ipad如何获取本机序列号和设备标示
- Power of Two LeetCode Java
- eclipse错误 The connection to adb is down,
- 物联通公司红外转发器的对码流程