美文网首页
4.实现自定义ListView的下拉刷新、上拉加载更多

4.实现自定义ListView的下拉刷新、上拉加载更多

作者: 小李同学今天博学了吗 | 来源:发表于2019-10-06 09:48 被阅读0次

效果图

下拉刷新

由于整个布局带有两个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() {

}

});

}

相关文章

网友评论

      本文标题:4.实现自定义ListView的下拉刷新、上拉加载更多

      本文链接:https://www.haomeiwen.com/subject/clphyctx.html