android中listview下拉刷新,上拉载入更多示例,Android中Listview下拉刷新和上拉加载更多的多种实现方案...

listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明。

方案一:添加头布局和脚布局

android系统为listview提供了addfootview和addheadview两个API。这样可以直接自定义一个View,以添加视图的形式实现下来刷新和上拉加载。

实现步骤

1、创建一个类继承ListView:class PullToRefreshListView extends ListView;

2、在构造方法中添加HeadView:addHeaderView(headView);

3、获取HeadView的高。测量控件的高可以有两方法getMeasuredHeight和getHeight,getMeasuredHeight()在onMeasure方法执行之后才能获取到;getHeight()  在onLayout方法执行之后才能获取到值;

4、显示和隐藏headView,通过setpadding实现,当向下滑,且第一条可见item是第0条的时候才需要设置HeadView的paddingTop来显示HeadView。

显示:headView.setPadding(0,0,0,0);

隐藏:headView.setPadding(0,-headViewHeight,0,0);

5、下拉刷新三种状态的判断,移动的时候,当paddingTop < 0 的时候,说明HeadView没有完全显示出来,进入下拉刷新状态;移动的时候,当paddingTop >= 0 的时候,   说明HeadView已经完全显示出来了,进入松开以新状态;手指抬起的时候,且当前状态是松开刷新状态的时候,进入正在刷新状态; 当已经是“正在刷新”状态时,   则不允许再做”下拉刷新”和”松开刷新”的操作了,在Move事件中加入判断,如果已经是正在刷新状态了,则不处理下拉的操作了。

6、下拉箭头的转动。下拉刷新是向下,松开刷新时向上。旋转动画通过属性动画实现。隐藏箭头的时候要清除动画:iv_arrow.clearAnimation();  如果不隐藏动画效果,设置View.GONE之后还是看得见的。

7、HeadView显示时,当手指松开时的处理,松开时如果是“正在刷新”状态,则把headVie完全显示;松开时如果是“下拉刷新”状态,则把HeadView完全隐藏

8、增加FooterView:addFooterView(footerView)。当ListView处于空闲状态,并且最后一条可见item是ListView中的最后一条数据时显示footview,   footerView显示出来后,ListView不会自动上滑把FooterView显示出来的,所以需要手动设置:setSelection(getCount() - 1);即选中最后一条。

9、增加回调监听器。当ListView处于刷新状态的时候会调用onRefreshing()方法;当ListView处于加载更多的时候会调用onLoadMore()。加载完成后通知控件加载完成。

具体实现:

import com.itheima.pulltorefreshlistview.R;

import android.content.Context;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

public class PullToRefreshListView extends ListView {

private View headerView;

private float downY;

private int headerViewHeight;

/** 状态:下拉刷新 */

private static final int STATE_PULL_TO_REFRESH = 0;

/** 状态:松开刷新 */

private static final int STATE_RELEASE_REFRESH = 1;

/** 状态:正在刷新 */

private static final int STATE_REFRESHING = 2;

/** 当前状态 */

private int currentState = STATE_PULL_TO_REFRESH; // 默认是下拉刷新状态

private ImageView iv_arrow;

private ProgressBar progress_bar;

private TextView tv_state;

private RotateAnimation upAnim;

private RotateAnimation downAnim;

private OnRefreshingListener mOnRefreshingListener;

private View footerView;

private int footerViewHeight;

/** 正在加载更多 */

private boolean loadingMore;

public PullToRefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

initHeaderView();

initFooterView();

}

private void initHeaderView() {

headerView = View.inflate(getContext(), R.layout.header_view, null);

iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);

progress_bar = (ProgressBar) headerView.findViewById(R.id.progress_bar);

showRefreshingProgressBar(false);

tv_state = (TextView) headerView.findViewById(R.id.tv_state);

headerView.measure(0, 0); // 主动触发测量,mesure内部会调用onMeasure

headerViewHeight = headerView.getMeasuredHeight();

hideHeaderView();

super.addHeaderView(headerView);

upAnim = createRotateAnim(0f, -180f);

downAnim = createRotateAnim(-180f, -360f);

}

private void initFooterView() {

footerView = View.inflate(getContext(), R.layout.footer_view, null);

footerView.measure(0, 0);// 主动触发测量,mesure内部会调用onMeasure

footerViewHeight = footerView.getMeasuredHeight();

hideFooterView();

super.addFooterView(footerView);

super.setOnScrollListener(new OnScrollListener() {

// 当ListView滚动的状态发生改变的时候会调用这个方法

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

if (scrollState == OnScrollListener.SCROLL_STATE_IDLE // ListView处于空闲状态

&& getLastVisiblePosition() == getCount() - 1 // 界面上可见的最后一条item是ListView中最后的一条item

&& loadingMore == false // 如果当前没有去做正在加载更多的事情

) {

loadingMore = true;

showFooterView();

setSelection(getCount() - 1);

if (mOnRefreshingListener != null) {

mOnRefreshingListener.onLoadMore();

}

}

}

// 当ListView滚动的时候会调用这个方法

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

}

});

}

