一、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);
}
}
});
}
适配器略,和原来一样。没啥变化。