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

效果图

下拉刷新

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

}

});

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容