Android 滑动列表之ListView

一、ListView

1、介绍

ListView是一种用来显示多个可滑动项(Item)列表的的ViewGroup 。

需要使用Adapter将集合数据和每一个Item所对应的布局动态适配到ListView中显示 。

显示列表: listView.setAdapter(adapter)。

更新列表: adapter.notifyDataSetChanged()。

2、常用适配器

(1) ArrayAdapter:  显示最简单的列表(文本)

集合数据为List<String>或String[]

(2)SimpleAdapter: 显示复杂的列表

集合数据必须是List<Map<String,Object>>类型

(3)BaseAdapter: 显示复杂的列表

集合数据可以是任意类型的集合List<Xxx>

(4) SimpleCursorAdapter: 显示复杂的列表

3、上拉加载和下拉刷新多种实现方式

自定义View实现上拉加载和下拉刷新

使用PullToRefresh 实现上拉加载和下拉刷新 

下载啊地址:https://github.com/chrisbanes/Android-PullToRefresh

使用Ultra-Pull-To-Refresh实现上拉加载和下拉刷新 (不支持上拉加载)

使用SwipeToRefreshLayout实现上拉加载和下拉刷新

 

二、ListView的使用和自定义刷新

package com.lht.liuhaitao;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class MyBaseAdapter extends BaseAdapter {

    private Context mContext;
    private List<String> mList;

    public MyBaseAdapter(Context context, List<String> list){
        mContext=context;
        mList=list;
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder=null;
        if(convertView==null){
            holder=new ViewHolder();
            convertView=LayoutInflater.from(mContext).inflate(R.layout.list_item,null);
            holder.title=convertView.findViewById(R.id.title);
            convertView.setTag(holder);
        }else{
            holder= (ViewHolder) convertView.getTag();
        }
        holder.title.setText(mList.get(position));
        return convertView;
    }

    class ViewHolder{
        TextView title;
    }
}

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
</LinearLayout>

 

package com.lht.liuhaitao;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;

/**
 * 自定义ListView 实现下拉刷新与加载更多
 * 0、改变头部的padingTop就能慢慢显示和隐藏
 * 1、需要添加头部和尾部下拉和加载更多视图
 * 2、触摸事件判断是向下滑动的而且在第一个item的时候
 * 3、在滚动事件判断滚动到最后一个Item的时候开始下拉
 * 4、默认--》下拉--》松开--》刷新--》还原默认
 * 5、考虑不同状态下UI变化
 */
public class RefreshListView extends ListView implements AbsListView.OnScrollListener {

    private final static int REDUCTION=0;//默认
    private final static int REFRESHING=1;//下拉状态
    private final static int RELEASE=2;//松开下拉状态
    private final static int HEADER_LOADING=3;//上啦刷新正在加载数据状态
    private final static int FOOTER_LOADING_NO_ATA=4;//尾部我是由地线的状态
    private final static int FOOTER_LOADING=5;//加载更多
    private final static int FOOTER_REDUCTION=6;//加载更多还原

    private int currentState=0;//当前状态
    private boolean isHeaderLoading=false;//顶部下拉刷新是否正在加载数据
    private boolean isFooterLoading=false;//底部加载更多是否正在加载数据
    private View headerView;//头视图
    private View footerView;//尾部视图
    private TextView  headerOftextInfo;//头部视图种的文字提示
    private TextView footerOfTextInfo;//底部加载更多文字以实
    private int footerHidhet=0;//尾部高度
    private int headerHieght=0;//头部高度
    private int downY=0;//手指放在屏幕上时候的Y坐标
    private OnRefreshListener listenr;//自定义改变数据的回调
    private int newPadingTop=0;
    private static final int HANDLE_HEADER_DATA_PRE=1;
    private static final int  HANDLE_HEADER_DATA_FINISH=2;
    private static final int  HANDLE_FOOTER_DATA_PRE=3;
    private static final int  HANDLE_FOOTER_DATA_FINISH=4;
    private static final int  HANDLE_FOOTER__NO_DATA=5;


    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case HANDLE_HEADER_DATA_PRE:
                    isHeaderLoading=true;
                    currentState=HEADER_LOADING;//加载数据中
                    switchStatus();
                    break;
                case HANDLE_HEADER_DATA_FINISH:
                    currentState=REDUCTION;//恢复默认状态
                    switchStatus();
                    isHeaderLoading=false;
                    break;
                case HANDLE_FOOTER_DATA_PRE:
                    currentState=FOOTER_LOADING;//加载更多状态
                    switchStatus();
                    isFooterLoading=true;
                    break;
                case HANDLE_FOOTER_DATA_FINISH:
                    isFooterLoading=false;
                    currentState=FOOTER_REDUCTION;
                    switchStatus();
                    break;

