編輯:關於Android編程
今天給大家講講android開發中比較常見的listView的下拉加載,其實也可以叫做分頁加載。為什麼會有這個叫法呢?說說我的理解吧!
從字面上很好理解。當你滑動一個列表到底部的時候,這個時候就會出現正在加載的底部加載布局去加載更多的數據。這裡拿微信作為一個例子,如下圖所示:
vcTjus3F89PRt6K1xNK70KnXtMysoaPV4srH0vLOqtXiuPbKsbrytPrC69Do0qq4+Lf+zvHG97eiy83H68fzu/HIocr9vt2yorPKz9bV4tCpyv2+3aGj1eK49sqxuvK78cihyv2+3b7Ns8nBy9fuusTKsbXEzsrM4qGjzqrKssO01eLDtMu1o7/I57n7w7vT0LfW0rO809TYtcS5psTco6zEx8O0o6zE47/PtqjQ6NKqu/HIocirsr+1xMr9vt2jrMTjv8nS1M/rz+ujrLrDvLjE6rXEyv2+3aOsyv2+3cG/v8myu8nZsKGjobeix+vH88ilu/HIodXi0KnK/b7dsqKzys/Wy/zDx8rHu+G63LrEyrG85LXEoaPL+dLUt9bSs7zT1Ni+zbrcusO1xL3ivvbBy9XiuPbOyszioaPE48/Iu/HIocbk1tC1xMquvLjM9cr9vt2yorPKz9bL/MPHoaO1scTj0rvWsbTTzbfkr8DA1eLKrry4zPXK/b7dtb294cr4tcTKsbryo6zV4rj2yrG68tTZyKW809TYuPy24LXEyv2+3bKis8rP1sv8w8eho8jnyc/NvMv5yr6jrNXi0fmyxcrHusO1xNPDu6fM5dHpoaM8L3A+DQo8aHIgLz4NCrjFxO7H5c76uvOjrL7fzOXKtc/WtcSyv7fWtb3By6Gj1eLA78q1z9bOotDFtcTPwsCtvNPU2NCnufujqLj2yMu40L71utyyu7Tto6y88r3gw/fBy6Opo6y087jF0OjSqtLUz8K8uLj2sr3W6KO6PGJyIC8+DQpmaXJzdCAmbWRhc2g7IMrXz8i5ub2oz8LArbzT1NjKsbXEtdeyv7zT1NiyvL7Wo6jV4sDvw/zD+86qdmlld19tb3Jlo6kgc2Vjb25kICZtZGFzaDsgu/HIocr9vt2yorj4bGlzdFZpZXfJ6NbDYWRhcHRlcqO7yejWw7rDYWRhcHRlcrrzo6y199PDt723qKO6PGNvZGU+bGlzdFZpZXcuYWRkRm9vdGVyVmlldyh2aWV3X21vcmUpOy8vIFRPRE8gzO2807XXsr+8x9TYsry+1jwvY29kZT7U2c35bGlzdFZpZXe1xLXXsr/M7bzTtdeyv7zT1NiyvL7WoaPX7rrzttRsaXN0Vmlld8no1sO7rLavvODM/cb3o7o8Y29kZT5saXN0Vmlldy5zZXRPblNjcm9sbExpc3RlbmVyKHRoaXMpOy8vIFRPRE8gbGlzdFZpZXfV4srHu6y2r7zgzP08L2NvZGU+ILKi1tjQtM/gudi3vbeoo7o8YnIgLz4NCjxjb2RlPnB1YmxpYyB2b2lkIG9uU2Nyb2xsU3RhdGVDaGFuZ2VkKEFic0xpc3RWaWV3IHZpZXcsIGludCBzY3JvbGxTdGF0ZSkge308L2NvZGU+ILrNIDxjb2RlPnB1YmxpYyB2b2lkIG9uU2Nyb2xsKEFic0xpc3RWaWV3IHZpZXcsIGludCBmaXJzdFZpc2libGVJdGVtLGludCB2aXNpYmxlSXRlbUNvdW50LCBpbnQgdG90YWxJdGVtQ291bnQpIHt9PC9jb2RlPiDV4sG9uPbW2NC0tcS3vbeo0ru49srHvODM/Wxpc3RWaWV3tcS7rLav17TMrLjEseSjrMHt0ru49srHvODM/Wxpc3RWaWV3tcS7rLavoaMgdGhpcmQgJm1kYXNoOyC1sbustq+84Mz9yejWw7rDuvOjrNTa1tjQtLXEwb249re9t6jA78PmxdC2z2xpc3RWaWV3yse38bustq+1vbXXsr+yosfSzaPWubustq+jqLy0u6y2r9e0zKzOqs2j1rm7rLavo6mho8jnufu0y8qxwvrX49XiuPbM9bz+o6zEx8O0vs2809TYuPy24LXEyv2+3aGjyv2+3bzT1NjN6rPJuvO+zcui0MLK/b7d1LSjrLTLyrG74dPQuPy24LXEyv2+3dTatdeyv7P2z9ahoyBmb3VydGggJm1kYXNoOyDX7rrztbHK/b7dyKuyv7zT1Ni6w7rzo6zSxrP9tdq2/rK91tDM7bzTtcS117K/vNPU2LK8vtZ2aWV3X21vcmWjrLX308O3vbeoo7o8Y29kZT5saXN0Vmlldy5yZW1vdmVGb290ZXJWaWV3KHZpZXdfbW9yZSk7Ly8gVE9ETyDSxrP9tdeyv7XEvNPU2LK8vtY8L2NvZGU+DQo8aDQgaWQ9"下面寫代碼一步一步來實現">下面寫代碼一步一步來實現: 1、首先准備一個底部加載布局,命名為view_more
很簡單的布局,顯示了一個進度條和一個文本控件。如圖:
第二,給listView設置數據並設置滑動監聽,設置好後判斷是否滑動到listView的底部並停止滑動,如果是那麼加載更多的數據:
package com.example.drop_down_load;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity implements OnScrollListener {
private ListView listView;
private int totalCount;// 數據總條數
private List lists = new ArrayList();
private ArrayAdapter adapter;
// 創建handler接收消息並處理消息
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
// 創建adapter
adapter = new ArrayAdapter(MainActivity.this,
android.R.layout.simple_list_item_1, lists);
// 設置adapter
listView.setAdapter(adapter);
// 添加底部加載布局
listView.addFooterView(view_more);
// 設置監聽
setListeners();
break;
}
};
};
private View view_more;
private ProgressBar pb;
private TextView tvLoad;
private int lastVisibleIndex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 控件初始化
initViews();
// 初始化數據
initData();
}
private void initData() {
// 模擬網絡請求獲取數據,一次獲取15條
new Thread() {
public void run() {
try {
totalCount = 100;// 假設數據一共有100條,將來調接口可以獲取到這個值
for (int i = 0; i < 15; i++) {
lists.add("數據" + (i + 1));
}
// 給handler發消息更新UI,子線程不可以更新UI
Message message = new Message();
message.what = 0;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
private void setListeners() {
if (totalCount > 15) {
// listView設置滑動簡監聽
listView.setOnScrollListener(this);
} else {
// 假如數據總數少於等於15條,直接移除底部的加載布局,不需要再加載更多的數據
listView.removeFooterView(view_more);
}
}
private void initViews() {
listView = (ListView) findViewById(R.id.listView);
// 構建底部加載布局
view_more = (View) getLayoutInflater()
.inflate(R.layout.view_more, null);
// 進度條
pb = (ProgressBar) view_more.findViewById(R.id.progressBar);
// “正在加載...”文本控件
tvLoad = (TextView) view_more.findViewById(R.id.tv_Load);
}
/**
* 監聽listView的滑動狀態的改變
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.e("TAG", "lastVisibleIndex = " + lastVisibleIndex);
Log.e("TAG", "adapter.getCount() = " + adapter.getCount());
// 滑到底部後自動加載,判斷listView已經停止滾動並且最後可視的條目等於adapter的條目
// 注意這裡在listView設置好adpter後,加了一個底部加載布局。
// 所以判斷條件為:lastVisibleIndex == adapter.getCount()
if (scrollState == SCROLL_STATE_IDLE
&& lastVisibleIndex == adapter.getCount()) {
/**
* 這裡也要設置為可見,是因為當你真正從網絡獲取數據且獲取失敗的時候。
* 我在失敗的方法裡面,隱藏了底部的加載布局並提示用戶加載失敗。所以再次監聽的時候需要
* 繼續顯示隱藏的控件。因為我模擬的獲取數據,失敗的情況這裡不給出。實際中簡單的加上幾句代碼就行了。
*/
pb.setVisibility(View.VISIBLE);
tvLoad.setVisibility(View.VISIBLE);
loadMoreData();// 加載更多數據
}
}
private void loadMoreData() {
}
/**
* 監聽listView的滑動
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 計算最後可見條目的索引
lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;
// 當adapter中的所有條目數已經和要加載的數據總條數相等時,則移除底部的View
if (totalItemCount == totalCount + 1) {
// 移除底部的加載布局
listView.removeFooterView(view_more);
}
}
}
以上代碼就是我上面步驟2和步驟2中所說的東西。加上我寫了注釋,所以相信大家看起來很簡單。關鍵點是怎麼判斷listView是否滑動到了底部並停止了滑動。我在代碼中添加了兩行log,可以打印日志信息。大家去自己調試就能明白我對關鍵點是怎麼判斷的了,但是也有聰明的!嘿嘿!大家都懂,自己人,我就不接話了。如圖:
最後就是加載更多的數據了,即完成第二步中未完成的方法:
loadMoreData();// 加載更多數據
具體代碼實現為:
private void loadMoreData() {
// 獲取此時adapter中的總條目數
int count = adapter.getCount();
// 一次加載15條數據,即下拉加載的執行
if (count + 15 < totalCount) {
start = count;
end = start + 15;
initData(start, end);// 模擬網絡獲取數據操作
} else {// 數據不足15條直接加載到結束
start = count;
end = totalCount;
initData(start, end);// 模擬網絡獲取數據曹祖
// 數據全部加載完成後,移除底部的view
listView.removeFooterView(view_more);
Toast.makeText(MainActivity.this, "數據已經全部加載", 1).show();
}
}
private void initData(final int start, final int end) {
// 模擬網絡請求獲取數據,一次獲取15條
new Thread() {
public void run() {
try {
Thread.sleep(4000);// 模擬獲取數據時的耗時3s
for (int i = start; i < end; i++) {
lists.add(i, "數據" + (i + 1));
}
// 給handler發消息更新UI,子線程不可以更新UI
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
此時handler中還要再加一個case語句,用來刷新數據源,如圖紅色方框標注地方,大家自己加一下。最後我會給項目源碼,大家可以下載看我的代碼:
好了下面給出幾張項目的展示圖片:
15條數據後加載更多數據,如圖: 30條數據後加載更多數據,如圖: 45條數據後加載更多數據,如圖: 數據全部加載完後,移除底部加載布局,如圖:談談我的感悟:你需要有自己的想法思路,別人的東西可以借鑒,但是你需要從中學到點什麼。要是什麼都沒學到,那就失去了分享的意義了!分享是為了讓大家學到更多,收獲更多。希望我的這篇能夠給大家一點點收獲!
前言前面我們已經完整的講述了屬性動畫的實現,我們已經學會了怎麼實現動畫,如果沒有屬性我們也學會了怎麼添加屬性,還學習了用ValueAnimator來實現動畫。Evalua
先看看我們的整個流程: 理解坐標系: 左側是Opengl默認的坐標系,右邊是典型的android設備屏幕的坐標系。左側的瘦瘦的
今天花了整個下午+晚上的的時間學習了Activity的啟動模式,本來以為這個知識點很簡單,但是在學習的過程中發現,Activity的啟動模式並沒有
Launcher3壁紙的規格默認是:壁紙高度=屏幕高度,壁紙寬帶=屏幕寬度*2倍 Android4.4的壁紙信息存放在/data/system/users/0/目錄下,W