本文的加载更多是参考http://www.aichengxu.com/view/6197217的代码,在这个基础上修改来达到项目的业务需求,需求符合一下三点:
- 实现下拉加载更多
- 下拉时不能有弹回去的效果,要实现平滑加载
- 加载完毕新的一屏,要在屏幕上显示出来新一屏的一条(仿微信和QQ的会话列表)
看代码如下:
下拉加载更多
public class ConversationListView extends ListView{
// 这个布尔变量是必须使用的,因为不然会访问多次网络,这个可以控制,防止访问多次网络
public boolean mIsLoading = false;
private OnLoadListener mOnLoadListener;
private View mHeaderView;
private boolean isPullable=true;
public ConversationListView(Context context) {
super(context);
init(context);
}
public ConversationListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mHeaderView = View.inflate(context, R.layout.pull_more,null);
addHeaderView(mHeaderView);
hideHeadView();
setOnScrollListener(onScrollListener);
}
private void hideHeadView() {
mIsLoading = false;
mHeaderView.setVisibility(View.GONE);
}
public void setPullable(boolean isPull){
this.isPullable=isPull;
}
private void showHeadView() {
mIsLoading = true;
mHeaderView.setVisibility(View.VISIBLE);
}
/**
* 加载完数据,供外界调用
*/
public void onLoadMoreComplete(String pid) {
mIsLoading = false;
if("1".equals(pid))
this.isPullable=false;
if(isPullable){
hideHeadView();
}else{
removeHeaderView(mHeaderView);
}
}
private AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == 0 && !mIsLoading && mOnLoadListener != null&&isPullable) {
showHeadView();
mOnLoadListener.onLoad();
}
}
};
/**
* 加载更多数据的接口
*/
public interface OnLoadListener {
void onLoad();
}
public void setOnLoadListener(OnLoadListener listener) {
this.mOnLoadListener = listener;
}
}
}
加载更多布局pull_more.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- <ImageView
android:id="@+id/loading_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:visibility="visible" />-->
<ProgressBar
android:id="@+id/loading_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:indeterminateDrawable="@drawable/progress_rotate"
android:indeterminateBehavior="repeat"/>
<!-- <TextView
android:id="@+id/loadstate_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/more"
android:textColor="@color/black"
android:textSize="16sp" />-->
</RelativeLayout>
加载更多progress_rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/loading_a01"
android:fromDegrees="0.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:toDegrees="360.0"/>
activity使用
@Override
public void onLoad() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
//请求网络获取数据逻辑,我这里是用的websokect
if (mMsgs != null && mMsgs.size() > 0) {
String pid = mMsgs.get(0).getPid();
activity.mHelper.up(pid);
} else {
if (mListView != null && mListView.mIsLoading&&mMsgs!=null&&mMsgs.size()!=0) {
mListView.onLoadMoreComplete(mMsgs.get(0).getPid());
}
}
activity.mVideoContainer.setVisibility(View.VISIBLE);
}
}, 1000);
}
从网络中获取数据前记录当前页面数据的位置
int msgSize = mMsgs.size();
从网络中获取数据后刷新页面
mListAdapter.notifyDataSetChanged();
跳转到记录的位置
mListView.setSelection(msgSize);
Q&A
1 这种滑动到顶部自动加载有个弊端,加载完数据不能定位到顶部,否则会不断去请求网络,造成死循环。解决办法第一次加载应该定位到底部;
2 每次加载的数据条数必须多于一屏,否则回去请求两次网络
summary
由于我做的项目有个每次定位到顶部自动播放录音的功能需求,所以没有采用这种加载更多的方式,如果有哪位同仁有更好的实现方式,欢迎联系我,我不胜感激!