                case  HANDLE_FOOTER__NO_DATA:
                    isFooterLoading=false;
                    currentState=FOOTER_LOADING_NO_ATA;
                    switchStatus();
                    break;


            }

        }
    };

    private String TAG="RefreshListView";

    public RefreshListView(Context context) {
        super(context);
    }

    public RefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        initHeaderView();
        initFooterView();
        setOnScrollListener(this);
    }

    /**
     * 添加顶部下拉刷新视图
     */
    private void initHeaderView(){
        //获取视图
        headerView= View.inflate(getContext(),R.layout.heder_refresh,null);
        headerOftextInfo=headerView.findViewById(R.id.text_state);
        //测量头部视图
        headerView.measure(0,0);
        //获得测量的头部视图高度
        headerHieght=headerView.getMeasuredHeight();
        //隐藏掉头头部
        headerView.setPadding(0,-headerHieght,0,0);
        //添加头部视图到ListView。
        this.addHeaderView(headerView);
    }

    /**
     * 添加底部加载更多
     */
    private void initFooterView(){
        //获取视图
        footerView=View.inflate(getContext(),R.layout.footer_refresh,null);
        footerOfTextInfo=footerView.findViewById(R.id.footer_text);
        addFooterView(footerView);
    }

    /**
     * 改变UI状态
     */
    private void switchStatus(){
       switch (currentState){
           case REFRESHING: //下拉中
               headerView.setPadding(0,newPadingTop,0,0);
               headerOftextInfo.setText("下拉刷新");
               break;
           case RELEASE: //松开刷新
               headerView.setPadding(0,newPadingTop,0,0);
               headerOftextInfo.setText("松开刷新");
               break;
           case HEADER_LOADING://加载数据
               headerView.setPadding(0,0,0,0);
               headerOftextInfo.setText("刷新数据中......");
               break;
           case REDUCTION://还原
               headerView.setPadding(0,-headerHieght,0,0);
               headerOftextInfo.setText("下拉刷新");
               break;
           case FOOTER_LOADING:
               footerOfTextInfo.setText("正在加载中.....");
               break;
           case FOOTER_REDUCTION:
               footerOfTextInfo.setText("加载更多");
               break;
           case FOOTER_LOADING_NO_ATA:
               footerOfTextInfo.setText("我是有地线的");
               break;
       }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                //开始的Y
                downY= (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //如果正在刷新就略过
                if(!isHeaderLoading){
                    //滑动时候的Y
                    int moveY= (int) ev.getY();
                    //滑动的距离
                    int moveDistanceY=moveY-downY;
                    //计算paddignTop,让头慢慢露出来
                    newPadingTop=-headerHieght+moveDistanceY;
                    if(newPadingTop<=0 && getFirstVisiblePosition()==0 &&!isHeaderLoading){
                        if(newPadingTop>=-headerHieght/3){
                            currentState=RELEASE;
                            switchStatus();//变化状态为松开
                        }else{
                            currentState=REFRESHING;//下拉状态
                            switchStatus();
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                //如果手指拿走了还是下拉状态是中途又不想刷新了,就把头隐藏了
                if(currentState==REFRESHING ){
                    currentState=REDUCTION;
                    switchStatus();
                }else if(currentState==RELEASE){
                    if(listenr!=null){
                        //分线程处理耗时数据
                        Thread thread=new Thread(new Runnable() {
                            @Override
                            public void run() {
                                handler.sendEmptyMessage(HANDLE_HEADER_DATA_PRE);
                                listenr.onRefresh();//钩子
                                if(getCount()==0){
                                    handler.sendEmptyMessage(HANDLE_FOOTER__NO_DATA);
                                }else{
                                    handler.sendEmptyMessage(HANDLE_HEADER_DATA_FINISH);
                                }
                            }
                        });
                        thread.start();
                    }
                }
                isHeaderLoading=false;
                //还原
                currentState=REDUCTION;
                switchStatus();
        }
        return super.onTouchEvent(ev);

    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){ //停止滑动时候
            //isFooterLoading 避免重复
            if( getLastVisiblePosition()==(getCount()-1) && !isFooterLoading){
                if(listenr!=null){
                    Thread thread=new Thread(new Runnable() {
                        @Override
                        public void run() {
                            handler.sendEmptyMessage(HANDLE_FOOTER_DATA_PRE);
                            listenr.onLoandMore(); //钩子
                            handler.sendEmptyMessage(HANDLE_FOOTER_DATA_FINISH);
                        }
                    });
                    thread.start();
                }
                //还原状态
                currentState=FOOTER_REDUCTION;
                switchStatus();
                isFooterLoading=false;
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

    public void setOnRefreshListener(OnRefreshListener listenr){
        this.listenr=listenr;
    }
    interface OnRefreshListener{
        void onRefresh();
        void onLoandMore();
    }
}

heder_refresh.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:gravity="center"
        android:paddingTop="20dp"
        android:paddingBottom="20dp"
        android:background="@android:color/darker_gray"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ProgressBar
            android:layout_width="20dp"
            android:layout_height="20dp" />
        <TextView
            android:id="@+id/text_state"
            android:layout_marginTop="2dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16dp"
            android:text="下拉刷新"/>
    </LinearLayout>
</LinearLayout>

footer_refresh.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/footer_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:paddingBottom="20dp"
        android:paddingTop="20sp"
        android:textSize="16dp"
        android:text="我是有地线的"/>

</LinearLayout>

 

package com.lht.liuhaitao;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private RefreshListView listView;
    static final String TAG="MainActivity";
    private List listDatas;
    private MyBaseAdapter myBaseAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView=findViewById(R.id.list_view);
        listDatas=buildData();
        myBaseAdapter=new MyBaseAdapter(this,listDatas);
        listView.setAdapter(myBaseAdapter);
        listView.setOnRefreshListener(new RefreshListView.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //处理数据,直接处理就行,已经在分线程了
                //模拟延时
                listDatas.clear();
                for(long i=0;i<15;i++){
                    listDatas.add("我是刷新的进来的数据"+i);
                }
                myBaseAdapter.notifyDataSetChanged();
            }

            @Override
            public void onLoandMore() {
                //处理数据
                Log.e(TAG, "onLoandMore: " );
                //模拟添加数据
                for(long i=0;i<15;i++){
                    listDatas.add("我是加载更多进来的数据"+i);
                }
                myBaseAdapter.notifyDataSetChanged();

            }
        });

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //可以获取每个Item中的数据
                TextView textView=view.findViewById(R.id.title);
                Toast.makeText(MainActivity.this,textView.getText(),Toast.LENGTH_LONG).show();
            }
        });

    }

    private List<String> buildData(){
        List<String> list=new ArrayList<>();
        for(int i=0;i<20;i++){
            list.add("name:liuhaitao"+i);
        }
        return list;
    }
}
activity_main.xml