private void hideFooterView() {

int paddingTop = -footerViewHeight;

setFooterViewPaddingTop(paddingTop);

}

private void showFooterView() {

int paddingTop = 0;

setFooterViewPaddingTop(paddingTop);

}

private void setFooterViewPaddingTop(int paddingTop) {

footerView.setPadding(0, paddingTop, 0, 0);

}

/**

* 设置显示进度的圈圈

* @param showProgressBar 如果是true,则显示ProgressBar,否则的话显示箭头

*/

private void showRefreshingProgressBar(boolean showProgressBar) {

progress_bar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);

iv_arrow.setVisibility(!showProgressBar ? View.VISIBLE : View.GONE);

if (showProgressBar) {

iv_arrow.clearAnimation(); // 有动画的View要清除动画才能真正的隐藏

}

}

/**

* 创建旋转动画

* @param fromDegrees 从哪个角度开始转

* @param toDegrees 转到哪个角度

* @return

*/

private RotateAnimation createRotateAnim(float fromDegrees, float toDegrees) {

int pivotXType = RotateAnimation.RELATIVE_TO_SELF; // 旋转点的参照物

int pivotYType = RotateAnimation.RELATIVE_TO_SELF; // 旋转点的参照物

float pivotXValue = 0.5f; // 旋转点x方向的位置

float pivotYValue = 0.5f; // 旋转点y方向的位置

RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);

ra.setDuration(300);

ra.setFillAfter(true); // 让动画停留在结束位置

return ra;

}

/** 隐藏HeaderView */

private void hideHeaderView() {

int paddingTop = -headerViewHeight;

setHeaderViewPaddingTop(paddingTop);

}

/** 显示HeaderView */

private void showHeaderView() {

int paddingTop = 0;

setHeaderViewPaddingTop(paddingTop);

}

/**

* 设置HeaderView的paddingTop

* @param paddingTop

*/

private void setHeaderViewPaddingTop(int paddingTop) {

headerView.setPadding(0, paddingTop, 0, 0);

}

@Override

public boolean onTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

downY = ev.getY();

break;

case MotionEvent.ACTION_MOVE:

if (currentState == STATE_REFRESHING) {

// 如果当前已经是“正在刷新“的状态了,则不用去处理下拉刷新了

return super.onTouchEvent(ev);

}

int fingerMoveDistanceY = (int) (ev.getY() - downY); // 手指移动的距离

// 如果是向下滑动,并且界面上可见的第一条item是ListView的索引为0的item时我们才处理下拉刷新的操作

if (fingerMoveDistanceY > 0 && getFirstVisiblePosition() == 0) {

int paddingTop = -headerViewHeight + fingerMoveDistanceY;

setHeaderViewPaddingTop(paddingTop);

if (paddingTop < 0 && currentState != STATE_PULL_TO_REFRESH) {

// 如果paddingTop小于0,说明HeaderView没有完全显示出来,则进入下拉刷新的状态

currentState = STATE_PULL_TO_REFRESH;

tv_state.setText("下拉刷新");

iv_arrow.startAnimation(downAnim);

showRefreshingProgressBar(false);

// 让箭头转一下

} else if (paddingTop >= 0 && currentState != STATE_RELEASE_REFRESH) {

// 如果paddingTop>=0,说明HeaderView已经完全显示出来,则进入松开刷新的状态

currentState = STATE_RELEASE_REFRESH;

tv_state.setText("松开刷新");

iv_arrow.startAnimation(upAnim);

showRefreshingProgressBar(false);

}

return true;

}

break;

case MotionEvent.ACTION_UP:

if (currentState == STATE_RELEASE_REFRESH) {

// 如果当前状态是松开刷新,并且抬起了手,则进入正在刷新状态

currentState = STATE_REFRESHING;

tv_state.setText("正在刷新");

showRefreshingProgressBar(true);

showHeaderView();

if (mOnRefreshingListener != null) {

mOnRefreshingListener.onRefreshing();

}

} else if (currentState == STATE_PULL_TO_REFRESH) {

// 如果抬起手时是下拉刷新状态,则把HeaderView完成隐藏

hideHeaderView();

}

break;

}

return super.onTouchEvent(ev);

}

public void setOnRefreshingListener(OnRefreshingListener mOnRefreshingListener) {

this.mOnRefreshingListener = mOnRefreshingListener;

}

/** ListView刷新的监听器 */

public interface OnRefreshingListener {

/** 当ListView可以刷新数据的时候会调用这个方法 */

void onRefreshing();

/** 当ListView可以加载更多 的时候会调用这个方法 */

void onLoadMore();

}

/** 联网刷新数据的操作已经完成了 */

public void onRefreshComplete() {

hideHeaderView();

currentState = STATE_PULL_TO_REFRESH;

showRefreshingProgressBar(false);

}

/** 加载更多新数据的操作已经完成了 */

