继承SwipeRefreshLayout实现上拉刷新

来源:互联网 发布:php排序算法 编辑:程序博客网 时间:2024/04/29 03:07

这里写图片描述

来自掘金请点击
对了,我就通过这篇文章写出这个上拉刷新的,非常感谢他,但是我还是要吐槽一下,因为他里面有个问题并没有提及怎么解决,addFooterView()在setAdapter()后调用无法显示的问题,后面我自己也有写错一个,出现问题,文末我会提示注意事项,下面请看我如何写。

基本逻辑就是:
触摸滚动时,滚动到最后一条数据时,显示底部加载条,并加载数据,数据加载完成隐藏底部加载条

一开始当然是要获取自定义布局所嵌套的子控件,即嵌套的listView嘛,因为要需要addFooterView()嘛

if (listView==null) {//这里listview是一个全局变量            if (getChildCount()>0) {                for (int i = 0; i < getChildCount(); i++) {                    if (getChildAt(i) instanceof ListView) {                        listView=(ListView) getChildAt(i);                        Log.i(CustomSwipeRefreshLayout, "找到了LIstView");                        initLoadLayout();//初始化加载控件                        setListViewOnScroll();//滚动监听                        break;                    }else {                        Log.i(CustomSwipeRefreshLayout, "不是LIstView的实例");                    }                }                Log.i(CustomSwipeRefreshLayout, "LIstView是否为空:"+(listView==null));            }        }

底部刷新的View,我是自己用java写,这样有个好处,下次要用直接一个类拷走,代码看起来好像有点多,其实很简单

    /**     * 初始化底部加载视图     */    private void initLoadLayout() {        //布局,由于父控件是ListView,所以 LayoutParams 是AbsListView的LayoutParams        AbsListView.LayoutParams listLayoutParams =new AbsListView.LayoutParams(listView.getLayoutParams());         listLayoutParams.width=LayoutParams.MATCH_PARENT;        listLayoutParams.height=100;        loadLayout=new LinearLayout(context);//这里是一个全局变量哦,初始化这个,其他地方就可以用了        loadLayout.setOrientation(LinearLayout.HORIZONTAL);        loadLayout.setLayoutParams(listLayoutParams);        loadLayout.setGravity(Gravity.CENTER_HORIZONTAL);        //dialog        android.view.ViewGroup.LayoutParams layoutParams =new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);        ProgressBar progressBar=new ProgressBar(context,null,android.R.attr.progressBarStyleInverse);        progressBar.setLayoutParams(layoutParams);        //textview        android.view.ViewGroup.LayoutParams layoutParams2 =new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);        TextView textView=new TextView(context);        textView.setText("正在加载.....");        textView.setTextSize(15);        textView.setLayoutParams(layoutParams2);        textView.setGravity(Gravity.CENTER_VERTICAL);        //设置子控件        loadLayout.addView(progressBar);        loadLayout.addView(textView);    }

基本上靠这段代码来判断是否加载的

/**     * 设置滚动监听     */    private void setListViewOnScroll() {        if (listView!=null) {            listView.setOnScrollListener(new OnScrollListener() {                //正在移动                @Override                public void onScrollStateChanged(AbsListView view, int scrollState) {                    Log.i(CustomSwipeRefreshLayout, ""+listView.getLastVisiblePosition());                    if (canLoadMore()) {//判断加载条件是否成立                        loadData();//加载数据                    }else {                        Log.i(CustomSwipeRefreshLayout, "不可以加载新数据");                        }                }                @Override                public void onScroll(AbsListView view, int firstVisibleItem,                        int visibleItemCount, int totalItemCount) {                    // TODO Auto-generated method stub                }            });        }    }

我们需要先把所有条件成立,即什么时候可以加载数据的条件:
1、是否已经正在加载数据了,正在加载,我们不允许再次加载的,因为一般都执行线程,所以执行太多会卡的
2、是否滑动到最后一个item,所以使用listview.getLastVisblePosition()==(listview.getCount()-1)
3、触摸滑动的距离是否符合我们的标准的

获取触摸,用来判断是否符合滑动距离

    //获取startY和endY    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        //按下时        if (ev.getAction()==MotionEvent.ACTION_DOWN) {            startY=ev.getY();        }        //手指离开时        else if(ev.getAction()==MotionEvent.ACTION_UP){            endY=ev.getY();        }        return super.dispatchTouchEvent(ev);    }

这个就是加载条件的代码

/**     * 三个条件可以加载数据     * 1、滑动距离合适的时候     * 2、最后一个条目     * 3、没有正在加载数据     * @return     */    protected boolean canLoadMore() {        //判断没有在加载        boolean condition1=false;        if (!isLoading){            condition1=true;        }        //判断是最后item并且已显示        boolean condition2=false;        if (listView.getLastVisiblePosition()==(listView.getCount()-1)) {            condition2=true;        }        //判断滑动距离是否合适,touchInstance这个设置个差不多就行        boolean condition3=false;        if ((startY-endY)>touchInstance) {            condition3=true;            }        Log.i(CustomSwipeRefreshLayout, "是否正在加载"+condition1+"是否是最后一个并且已经显示出来"+condition2+"触摸距离是否合适"+condition3);                return condition1&&condition2&&condition3;    }

所有条件成立之后我们就可以加载数据了

/**     * 接口回调实现自定义加载数据     */    protected void loadData() {        if (onLoadListener!=null) {            if (loadLayout!=null) {                addLoadLayout();//添加footerView            }            onLoadListener.onLoad();        }    }    //调用这个我们自定义刷新控件        public void setOnLoadListener(OnLoadListener onLoadListener) {        this.onLoadListener = onLoadListener;    }

那什么时候remove加载条呢

//外部调用,即用户重写onLoadListener在onload方法中调用即可    public void setOnload(boolean isLoad){        isLoading=isLoad;        if (!isLoad) {            removeLoadLayout();        }    }

以下使用方法
XML写法

<com.tc.customswiperefreshview.CustomSwipeRefreshLayout     android:id="@+id/customSwipeRefreshLayout "    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.tc.customswiperefreshview.MainActivity" >    <ListView         android:id="@+id/listView"        android:layout_width="match_parent"        android:layout_height="match_parent"        >    </ListView></com.tc.customswiperefreshview.CustomSwipeRefreshLayout>

activity调用

customSwipeRefreshLayout.setOnLoadListener(new CustomSwipeRefreshLayout.OnLoadListener() {            @Override            public void onLoad() {                new Handler().postDelayed(new Runnable() {                    @Override                    public void run() {                        if (test) {                            for (int i = 15; i <20; i++) {                                data.add("我是天才"+i);                                test=false;                            }                        }else {                            Toast.makeText(MainActivity.this, "没有数据啦", Toast.LENGTH_SHORT).show();                        }                        customSwipeRefreshLayout.setOnload(false);                        adapter.notifyDataSetChanged();                    }                }, 1000);            }        });

接下来是两点注意问题:
1、addFooterView()需要在setAdapter之前调用怎么解决呢,其实我的这个解决也是不怎么好,对,就是重新获取adapter重新适配

private void addLoadLayout() {        listView.addFooterView(loadLayout);        if ( listView.getAdapter() instanceof BaseAdapter) {            BaseAdapter adapter=(BaseAdapter) listView.getAdapter() ;            listView.setAdapter(adapter);            Log.i(CustomSwipeRefreshLayout, "是baseAdapter");        }else{            Log.i(CustomSwipeRefreshLayout, "不是baseAdapter");        }    }

2、之前一直报这个错误
Caused by: java.lang.NoSuchMethodException: [class android.content.Context, interface android.util.AttributeSet]
出错原因
1)

public CustomSwipeRefreshLayout(Context context) {        super(context);    }    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {//没有生成这个构造方法,所以报错        super(context, attrs);        this.context=context;    }

2)

    private CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {        super(context, attrs);        this.context=context;    }

不知道有没有发现什么不一样的,就访问权限,private,说起来也是奇葩,eclipse快捷键自动生成的,居然是private

接下来贴出全部代码

package com.tc.customswiperefreshview;import android.content.Context;import android.support.v4.widget.SwipeRefreshLayout;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.LinearLayout.LayoutParams;import android.widget.BaseAdapter;import android.widget.LinearLayout;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {    private static final String CustomSwipeRefreshLayout = "CustomSwipeRefreshLayout";    public OnLoadListener onLoadListener;    Context context;    ListView listView;    float startY=0;    float endY=0;    private static  float touchInstance=150;    boolean isLoading=false;    LinearLayout loadLayout;    public CustomSwipeRefreshLayout(Context context) {        super(context);    }    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {        super(context, attrs);        this.context=context;    }    @Override    protected void onLayout(boolean changed, int left, int top, int right,            int bottom) {        if (listView==null) {            if (getChildCount()>0) {                for (int i = 0; i < getChildCount(); i++) {                    if (getChildAt(i) instanceof ListView) {                        listView=(ListView) getChildAt(i);                        Log.i(CustomSwipeRefreshLayout, "找到了LIstView");                        initLoadLayout();//初始化加载控件                        setListViewOnScroll();//滚动监听                        break;                    }else {                        Log.i(CustomSwipeRefreshLayout, "不是LIstView的实例");                    }                }                Log.i(CustomSwipeRefreshLayout, "LIstView是否为空:"+(listView==null));            }        }        super.onLayout(changed, left, top, right, bottom);    }    public OnLoadListener getOnLoadListener() {        return onLoadListener;    }    public void setOnLoadListener(OnLoadListener onLoadListener) {        this.onLoadListener = onLoadListener;    }    /**     * 设置滚动监听     */    private void setListViewOnScroll() {        if (listView!=null) {            listView.setOnScrollListener(new OnScrollListener() {                //正在移动                @Override                public void onScrollStateChanged(AbsListView view, int scrollState) {                    Log.i(CustomSwipeRefreshLayout, ""+listView.getLastVisiblePosition());                    if (canLoadMore()) {                        loadData();                    }else {                        Log.i(CustomSwipeRefreshLayout, "不可以加载新数据");                        }                }                @Override                public void onScroll(AbsListView view, int firstVisibleItem,                        int visibleItemCount, int totalItemCount) {                    // TODO Auto-generated method stub                }            });        }    }    /**     * 三个条件可以加载数据     * 1、滑动距离合适的时候     * 2、最后一个条目     * 3、没有正在加载数据     * @return     */    protected boolean canLoadMore() {        boolean condition1=false;        if (!isLoading){            condition1=true;        }        boolean condition2=false;        if (listView.getLastVisiblePosition()==(listView.getCount()-1)) {            condition2=true;        }        boolean condition3=false;        if ((startY-endY)>touchInstance) {            condition3=true;            }        Log.i(CustomSwipeRefreshLayout, "是否正在加载"+condition1+"是否是最后一个并且已经显示出来"+condition2+"触摸距离是否合适"+condition3);                return condition1&&condition2&&condition3;    }    /**     * 接口回调实现自定义加载数据     */    protected void loadData() {        if (onLoadListener!=null) {            if (loadLayout!=null) {                addLoadLayout();//添加footerView            }            onLoadListener.onLoad();        }    }    private void addLoadLayout() {        listView.addFooterView(loadLayout);        if ( listView.getAdapter() instanceof BaseAdapter) {            BaseAdapter adapter=(BaseAdapter) listView.getAdapter() ;            listView.setAdapter(adapter);            Log.i(CustomSwipeRefreshLayout, "是baseAdapter");        }else{            Log.i(CustomSwipeRefreshLayout, "不是baseAdapter");        }    }    private void removeLoadLayout() {        listView.removeFooterView(loadLayout);    }    public void setOnload(boolean isLoad){        isLoading=isLoad;        if (!isLoad) {            removeLoadLayout();        }    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        //按下时        if (ev.getAction()==MotionEvent.ACTION_DOWN) {            startY=ev.getY();        }        //离开时        else if(ev.getAction()==MotionEvent.ACTION_UP){            endY=ev.getY();        }        return super.dispatchTouchEvent(ev);    }    /**     * 初始化底部加载视图     */    private void initLoadLayout() {        //布局,由于父控件是ListView,所以 LayoutParams 是AbsListView的LayoutParams        AbsListView.LayoutParams listLayoutParams =new AbsListView.LayoutParams(listView.getLayoutParams());         listLayoutParams.width=LayoutParams.MATCH_PARENT;        listLayoutParams.height=100;        loadLayout=new LinearLayout(context);        loadLayout.setOrientation(LinearLayout.HORIZONTAL);        loadLayout.setLayoutParams(listLayoutParams);        loadLayout.setGravity(Gravity.CENTER_HORIZONTAL);        //dialog        android.view.ViewGroup.LayoutParams layoutParams =new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);        ProgressBar progressBar=new ProgressBar(context,null,android.R.attr.progressBarStyleInverse);        progressBar.setLayoutParams(layoutParams);        //textview        android.view.ViewGroup.LayoutParams layoutParams2 =new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);        TextView textView=new TextView(context);        textView.setText("正在加载.....");        textView.setTextSize(15);        textView.setLayoutParams(layoutParams2);        textView.setGravity(Gravity.CENTER_VERTICAL);        //设置子控件        loadLayout.addView(progressBar);        loadLayout.addView(textView);    }     interface OnLoadListener{        public void onLoad();    }}
0 0
原创粉丝点击