<com.lht.liuhaitao.RefreshListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </com.lht.liuhaitao.RefreshListView>

 

三、使用SwipeRefreshLayout(没有上啦加载更多)


    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.lht.liuhaitao.RefreshListView
            android:id="@+id/list_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">>
        </com.lht.liuhaitao.RefreshListView>

    </android.support.v4.widget.SwipeRefreshLayout>
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        swipe_refresh=(SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
        listView=findViewById(R.id.list_view);
        listDatas=buildData();
        myBaseAdapter=new MyBaseAdapter(this,listDatas);
        listView.setAdapter(myBaseAdapter);

        //可以设置四种颜色,小于四种就行
        swipe_refresh.setColorSchemeColors(Color.BLUE,Color.GREEN,Color.RED,Color.BLACK);
        //手指在屏幕滑动下拉多少才出发刷新
        swipe_refresh.setDistanceToTriggerSync(350);
        //设置圆圈的背景颜色
        swipe_refresh.setProgressBackgroundColorSchemeColor(Color.WHITE);
        //设置圆圈的大小
        swipe_refresh.setSize(SwipeRefreshLayout.LARGE);
        //设置下拉刷新监听
        swipe_refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //如果当前没有刷新中
                if(swipe_refresh.isRefreshing()){
                    //延迟5秒后刷新数据
                    new Handler().postDelayed(new Runnable(){
                        @Override
                        public void run() {
                            Log.e(TAG, "run: "+"okokok" );
                            //清除集合数据
                            listDatas.clear();
                            for(long i=0;i<15;i++){
                                 listDatas.add("我是刷新的进来的数据"+i);
                                Log.e(TAG, "run: "+ "我是刷新的进来的数据"+i);
                             }
                            swipe_refresh.setRefreshing(false);//是否进行刷新
                            myBaseAdapter.notifyDataSetChanged();

                        }
                    },2000);
                }

            }
        });

}

适配器略,和原来一样。没啥变化。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值