安卓自定义ListView实现上拉加载、下拉刷新
来源:互联网 发布:俄罗斯的聊天软件 编辑:程序博客网 时间:2024/04/28 06:46
自定义ListView实现上拉加载、下来刷新,暂时未加入侧滑功能,可以设置是否需要加载、刷新以及每次加载的item个数,可以根据设置的加载item个数判断第一次获取数据后是否加载(如果少于设置的个数则不许加载)
xml头部布局<?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:gravity="center"> <RelativeLayout android:id="@+id/my_list_view_header_content" android:layout_width="match_parent" android:layout_height="60dp"> <LinearLayout android:id="@+id/my_list_view_header_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/my_list_view_header_hint_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉刷新" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="上次更新时间:" android:textSize="12sp" /> <TextView android:id="@+id/my_list_view_header_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" /> </LinearLayout> </LinearLayout> <ImageView android:id="@+id/my_list_view_header_arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/my_list_view_header_text" android:layout_centerVertical="true" android:layout_marginLeft="-35dp" android:src="@drawable/my_listview_arrow" /> <ProgressBar android:id="@+id/my_list_view_header_progressbar" android:layout_width="30dp" android:layout_height="30dp" android:layout_alignLeft="@id/my_list_view_header_text" android:layout_centerVertical="true" android:layout_marginLeft="-40dp" android:visibility="gone" /> </RelativeLayout></LinearLayout>
xml底部布局
<?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="75dp" android:clickable="false" android:orientation="vertical"> <LinearLayout android:id="@+id/my_listview_footer_load_layout" android:layout_width="match_parent" android:layout_height="75dp" android:gravity="center" android:orientation="horizontal" android:paddingBottom="10dp" android:paddingTop="10dp"> <ProgressBar android:id="@+id/my_listview_footer_load_progress" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginRight="10dp" /> <TextView android:id="@+id/my_listview_footer_load_text" android:layout_width="wrap_content" android:layout_height="20dp" android:text="正在加载" android:textSize="16sp" /> </LinearLayout></LinearLayout>
java代码
import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;import com.jwwl.carrierapp.R;import java.text.SimpleDateFormat;import java.util.Date;/** * 自定义ListView用于上拉加载、下拉刷新、左滑菜单 */public class MyListView extends ListView implements OnScrollListener { /** * 滑动开始时,手指按下Y的坐标 */ private int downY; /** * 每次加载的Item个数,根据此个数判断第一次获取数据后是否需要加载,默认为0个 */ private int sizeItem = 0; /** * 用于保证每次滑动是一个完整的滑动事件,按下的downY坐标值每次事件中只被记录一次(按下->滑动->松开,为一个完整事件),默认为false * true处于一个事件中 * false未开始事件 */ private boolean isRecored = false; /** * 外部调用设置,是否可以下拉刷新,默认为false * true可以下拉刷新 * false不可以下拉刷新 */ private boolean isRefreshable = false; /** * 外部调用设置,是否可以上拉加载数据,默认为false * true 可以上拉加载 * false 不可以上拉加载 */ private boolean isLoadable = false; /** * 是否处于可下拉刷新状态,当Item为0时为true,默认为false * true可以下拉刷新状态 * false不可以下拉刷新状态 */ private boolean isRefresh = false; /** * 是否处于可上拉加载状态,当前屏幕最后一个Item下标为总的Item下标时为true,默认为false * true可以上拉加载状态 * false不可以上拉加载状态 */ private boolean isLoad = false; /** * 用于判断是否是从下拉要刷新状态滑动到下拉要返回状态,默认为false * true 是 * false 不是 */ private boolean isBack = false; /** * 是否处于上拉加载中,默认为false * true上拉加载中 * false不在上拉加载中 */ private boolean isLoading = false; /** * 下拉刷新头部布局,各个控件 */ private View headerView; // 头部布局 private TextView headerTipsTv; //下来刷新提示 private TextView headerTimeTv; //下来刷新时间 private ImageView headerArrowIv; //下来刷新箭头 private ProgressBar headerProgressBar; //下来刷新进度条 /** * 底部布局 */ private View footerView; /** * 加载监听接口 */ private OnLoaderListener onLoaderListener; /** * 刷新监听接口 */ private OnRefreshListener refreshListener; /** * 下拉刷新头部布局的高度 */ private int headerContentHeight; /** * 下来刷新箭头动画 */ private RotateAnimation rotateAnimation; //正向旋转, private RotateAnimation reverseRotateAnimation; //反向旋转, /** * 下拉刷新状态值:下拉状态,松开不刷新 */ private final static int PULL_TO_BACK = 0; /** * 下拉刷新状态值:下拉状态,松开会刷新 */ private final static int PULL_TO_REFRESHING = 1; /** * 下拉刷新状态值:刷新中 */ private final static int REFRESHING = 2; /** * 上拉刷新状态值:完成 */ private final static int DONE = 3; /** * 上拉刷新状态,默认为完成状态 */ private int state = DONE; /** * 滑动的偏移比例,当滑动距离除以此比例大于等于布局高度时,则达到可以刷新加载状态 */ private final static int RATIO = 3; //构造方法 public MyListView(Context context) { super(context); initView(context); } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public MyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } /** * 初始化View */ private void initView(Context context) { LayoutInflater inflater = LayoutInflater.from(context); setCacheColorHint(context.getResources().getColor(R.color.app_white)); //ListView滑动时背景/* * 下拉刷新: */ //获取布局 headerView = inflater.inflate(R.layout.my_listview_header, null); //获取头部控件 headerView.setClickable(false); //设置布局不可点击 headerTipsTv = (TextView) headerView.findViewById(R.id.my_list_view_header_hint_textview); //下来刷新标题 headerTimeTv = (TextView) headerView.findViewById(R.id.my_list_view_header_time); //下拉刷新时间 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); headerTimeTv.setText(sdf.format(new Date())); headerArrowIv = (ImageView) headerView.findViewById(R.id.my_list_view_header_arrow); //下拉刷新箭头 headerProgressBar = (ProgressBar) headerView.findViewById(R.id.my_list_view_header_progressbar); //下拉刷新进度条 //获取下拉刷新控件高度 headerView.measure(0, 0); headerContentHeight = headerView.getMeasuredHeight(); //设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏 headerView.setPadding(0, -headerContentHeight, 0, 0); //重绘一下 headerView.invalidate(); //将下拉刷新的布局加入ListView的顶部 addHeaderView(headerView, null, false); //设置正向旋转动画事件 rotateAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setInterpolator(new LinearInterpolator()); rotateAnimation.setDuration(200); rotateAnimation.setFillAfter(true); //设置反向旋转动画事件 reverseRotateAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); reverseRotateAnimation.setInterpolator(new LinearInterpolator()); reverseRotateAnimation.setDuration(200); reverseRotateAnimation.setFillAfter(true);/* * 上拉加载 */ //获取布局 footerView = inflater.inflate(R.layout.my_listview_footer, null); //获取底部加载控件 footerView.findViewById(R.id.my_listview_footer_load_layout).setVisibility(GONE); footerView.setClickable(false);//设置布局不可点击 // 将上拉加载的布局加入ListView的底部 addFooterView(footerView); /* 滑动监听事件 */ setOnScrollListener(this); } /** * 设置是否可以下拉刷新 * * @param enable true-可以下拉刷新,false-不可以下拉刷新 */ public void setRefreshEnable(boolean enable) { isRefreshable = enable; } /** * 设置是否可以上拉加载 * * @param enable true-可以上拉加载,false-不可以上拉加载 */ public void setLoadEnable(boolean enable) { isLoadable = enable; } /** * 设置每次加载的Item个数 */ public void setSizeItem(int sizeItem) { this.sizeItem = sizeItem; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //按下 downY = (int) ev.getY(); //记录按下时的y坐标 /* * 如果可以刷新或加载,并且未开始一个事件,则开始一个滑动事件 */ if (isRefreshable && !isRecored && (isRefresh || isLoad)) { isRecored = true; } break; case MotionEvent.ACTION_MOVE: //滑动 int moveY = (int) ev.getY(); /* * 如果可以刷新或加载,并且未开始一个事件,则开始一个滑动事件 */ if (isRefreshable && !isRecored && (isRefresh || isLoad)) { isRecored = true; downY = moveY; } /** * 根据是否处于滑动事件和刷新加载状态及是否处于可刷新判断刷新 */ if (isRecored && state != REFRESHING && isRefresh) { /* 如果在完成状态滑动 当下滑时,状态设置为下拉状态,并更新header的信息 */ if (state == DONE) { //1、如果滑动值为正,则是往下滑,状态设置为下拉要返回状态 if (moveY - downY > 0) { state = PULL_TO_BACK; changeViewByState();//更新hander信息 } } /* 如果在下拉要返回状态滑动 */ if (state == PULL_TO_BACK) { setSelection(0); //1、如果滑动值为负,则是上滑,当滑动超出原按下位置时设为完成状态 if ((moveY - downY) <= 0) { state = DONE; changeViewByState();//更新hander信息 } //2、如果滑动值为正,则是下滑,当滑动达到可以刷新时设为下拉可刷新状态 if ((moveY - downY) > 0 && (moveY - downY) / RATIO >= headerContentHeight) { state = PULL_TO_REFRESHING; changeViewByState();//更新hander信息 } //3、设置header的padding值 headerView.setPadding(0, (moveY - downY) / RATIO - headerContentHeight, 0, 0); } /* 如果在下拉可刷新状态滑动 */ if (state == PULL_TO_REFRESHING) { setSelection(0); //1、如果滑动值为正,则是下滑,当滑动达回到下拉要返回状态时,设置为下拉要返回状态 if ((moveY - downY) > 0 && (moveY - downY) / RATIO < headerContentHeight) { isBack = true; state = PULL_TO_BACK; changeViewByState();//更新hander信息 } //2、设置header的padding值 headerView.setPadding(0, (moveY - downY) / RATIO - headerContentHeight, 0, 0); } } /** * 根据是否处于滑动事件和刷新加载状态及是否处于可刷新判断加载 */ if (isRecored && !isLoading && isLoad) { //1、如果滑动值为负,则是往上滑,状态设置上拉加载状态 if (moveY - downY < 0 && onLoaderListener != null) { isLoading = true; Log.i("TAG", "数据加载load"); footerView.findViewById(R.id.my_listview_footer_load_layout).setVisibility(VISIBLE); onLoaderListener.onLoad(); } } break; case MotionEvent.ACTION_UP: //松开 isBack = false; isRecored = false; //按下、滑动、松开整个事件结束 /** * 根据松开时的刷新状态判断是否刷新 * 只有不处于刷新中才判断 */ if (state != REFRESHING) { //下拉到要返回状态松开 if (state == PULL_TO_BACK) { state = DONE; //状态设为完成 changeViewByState();//更新hander信息 } //下拉到要刷新状态松开 if (state == PULL_TO_REFRESHING) { //回调刷新方法 if (refreshListener != null) { state = REFRESHING; //状态设为刷新 changeViewByState();//更新hander信息 refreshListener.onRefresh(); } else { state = DONE; //状态设为完成 changeViewByState();//更新hander信息 } } } break; } return super.onTouchEvent(ev); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { /* * 滑动时会一直回调该方法,直到停止滑动。单击时回调一次该方法。 * firstVisibleItem表示当前屏幕显示的第一个listItem在整个listView里的位置(下标从0开始); * visibleItemCount表示当前屏幕可见的listItem(部分显示的listItem也算)总数; * totalItemCount表示listView里listItem总数。 * <p/> * 当滑动到列表首个Item时,判断是否可以下拉刷新 * 当滑动到列表结尾之前,判断是否加载数据 */ //根据当前首个item下标是否是0并且是否可以下拉刷新,判断是否能够下拉刷新 if (isRefreshable && firstVisibleItem == 0) { isRefresh = true; } else { isRefresh = false; } //当前屏幕首个item的下标与当前屏幕item个数之和同item总个数比较,判断是否加载数据 if (isLoadable && totalItemCount == (firstVisibleItem + visibleItemCount) && sizeItem <= totalItemCount && totalItemCount != 0) { isLoad = true; } else { isLoad = false; } } /** * 当刷新状态改变时候,调用该方法,根据当前状态更新header界面信息 */ private void changeViewByState() { switch (state) { case PULL_TO_BACK: //松开不刷新 headerProgressBar.setVisibility(View.GONE); //隐藏进度条 headerTipsTv.setVisibility(View.VISIBLE); //显示刷新提示 headerTipsTv.setText("下拉刷新"); //设置刷新提示内容 headerTimeTv.setVisibility(View.VISIBLE); //显示上次刷新时间 headerArrowIv.setVisibility(View.VISIBLE); //显示刷新箭头 headerArrowIv.clearAnimation(); //清除刷新箭头动画 //根据是否是从下拉要刷新状态滑动到下拉要返回状态,来判断是否调用反向旋转的箭头动画 if (isBack) { isBack = false; headerArrowIv.startAnimation(reverseRotateAnimation);//设置刷新动画为反向旋转动画 } break; case PULL_TO_REFRESHING: //松开要刷新 headerProgressBar.setVisibility(View.GONE);//隐藏进度条 headerTipsTv.setVisibility(View.VISIBLE);//显示刷新提示 headerTipsTv.setText("松开刷新");//设置刷新提示内容 headerTimeTv.setVisibility(View.VISIBLE);//显示上次刷新时间 headerArrowIv.setVisibility(View.VISIBLE);//显示刷新箭头 headerArrowIv.clearAnimation(); //清除刷新箭头动画 headerArrowIv.startAnimation(rotateAnimation);//设置刷新动画为正向旋转动画 break; case REFRESHING: //刷新中 headerView.setPadding(0, 0, 0, 0); //设置刷新头布局padding headerProgressBar.setVisibility(View.VISIBLE);//显示进度条 headerTimeTv.setVisibility(View.VISIBLE);//显示刷新提示 headerTipsTv.setText("正在刷新");//设置刷新提示内容 headerArrowIv.clearAnimation();//清除刷新箭头动画 headerArrowIv.setVisibility(View.GONE);//隐藏刷新箭头 break; case DONE: //刷新完成 headerView.setPadding(0, -1 * headerContentHeight, 0, 0);//设置刷新头部布局padding headerProgressBar.setVisibility(View.GONE);//隐藏进度条 headerTimeTv.setVisibility(View.VISIBLE);//显示刷新提示 headerTipsTv.setText("下拉刷新");//设置刷新提示内容 headerArrowIv.clearAnimation();//清除刷新箭头动画 headerArrowIv.setVisibility(View.VISIBLE);//显示刷新箭头 break; } } //刷新监听方法,用于刷新接口实现 public void setRefreshListener(OnRefreshListener refreshListener) { this.refreshListener = refreshListener; } //刷新回调接口,用于回调刷新方法 public interface OnRefreshListener { void onRefresh(); } //刷新完成调用方法 public void refreshComplete() { //刷新状态设为完成状态 state = DONE; //设置刷新时间 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); headerTimeTv.setText(sdf.format(new Date())); //更新header信息 changeViewByState(); } //加载监听方法,用于加载接口的实现 public void setLoaderListener(OnLoaderListener onLoaderListener) { this.onLoaderListener = onLoaderListener; } // 加载回调接口,用于回调加载方法 public interface OnLoaderListener { void onLoad(); } //加载完毕调用方法 public void loadComplete() { isLoading = false; footerView.findViewById(R.id.my_listview_footer_load_layout).setVisibility(GONE); }}
0 0
- 安卓自定义ListView实现上拉加载、下拉刷新
- 安卓:ListView上拉加载,下拉刷新简单实现
- Android 自定义ListView 实现下拉刷新 上拉加载功能
- 自定义ListView实现下拉刷新,上拉加载更多
- 自定义ListView 实现上拉刷新 下拉加载数据
- 自定义listview实现上拉加载下拉刷新
- SwipeRefreshLayout+ListView实现下拉刷新自定义上拉加载
- 自定义ListView,实现下拉刷新,上拉加载
- 自定义布局实现listview上拉加载下拉刷新
- 自定义控件实现ListView下拉刷新和上拉加载
- 自定义listview布局实现上拉加载,下拉刷新
- 自定义ListView实现下拉刷新上拉加载功能
- 使用安卓自带刷新控件实现ListView的上拉加载和下拉刷新
- 自定义ListView下拉刷新上拉加载
- 自定义ListView----->下拉刷新,上拉加载
- 自定义ListView下拉刷新,上拉加载
- 安卓下拉刷新上拉加载更多的listview
- 谈谈安卓中的下拉刷新,上拉加载ListView的实现
- 从小猴摘桃子问题引发的斐波那契数列与递归的思考
- C语言宏与单井号(#)和双井号(##)
- Android调用拨号界面、拨打电话功能
- STL容器的size()函数的一个容易忽略的点
- android studio 模拟器启动不了
- 安卓自定义ListView实现上拉加载、下拉刷新
- C语言中的static 详细分析
- 弹性scrollview
- local.properties
- R语言对数据的基本管理
- Linux下Signal信号
- SystemUI中的访客模式整理
- UITabBarController + UINavigationController 框架相关问题(隐藏TabBar)
- Android 银联支付Demo