自定義安卓實現數據分頁功能
- 最近基於客戶要求做了個手持安卓端的軟件,主要是用於數據和相關信息的查看功能。開始由於數據較少,查看的數據都是用的滾屏展示的,后來因為數據量大、經常要加載很久。所以要求實現分頁。
1、分頁實現原理
-
博主在網上看了比較多的分頁模板、大致套路總結有兩個思路:
-
(1)一步到位、一次性返回所有數據:將數據在后台封裝好、類似於前端數據展示一樣、用PageInfo進行封裝數據,然后返回到前端。安卓端也相當於是一個前端,此方法相當於一步到位、一次請求返回所有數據,剩下的數據解析翻頁啥就交給安卓端搞定了。
-
(2)單獨請求每頁數據、實時更新:后台編寫個獲取數據的接口。通過安卓端每次點擊下一頁發送一個http請求、攜帶頁數參數。對應返回相應頁數的一部分數據。相當於每次翻頁都會單獨發送請求返回數據。個人覺得對於數據實時增刪要求較高切服務器壓力不大可選用此類方法。
-
由於博主主要只需展示數據、未用到增刪,考慮到每次分頁都發請求可能會增加服務器壓力,那就選用一次性到位的方法吧。而且分頁展示用的是自定義的TableView,所以一切都是自己寫的。以下是我自己寫的一個分頁demo、可能不套用、僅供提供思路參考!看看我的效果圖吧、非專業UI界面有點丑、哈哈
2、基於tableView實現的數據展示。
- 自定義的TableView:
public class TableView extends HorizontalScrollView {
}
//此處省略一萬字,完整版請點最底下鏈接! 因為都是自定義的!僅提供思路!如想copy博主界面demo的可點最下方鏈接下載!
- 自定義分頁插件: 后台直接返回的是JSONArray,此工具類作用就是解析后台返回的數據,定義一個pageBean封裝每頁的數據。下面寫了三種數據格式、分別是List<String[]> 、 JSONArray、 List 。可根據自己需求增改!
PageUtils
public class PageUtils {
private JSONArray currentJsonArray;
private List<String[]> stringList;
public void setData(JSONArray currentJsonArray, List<String[]> stringList){
this.currentJsonArray = currentJsonArray;
this.stringList = stringList;
}
public static PageBean getPageData(JSONArray currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
int everyPageLimit = pageMax -1;
PageBean pageData = new PageBean();
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //總頁數
HashMap<Integer, List<Object>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<Object> json = new LinkedList<>();
if((i + 1)* everyPageLimit > currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setJsonPage(jsonPage);
return pageData;
}
public static PageBean getPageArrayData(List<HashMap> currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
PageBean pageData = new PageBean();
int everyPageLimit = pageMax - 1;
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //總頁數
HashMap<Integer, List<HashMap>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<HashMap> json = new LinkedList<>();
if((i + 1)* everyPageLimit >= currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setMapPage(jsonPage);
return pageData;
}
public static PageBean getPageData(List<String[]> currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
int everyPageLimit = pageMax -1;
PageBean pageData = new PageBean();
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //總頁數
HashMap<Integer, List<String[]>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<String[]> json = new LinkedList<>();
if((i + 1)* everyPageLimit >= currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setStringPage(jsonPage);
return pageData;
}
}
Pagebean
public class PageBean {
private int pages; //當前頁數
//當前頁的數據
private HashMap<Integer, List<String[]>> stringPage ;
private HashMap<Integer, List<Object>> jsonPage ;
private HashMap<Integer, List<HashMap>> mapPage ;
public HashMap<Integer, List<HashMap>> getMapPage() {
return mapPage;
}
public void setMapPage(HashMap<Integer, List<HashMap>> mapPage) {
this.mapPage = mapPage;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public HashMap<Integer, List<String[]>> getStringPage() {
return stringPage;
}
public void setStringPage(HashMap<Integer, List<String[]>> stringPage) {
this.stringPage = stringPage;
}
public HashMap<Integer, List<Object>> getJsonPage() {
return jsonPage;
}
public void setJsonPage(HashMap<Integer, List<Object>> jsonPage) {
this.jsonPage = jsonPage;
}
}
3、具體實現效果展示:
public class AreaCtrlDetailActivity extends Activity {
private JSONArray resultJson ;
private boolean flag = false;
private TextView title;
private String areaType;
private String deptId;
String[] dataP ;
HashMap<String, JSONObject> allAreaRollCallMap = new HashMap<>();
private LinearLayout tableLayout;
PageBean pageData = new PageBean();
private int curPage = 1;
int maxPage = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.demo_detail_list);
tableLayout = findViewById(R.id.tableBody);
getActionBar().show();
getActionBar().setBackgroundDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg));
getActionBar().setTitle("區域詳情");
dataP = getIntent().getStringArrayExtra("rowData");
areaType = getIntent().getStringExtra(Constants.Param.AREA_TYPE);
deptId = getIntent().getStringExtra(Constants.Param.DEPT_ID);
freshPanel();
initTableView();
}
private void freshPanel() {
new Thread(new Runnable() {
@Override
public void run() {
getGlobalData();
}
}).start();
}
private synchronized void initTableView() {
if (!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(null != pageData) {
refreshPanel(pageData.getJsonPage().get(curPage));
maxPage = pageData.getPages();
}else{
CommonCode.showMessage(AreaCtrlDetailActivity.this, "未查詢到數據");
finish();
}
}
public void onQueryAddPageButtonClicked(View v){
if(curPage >= maxPage){
CommonCode.showMessage(AreaCtrlDetailActivity.this, "已到最后一頁");
}else{
curPage++;
runOnUiThread(()->refreshPanel(pageData.getJsonPage().get(curPage)));
}
}
public void onQueryReducePageButtonClicked(View v){
if(curPage == 1){
CommonCode.showMessage(AreaCtrlDetailActivity.this, "已到首頁");
}else{
curPage --;
runOnUiThread(()->refreshPanel(pageData.getJsonPage().get(curPage)));
}
}
void refreshPanel(List<Object> cpData){
TableView2 tv = (TableView2) findViewById(R.id.tableView);
tv.clearData();
tv.setHeaderBackColor(R.color.md_blue_300);
tv.setHeaderNames("姓名", "狀態", "部門", "編號", "詳情","id");
//設置每格的寬度
tv.setColumnWidth(0, 105);
tv.setColumnWidth(1, 80);
tv.setColumnWidth(2, 170);
tv.setColumnWidth(3, 180);
tv.setColumnWidth(4, 100);
if(null == cpData || 0 == cpData.size()){
runOnUiThread(() -> Toast.makeText(AreaCtrlDetailActivity.this, "當前區域無數據!", Toast.LENGTH_SHORT).show());
finish();
}
for (int i = 0; i < cpData.size(); i++) {
JSONObject rowData = (JSONObject) cpData.get(i);
allAreaRollCallMap.put(rowData.getString(Constants.Param.PERSON_INFO_ID), rowData);
String detail = "詳情";
String io = rowData.getString(Constants.Param.IO_TYPE).equals(Constants.Common.IN) ?Constants.Common.E_IN : Constants.Common.E_OUT;
String[] ss = { rowData.getString(Constants.Param.PERSON_INFO_NAME),io, rowData.getString(Constants.Param.DEPT_NAME),
rowData.getString(Constants.Param.PERSONNEL_NUMBER), detail, rowData.getString(Constants.Param.PERSON_INFO_ID)};
Log.d("success", Arrays.toString(ss));
tv.addRowData(i, ss);
}
tv.setOnItemClickListener(new TableView2.OnTableItemClickListener() {
@Override
public void onItemClick(int position, String[] rowData) {
Toast toast=Toast.makeText(AreaCtrlDetailActivity.this,rowData[position]+"的詳情信息",Toast.LENGTH_SHORT );
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
});
tv.setOnItemLongClickListener(new TableView2.OnTableItemLongClickListener() {
@Override
public void onItemLongClick(int position, String[] rowData) {
}
});
tv.setOnUnitClickListener(new TableView2.OnUnitClickListener() {
@Override
public void onUnitClick(int row, int column, String unitText) {
if(!"all".equals(unitText)){
Intent intent = new Intent(AreaCtrlDetailActivity.this, AreaCtrlPersonInfoDetailActivity.class);
String[] data = tv.getRowData(row);
intent.putExtra("rowData", data);
intent.putExtra("areaType", dataP[1]);
intent.putExtra(Constants.Param.PERSON_ID, unitText);
intent.putExtra("dataDetail", allAreaRollCallMap.get(unitText));
startActivity(intent);
}
}
});
tv.setEventMode(TableView2.MODE_EITHER_UNIT_EVENT); //自定義某些列的單元格處理事件
tv.setColumnEventIndex(4);//設置哪些列的單元格處理事件
tv.setUnitSelectable(false);//單元格處理事件的時候是否可以選中
tv.setUnitDownColor(R.color.md_blue_900);//單元格處理事件的時候,按下態的顏色
tableLayout.removeAllViews();
tableLayout.addView(tv);
}
public void onQueryCancelButtonClicked(View v){
finish();
}
//這是后台數據獲取、設置個鎖、如果數據未獲取到、讓界面繪制的線程等一下。加載完在喚醒!
private synchronized void getGlobalData(){
JSONObject param = new JSONObject();
//傳遞的參數
param.put(Constants.Param.AREA_TYPE, areaType);
param.put(Constants.Param.DEPT_ID, deptId);
param.put(Constants.Param.CATEGORY, Constants.Category.PRISON);
String url = CommonCode.getPortalUrl(Constants.Portal.HANDLE_CLIENT_GET_AREA_CTRL_DETAIL);
JSONObject result = CommonCode.postGetJson(param,url);
if (CommonCode.getResultFlag(result)) {
//成功返回數據並用分頁封裝!
resultJson = (JSONArray) CommonCode.getResultMapProperty(result, Constants.Param.DATA_LIST);
pageData = PageUtils.getPageData(resultJson, 17);
}else{
runOnUiThread(() -> Toast.makeText(AreaCtrlDetailActivity.this, result.getString("message"), Toast.LENGTH_SHORT).show());
}
flag = true;
notify();
}
}
布局文件
<?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">
<HorizontalScrollView
android:id="@+id/scroll_data_lay"
android:layout_width="0dp"
android:layout_height="460dp"
android:layout_marginTop="10dp"
android:scrollbarDefaultDelayBeforeFade="400"
android:scrollbarSize="4dp"
android:scrollbars="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/tableBody"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/textView18"
tools:layout_editor_absoluteY="134dp">
<com.neurotec.samples.multibiometric.util.TableView2
android:id="@+id/tableView"
android:layout_width="317dp"
android:layout_height="460dp"
android:layout_marginLeft="1dp"
app:headerTextColor="#000000"
app:headerTextSize="10sp" />
</LinearLayout>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/bottomButtonsLinearLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
<Button
android:id="@+id/pageReduce"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/md_light_blue_400"
android:gravity="center"
android:onClick="onQueryReducePageButtonClicked"
android:text="上一頁"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/pageAdd"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/md_light_blue_400"
android:gravity="center"
android:onClick="onQueryAddPageButtonClicked"
android:text="下一頁"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:background="#78909C"
android:gravity="center"
android:onClick="onQueryCancelButtonClicked"
android:text="返 回"
android:textColor="#FFFFFF" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
-
注:博主的代碼未考慮到界面界面適配。因為公司產品用的定制設備不需要多型號界面適配,界面適配暫未有深層次研究,所以布局文件代碼僅供參考、未通用!
-
一直不務正業的野雞Java后端開發!如有錯誤、還望指正!如果對你有啟發,記得點個贊哈!手動滑稽!謝謝!
剛才說到的TableView控件!下載地址 傳送門