public void onLoadmoreComplete() {

hideFooterView();

loadingMore = false;

}

}

方案二: listview的多种样式显示

设置listview的适配器的时候可以实现两个方法: getViewTypeCount()和getItemViewType(),前者指定条目的种类,后者返回具体的类型,这样可以根据不同的类型设计相关的样式,包括上拉加载更多,和下拉刷新,两者类似,因此这里仅仅给出加载更多的写法。具体实现如下:

1、重写getViewTypeCount()和getItemViewType(),这里包括普通的item条目和加载更多的条目,所以getViewTypeCount()返回值为2;

@Override

public int getViewTypeCount() {

return super.getViewTypeCount() + 1;

}

@Override

public int getItemViewType(int position) {

if (position == getCount() - 1) {

return 0;

} else {

return addViewType(position); //构造一个方法出来,方便子类修改,添加更多的样式

}

}

public int addViewType(int position) {

return 1;

}

2、在getview()中针对不同的类型添加布局:

@Override

public View getView(int position, View convertView, ViewGroup parent) {

BaseHoldle holdle;

if (convertView == null) {

if (getItemViewType(position) == 0) { //type为0 表示应该加载加载更多的视图

holdle = getLoadmoreHoldle();

} else { //否则为普通视图

holdle = getSpecialBaseHoldle(position);

}

} else {

holdle = (BaseHoldle) convertView.getTag();

}

if (getItemViewType(position) == 0) { //加载更多视图,请求网络获取数据

if (havemore()) {

holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_LODING);

triggleLoadMoreData();

} else {

holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_NONE);

}

} else { //普通视图视图,请求网络获取数据

T data = (T) mdata.get(position);

holdle.setDataAndRefreshHoldleView(data);

}

mHoldleView = holdle.mHoldleView;

mHoldleView.setScaleX(0.6f);

mHoldleView.setScaleY(0.6f);

ViewCompat.animate(mHoldleView).scaleX(1).scaleY(1).setDuration(400).setInterpolator(new OvershootInterpolator(4)).start();

return mHoldleView;

}

3、具体的加载更多视图的实现

private BaseHoldle getLoadmoreHoldle() {

if (mLoadmoreHoldle == null) {

mLoadmoreHoldle = new LoadmoreHoldle();

}

return mLoadmoreHoldle;

}

public class LoadmoreHoldle extends BaseHoldle {

@Bind(R.id.item_loadmore_container_loading)

LinearLayout itemloadmorecontainerloading;

@Bind(R.id.item_loadmore_container_retry)

LinearLayout itemloadmorecontainerretry;

@Bind(R.id.item_loadmore_tv_retry)

TextView item_loadmore_tv_retry;

public static final int LOADMORE_LODING = 0;

public static final int LOADMORE_ERROR = 1;

public static final int LOADMORE_NONE = 2;

private int mCurretState;

@Override

public void refreshHoldleView(Object data) {

itemloadmorecontainerloading.setVisibility(View.GONE);

itemloadmorecontainerretry.setVisibility(View.GONE);

mCurretState = (int) data;

switch (mCurretState) {

case LOADMORE_LODING:

itemloadmorecontainerloading.setVisibility(View.VISIBLE);

break;

case LOADMORE_ERROR:

itemloadmorecontainerretry.setVisibility(View.VISIBLE);

break;

case LOADMORE_NONE:

break;

}

}

@Override

public View ininViewHoldle() {

View view = View.inflate(UiUtils.getContext(), R.layout.itemloadmore, null);

ButterKnife.bind(this, view);

return view;

}

}

//holder基类,提取公共的方法

public abstract class BaseHoldle {

public View mHoldleView;

public T mdata;

public BaseHoldle() {

mHoldleView = ininViewHoldle();

mHoldleView.setTag(this);

}

public void setDataAndRefreshHoldleView(T mdata) {

this.mdata = mdata;

refreshHoldleView(mdata);

}

public abstract void refreshHoldleView(T data);

public abstract View ininViewHoldle();

}

方案三: SwipeRefreshLayout实现下来刷新

SwipeRefreshLayout对下不兼容,且只有下拉刷新功能没有上拉加载更多的功能。当时作为Andriod5.0之后的新特性,使用起来方便,可以直接调用系统的API。使用方法也较为简单。具体实现如下:

首先声明控件,设置颜色:

refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);

refreshLayout.setOnRefreshListener(this);

refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,

android.R.color.holo_green_light,android.R.color.holo_orange_light,

android.R.color.holo_red_light);

refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);

refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);

写一个类实现SwipeRefreshLayout.OnRefreshListener,重写onRefresh()方法:

@Override

public void onRefresh() {

refreshLayout.postDelayed(new Runnable() {

@Override

public void run() {

//请求网络,获取数据

refreshLayout.setRefreshing(false);

}

},3000);

}

以上所述是小编给大家介绍的Android中Listview下拉刷新和上拉加载更多的多种实现方案,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值