效果图
由于整个布局带有两个Header,所以这里自己写了一个类来继承ListView去实现它的方法,并根据ontouch里面滑动的参数来判断什么时候显示
一:下拉刷新
1.由于我的轮播的那个图,已经是头部文件了,所以我的下拉刷新是在自定义的ListView中添加的,
private void initHeaderView(){
mMMHeaderView = View.inflate(getContext(), R.layout.pull_to_refresh,null);
/*这里的mMMHeaderView就是下拉刷新,ListView先加载这个布局,之后在引用ListView的地方加载第二个Header
*/
this.addHeaderView(mMMHeaderView);
//找到各个布局
mIv_listheader =mMMHeaderView.findViewById(R.id.iv_listheader);
mPb_listheader =mMMHeaderView.findViewById(R.id.pb_listheader);
mTv_listheader_title =mMMHeaderView.findViewById(R.id.tv_listheader_title);
tv_listheader_data =mMMHeaderView.findViewById(R.id.tv_listheader_data);
// 在生成布局时得到布局的宽高
mMMHeaderView.measure(0,0);
mMHeaderViewHeight =mMMHeaderView.getMeasuredHeight();
mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
initAnimation();
}
2.根据滑动来判断当前的刷新的状态,来设置头布局的显示与隐藏,重写onTouchEvent方法
private int mStartY = -1;
//下拉刷新
public static final int STATE_PULL_TO_REFRESH =1;
//释放刷新
public static final int STATE_RELEASE_TO_REFRESH =2;
//正在刷新
public static final int STATE_REFRESHING =3;
//当前刷新的栏的状态
public int currentstate =STATE_PULL_TO_REFRESH;
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
//得到屏幕滑动的初始y值
mStartY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//如果当前处于刷新状态,则直接break,不进行下列操作
if(currentstate ==STATE_REFRESHING){
break;
}
//防止ListView没有捕获到滑动开始时的点击事件
if(mStartY == -1){
mStartY = (int)ev.getY();
}
int endy = (int)ev.getY();
//dy 为移动的距离,如果向下滑动,则dy大于0,当前的头布局已经设置padding为 负的布局高度,再用正的
//减去布局高度,则得到的隐藏值将会缩小
int dy = endy -mStartY;
Log.i("TAG","dy:"+dy+" endy:"+endy);
int firstVisiblePosition = getFirstVisiblePosition();
//2.让刷新布局跟随手指移动 ,当在顶部的时候,向下拉这用滑动的距离减去刷新布局的高度,则将刷新布更改位置
if(dy >0 && firstVisiblePosition ==0){
int padding = dy -mMHeaderViewHeight;
mMMHeaderView.setPadding(0,padding,0,0);
if(padding >0 &¤tstate !=STATE_RELEASE_TO_REFRESH){
currentstate =STATE_RELEASE_TO_REFRESH;
refreshState();
}else if(padding <0 &¤tstate !=STATE_PULL_TO_REFRESH){
currentstate =STATE_PULL_TO_REFRESH;
refreshState();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
mStartY = -1;
// 当松开布局时,判断当前状态,将布局隐藏或者显示
if(currentstate ==STATE_RELEASE_TO_REFRESH){
currentstate =STATE_REFRESHING;
refreshState();
mMMHeaderView.setPadding(0,0,0,0);
}else if(currentstate ==STATE_PULL_TO_REFRESH){
mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
// 这个方法根据滑动的状态去更新布局的信息
private void refreshState() {
switch (currentstate){
case STATE_PULL_TO_REFRESH:
mTv_listheader_title.setText("下拉刷新");
mPb_listheader.setVisibility(View.INVISIBLE);
mIv_listheader.setVisibility(View.VISIBLE);
mIv_listheader.startAnimation(mDownanimation);
break;
case STATE_REFRESHING:
mIv_listheader.clearAnimation();
mTv_listheader_title.setText("正在刷新...");
mPb_listheader.setVisibility(View.VISIBLE);
mIv_listheader.setVisibility(View.INVISIBLE);
//调用刷新的方法
mListener.onrefresh();
break;
case STATE_RELEASE_TO_REFRESH:
mTv_listheader_title.setText("释放刷新");
mPb_listheader.setVisibility(View.INVISIBLE);
mIv_listheader.setVisibility(View.VISIBLE);
mIv_listheader.startAnimation(mUpanimation);
break;
default:
break;
}
}
3.定义接口和方法让外部回调
// 3.1 这个方法是刷新完成后调用,隐藏布局
public void setRefreshComplement() {
mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
currentstate =STATE_PULL_TO_REFRESH;
mTv_listheader_title.setText("下拉刷新");
mPb_listheader.setVisibility(View.INVISIBLE);
mIv_listheader.setVisibility(View.VISIBLE);
mIv_listheader.startAnimation(mDownanimation);
}
// 定义解控供外部调用
public interface OnRefreshListener{
void onrefresh();
}
private OnRefreshListenermListener mListener;
//外部布局设置刷新的方法
public void setOnRefreshListener(OnRefreshListener listener){
this.mListener = listener;
}
4.在外部调用设置接口的方法,调用刷新的方法
mlv_news.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {
@Override
public void onrefresh() {
getDataFromServer();
}
});
//当请求数据成功,并解析出来后调用刷新完成的方法,隐藏布局
x.http().get(params, new Callback.CommonCallback() {
@Override
public void onSuccess(String result) {
processData(result);
// 保存缓存
PrefUtils.setString(mactivity,mUri,result);
mlv_news.setRefreshComplement();
}
}
二:上拉加载更多
2.1:定义一个上拉加载的布局,我的是pull_to_refresh_footer.xml
<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
android:id="@+id/pb_listheader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/custom_progress"
android:visibility="visible"
/>
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载更多"
/>
</LinearLayout>
2.2:为footerview初始化,找到布局,并将ListView加入FooterView,这里让继承ListView的布局实现OnScrollListener接口
private void initFooterView(){
mMFooterView = View.inflate(getContext(),R.layout.pull_to_refresh_footer,null);
this.addFooterView(mMFooterView);
mMFooterView.measure(0,0);
mFooterViewHeight =mMFooterView.getMeasuredHeight();
mMFooterView.setPadding(0,-mMHeaderViewHeight,0,0);
this.setOnScrollListener(this);
}
2.3在自己定义的接口中定义加载更多的方法,其中loadmore(),就是供外部加载更多的方法/***
@param view
* @param scrollState
* 在滑动的监听中更新加载更多的布局的位置,其中 isLoadMore是为了防止用户在加载更多的时候再次滑动,造成数据得重复
* 加载,其中setSelection(getCount() -1)是让加载更多时直接全部拖出,不然用户有时滑至底部不知道下滑加载更多,调用
* 让监听执行loadmore方法
*
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState ==SCROLL_STATE_IDLE){
int lastVisiblePosition = getLastVisiblePosition();
if(lastVisiblePosition == getCount() -1 && !isLoadMore){
isLoadMore =true;
mMFooterView.setPadding(0,0,0,0);
//将listview的位置设置到最后一个item布局
setSelection(getCount() -1);
mListener.loadmore();
}
}
}
2.4:在外部调用执行具体的loadmore()方法
//获取到加载更多的url,如果存在下一个页面的Url则加载,否则赋值为null
String loadmore = newTabBean.data.more;
if(!TextUtils.isEmpty(loadmore)){
mLoadmoreurl = ConstantValues.SERVER_URL+loadmore;
}else {
mLoadmoreurl =null;
}
通过判断路径是否为空来调用getDataMoreFromServer()方法,去服务器请求更多的数据
@Override
public void loadmore() {
if(mLoadmoreurl !=null) {
getDataMoreFromServer();
}else{
Toast.makeText(mactivity,"没有更多数据了",Toast.LENGTH_SHORT).show();
mlv_news.setRefreshComplement(false);
}
}
调用解析数据方法是,传入一个
private void getDataMoreFromServer(){
RequestParams params =new RequestParams(mLoadmoreurl);
x.http().get(params, new Callback.CommonCallback() {
@Override
public void onSuccess(String result) {
processData(result,true);
mlv_news.setRefreshComplement(false);
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(mactivity,"获取数据失败",Toast.LENGTH_SHORT).show();
mlv_news.setRefreshComplement(false);
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
}