首先还是做一个listview,这次我们的数据使用一个自定义的类来定义,这个类只有两个属性
package com.example.listviewtest03;
public class News {
String title;
String content;
}
然后在我们的起始页面来操作
package com.example.listviewtest03;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Vector;
public class MainActivity extends AppCompatActivity {
private ListView listView;
//首先实例化布局并在下面绑定布局
private Vector<News> news = new Vector<>();
//新建一个泛型为News的Vector集合(Vector集合是线程安全的,是同步访问的),然后实例化。
private MyAdapter myAdapter;
//在开头声明然后在下面初始界面实例化
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView1);
initDate();
//因为该方法非static在程序启动界面调用一下该方法,才能初始化数据
myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
//实例化adapter并填入listview
}
/**
* 初始化数据,每一次循环新建一个news对象并给两个属性赋值,然后把对象填进集合,最后index+1
*/
private int index = 1;
private void initDate(){
for (int i = 0; i<25; i++){
News n = new News();
n.content = "客户编号--" + index;
n.title = "客户名称--" + index;
news.add(n);
index++;
}
}
/**
* 自定义适配器
*/
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return news.size();
}
@Override
public Object getItem(int i) {
return news.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null){
view = getLayoutInflater().inflate(R.layout.item ,null);
viewHolder = new ViewHolder();
viewHolder.tv_content = view.findViewById(R.id.textView2);
viewHolder.tv_title = view.findViewById(R.id.textView);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
News news1 = news.get(i);
viewHolder.tv_title.setText(news1.title);
viewHolder.tv_content.setText(news1.content);
return view;
}
class ViewHolder{
TextView tv_title;
TextView tv_content;
}
}
}
效果是这样的
接下来就是做分页加载,当我们的数据达到我们这定好的数据就会停止加载,当用户把进度条拉到我们设定的数量的最大值之后,就会开始重新加载下一页
首先我们需要做一个加载的页面
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar2"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="110dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="加载中...."
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar2" />
</androidx.constraintlayout.widget.ConstraintLayout>
这里我们用了一个progressbar(当然你也可以用别的)和一个textview来显示,progressbar实际上是动态的,实际运行效果时是转动的
然后在起始页面的onCreate方法中放进listview
package com.example.listviewtest03;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Vector;
public class MainActivity extends AppCompatActivity {
private ListView listView;
//首先实例化布局并在下面绑定布局
private Vector<News> news = new Vector<>();
//新建一个泛型为News的Vector集合(Vector集合是线程安全的,是同步访问的),然后实例化。
private MyAdapter myAdapter;
//在开头声明然后在下面初始界面实例化
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView1);
View footview = getLayoutInflater().inflate(R.layout.loding,null);
//先使用inflate实例化然后使用下面的方法填入
listView.addFooterView(footview);
//使该页面加载在底部,相反的加载在顶部的是 listView.addHeaderView();
initDate();
//因为该方法非static在程序启动界面调用一下该方法,才能初始化数据
myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
//实例化adapter并填入listview
}
/**
* 初始化数据,每一次循环新建一个news对象并给两个属性赋值,然后把对象填进集合,最后index+1
*/
private int index = 1;
private void initDate(){
for (int i = 0; i<25; i++){
News n = new News();
n.content = "客户编号--" + index;
n.title = "客户名称--" + index;
news.add(n);
index++;
}
}
/**
* 自定义适配器
*/
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return news.size();
}
@Override
public Object getItem(int i) {
return news.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null){
view = getLayoutInflater().inflate(R.layout.item ,null);
viewHolder = new ViewHolder();
viewHolder.tv_content = view.findViewById(R.id.textView2);
viewHolder.tv_title = view.findViewById(R.id.textView);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
News news1 = news.get(i);
viewHolder.tv_title.setText(news1.title);
viewHolder.tv_content.setText(news1.content);
return view;
}
class ViewHolder{
TextView tv_title;
TextView tv_content;
}
}
}
当然,我们想让他在加载页面的时候再显示,最重要的当然是写逻辑 ,我们这里使用继承
AbsListView.OnScrollListener接口的方法得到监听下拉滚动条的方法,同时判断是否最后一条信息已经显示,是的话就启动我们加载新数据的线程,加载完数据之后需要主页面进行刷新,因为子线程无法对主线程进行操作,这里我们使用了handler来向主线程发送请求,在主线程的handler里面判断,然后用notifyDataSetChanged();来进行操作,notifyDataSetChanged()可以在修改适配器绑定的数组后, 不用重新刷新Activity,通知Activity更新ListView。下面是完整代码
package com.example.listviewtest03;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Vector;
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener {
private ListView listView;
//首先实例化布局并在下面绑定布局
private Vector<News> news = new Vector<>();
//新建一个泛型为News的Vector集合(Vector集合是线程安全的,是同步访问的),然后实例化。
private MyAdapter myAdapter;
//在开头声明然后在下面初始界面实例化
private static final int DATA_UPDATE = 0x1;
//数据更新完成后的标记
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView1);
listView.setOnScrollListener(this);
//注册监听
View footview = getLayoutInflater().inflate(R.layout.loding,null);
listView.addFooterView(footview);
//使该页面加载在底部,相反的加载在顶部的是 listView.addHeaderView();
initDate();
//因为该方法非static在程序启动界面调用一下该方法,才能初始化数据
myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
//实例化adapter并填入listview
}
/**
* 初始化数据,每一次循环新建一个news对象并给两个属性赋值,然后把对象填进集合,最后index+1
*/
private int index = 1;
private void initDate(){
for (int i = 0; i<25; i++){
News n = new News();
n.content = "客户编号--" + index;
n.title = "客户名称--" + index;
news.add(n);
index++;
}
}
/**
*接受子线程发送的标记从而改变主线程
*/
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what ){
case DATA_UPDATE:
myAdapter.notifyDataSetChanged();
//notifyDataSetChanged()可以在修改适配器绑定的数组后,
// 不用重新刷新Activity,通知Activity更新ListView。
break;
}
}
};
/**
* 监听滚动条状态改变的方法
* @param absListView
* @param i 当前状态
* 三种状态 SCROLL_STATE_FLING,这个参数表示你手离开后ListView还在“飞”中
* SCROLL_STATE_IDLE,这个参数表示ListView停下不动了
* SCROLL_STATE_TOUCH_SCROLL,这个参数表示你手还在ListView上
*/
private int visibleLastIndex;//用来可显示的最后一条数据的索引
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
if (myAdapter.getCount() == visibleLastIndex && i == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
new loding().start();
//当最后一条数据的索引被显示,同时滚动条滚到最后停住了,启动加载新条目
}
}
/**
*
* @param absListView
* @param i 当前第一个可见的item
* @param i1 当前总共有多少个可见的item
* @param i2 总的item
*/
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
visibleLastIndex = i + i1 -1;
//注意这里不要忘了-1,因为我们做的加载的布局也占用了一个item
//如果没有-1他会一直以为是在倒数第二条
}
/**
* 该方法用于当加载新的条目的时候人为的使程序停滞1秒用来模仿网络加载时的延迟
*/
class loding extends Thread{
@Override
public void run() {
initDate();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(DATA_UPDATE);
//通过handler给主线程发送一个信息标记
}
}
/**
* 自定义适配器
*/
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return news.size();
}
@Override
public Object getItem(int i) {
return news.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null){
view = getLayoutInflater().inflate(R.layout.item ,null);
viewHolder = new ViewHolder();
viewHolder.tv_content = view.findViewById(R.id.textView2);
viewHolder.tv_title = view.findViewById(R.id.textView);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
News news1 = news.get(i);
viewHolder.tv_title.setText(news1.title);
viewHolder.tv_content.setText(news1.content);
return view;
}
class ViewHolder{
TextView tv_title;
TextView tv_content;
}
}
}