转自http://www.android-study.com/jichuzhishi/496.html
实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据。先来看看本文程序运行的动画:
这个SQL分页表格控件主要分为“表格区”和“分页栏”这两部分,这两部分都是基于GridView实现的。网上介绍Android上实现表格的DEMO一般都用ListView。ListView与GridView对比,ListView最大的优势是格单元的大小可以自定义,可以某单元长某单元短,但是难于实现自适应数据表的结构;而GridView最大的优势就是自适应数据表的结构,但是格单元统一大小。。。对于数据表结构多变的情况,建议使用GridView实现表格。
本文实现的SQL分页表格控件有以下特点:
1、自适应数据表结构,但是格单元统一大小。
2、支持分页。
3、“表格区”有按键事件回调处理,“分页栏”有分页切换事件回调处理。
本文程序代码较多,可以到这里下载整个工程的源码:testSQLite.rar
items.xml的代码如下,它是“表格区”和“分页栏”的格单元实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:id = "@+id/LinearLayout01"
android:layout_width = "fill_parent"
android:background = "#555555"
android:layout_height = "wrap_content" >
< TextView
android:id = "@+id/ItemText"
android:layout_below = "@+id/ItemImage"
android:text = "TextView01"
android:bufferType = "normal"
android:singleLine = "true"
android:background = "#000000"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
android:layout_margin = "1dip"
android:layout_gravity = "center"
/>
</ LinearLayout >
|
main.xml的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:id = "@+id/MainLinearLayout" >
< Button
android:id = "@+id/btnCreateDB"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:text = "创建数据库"
/>
< Button
android:id = "@+id/btnInsertRec"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:text = "插入一串实验数据"
/>
< Button
android:id = "@+id/btnClose"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:text = "关闭数据库"
/>
</ LinearLayout >
|
演示程序testSQLite.java的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package com.testSQLite;
import android.app.Activity;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
public class testSQLite extends Activity {
GVTable table;
Button btnCreateDB, btnInsert, btnClose;
SQLiteDatabase db;
int id; // 添加记录时的id累加标记,必须全局
private static final String TABLE_NAME = "stu" ;
private static final String ID = "id" ;
private static final String NAME = "name" ;
private static final String PHONE = "phone" ;
private static final String ADDRESS = "address" ;
private static final String AGE = "age" ;
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
btnCreateDB = (Button) this .findViewById(R.id.btnCreateDB);
btnCreateDB.setOnClickListener( new ClickEvent());
btnInsert = (Button) this .findViewById(R.id.btnInsertRec);
btnInsert.setOnClickListener( new ClickEvent());
btnClose = (Button) this .findViewById(R.id.btnClose);
btnClose.setOnClickListener( new ClickEvent());
table = new GVTable( this );
table.gvSetTableRowCount( 8 ); // 设置每个分页的ROW总数
LinearLayout ly = (LinearLayout) findViewById(R.id.MainLinearLayout);
table.setTableOnClickListener( new GVTable.OnTableClickListener() {
@Override
public void onTableClickListener( int x, int y, Cursor c) {
c.moveToPosition(y);
String str = c.getString(x) + " 位置:(" + String.valueOf(x) + ","
+ String.valueOf(y) + ")" ;
Toast.makeText(testSQLite. this , str, 1000 ).show();
}
});
table.setOnPageSwitchListener( new GVTable.OnPageSwitchListener() {
@Override
public void onPageSwitchListener( int pageID, int pageCount) {
String str = "共有" + String.valueOf(pageCount) + " 当前第"
+ String.valueOf(pageID) + "页" ;
Toast.makeText(testSQLite. this , str, 1000 ).show();
}
});
ly.addView(table);
}
class ClickEvent implements View.OnClickListener {
@Override
public void onClick(View v) {
if (v == btnCreateDB) {
CreateDB();
} else if (v == btnInsert) {
InsertRecord( 16 ); // 插入16条记录
table.gvUpdatePageBar( "select count(*) from " + TABLE_NAME, db);
table.gvReadyTable( "select * from " + TABLE_NAME, db);
} else if (v == btnClose) {
table.gvRemoveAll();
db.close();
}
}
}
/**
* 在内存创建数据库和数据表
*/
void CreateDB() {
// 在内存创建数据库
db = SQLiteDatabase.create( null );
Log.e( "DB Path" , db.getPath());
String amount = String.valueOf(databaseList().length);
Log.e( "DB amount" , amount);
// 创建数据表
String sql = "CREATE TABLE " + TABLE_NAME + " (" + ID
+ " text not null, " + NAME + " text not null," + ADDRESS
+ " text not null, " + PHONE + " text not null," + AGE
+ " text not null " + ");" ;
try {
db.execSQL( "DROP TABLE IF EXISTS " + TABLE_NAME);
db.execSQL(sql);
} catch (SQLException e) {
}
}
/**
* 插入N条数据
*/
void InsertRecord( int n) {
int total = id + n;
for (; id < total; id++) {
String sql = "insert into " + TABLE_NAME + " (" + ID + ", " + NAME
+ ", " + ADDRESS + ", " + PHONE + ", " + AGE + ") values('"
+ String.valueOf(id)
+ "', 'man','address','123456789','18');" ;
try {
db.execSQL(sql);
} catch (SQLException e) {
}
}
}
}
|
分页表格控件GVTable.java的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
package com.testSQLite;
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;
public class GVTable extends LinearLayout {
protected GridView gvTable, gvPage;
protected SimpleAdapter saPageID, saTable; // 适配器
protected ArrayList<HashMap<String, String>> srcPageID, srcTable; // 数据源
protected int TableRowCount = 10 ; // 分页时,每页的Row总数
protected int TableColCount = 0 ; // 每页col的数量
protected SQLiteDatabase db;
protected String rawSQL = "" ;
protected Cursor curTable; // 分页时使用的Cursor
protected OnTableClickListener clickListener; // 整个分页控件被点击时的回调函数
protected OnPageSwitchListener switchListener; // 分页切换时的回调函数
public GVTable(Context context) {
super (context);
this .setOrientation(VERTICAL); // 垂直
// ----------------------------------------
gvTable = new GridView(context);
addView(gvTable, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); // 宽长式样
srcTable = new ArrayList<HashMap<String, String>>();
saTable = new SimpleAdapter(context, srcTable, // 数据来源
R.layout.items, // XML实现
new String[] { "ItemText" }, // 动态数组与ImageItem对应的子项
new int [] { R.id.ItemText });
// 添加并且显示
gvTable.setAdapter(saTable);
gvTable.setOnItemClickListener( new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
int y = arg2 / curTable.getColumnCount() - 1 ; // 标题栏的不算
int x = arg2 % curTable.getColumnCount();
if (clickListener != null // 分页数据被点击
&& y != - 1 ) { // 点中的不是标题栏时
clickListener.onTableClickListener(x, y, curTable);
}
}
});
// ----------------------------------------
gvPage = new GridView(context);
gvPage.setColumnWidth( 40 ); // 设置每个分页按钮的宽度
gvPage.setNumColumns(GridView.AUTO_FIT); // 分页按钮数量自动设置
addView(gvPage, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT)); // 宽长式样
srcPageID = new ArrayList<HashMap<String, String>>();
saPageID = new SimpleAdapter(context, srcPageID, // 数据来源
R.layout.items, // XML实现
new String[] { "ItemText" }, // 动态数组与ImageItem对应的子项
new int [] { R.id.ItemText });
// 添加并且显示
gvPage.setAdapter(saPageID);
// 添加消息处理
gvPage.setOnItemClickListener( new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
LoadTable(arg2); // 根据所选分页读取对应的数据
if (switchListener != null ) { // 分页切换时
switchListener.onPageSwitchListener(arg2, srcPageID.size());
}
}
});
}
/**
* 清除所有数据
*/
public void gvRemoveAll() {
if ( this .curTable != null )
curTable.close();
srcTable.clear();
saTable.notifyDataSetChanged();
srcPageID.clear();
saPageID.notifyDataSetChanged();
}
/**
* 读取指定ID的分页数据,返回当前页的总数据 SQL:Select * From TABLE_NAME Limit 9 Offset 10;
* 表示从TABLE_NAME表获取数据,跳过10行,取9行
*
* @param pageID
* 指定的分页ID
*/
protected void LoadTable( int pageID) {
if (curTable != null ) // 释放上次的数据
curTable.close();
String sql = rawSQL + " Limit " + String.valueOf(TableRowCount)
+ " Offset " + String.valueOf(pageID * TableRowCount);
curTable = db.rawQuery(sql, null );
gvTable.setNumColumns(curTable.getColumnCount()); // 表现为表格的关键点!
TableColCount = curTable.getColumnCount();
srcTable.clear();
// 取得字段名称
int colCount = curTable.getColumnCount();
for ( int i = 0 ; i < colCount; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put( "ItemText" , curTable.getColumnName(i));
srcTable.add(map);
}
// 列举出所有数据
int recCount = curTable.getCount();
for ( int i = 0 ; i < recCount; i++) { // 定位到一条数据
curTable.moveToPosition(i);
for ( int ii = 0 ; ii < colCount; ii++) // 定位到一条数据中的每个字段
{
HashMap<String, String> map = new HashMap<String, String>();
map.put( "ItemText" , curTable.getString(ii));
srcTable.add(map);
}
}
saTable.notifyDataSetChanged();
}
/**
* 设置表格的最多显示的行数
*
* @param row
* 表格的行数
*/
public void gvSetTableRowCount( int row) {
TableRowCount = row;
}
/**
* 取得表格的最大行数
*
* @return 行数
*/
public int gvGetTableRowCount() {
return TableRowCount;
}
/**
* 取得当前分页的Cursor
*
* @return 当前分页的Cursor
*/
public Cursor gvGetCurrentTable() {
return curTable;
}
/**
* 准备分页显示数据
*
* @param rawSQL
* sql语句
* @param db
* 数据库
*/
public void gvReadyTable(String rawSQL, SQLiteDatabase db) {
this .rawSQL = rawSQL;
this .db = db;
}
/**
* 刷新分页栏,更新按钮数量
*
* @param sql
* SQL语句
* @param db
* 数据库
*/
public void gvUpdatePageBar(String sql, SQLiteDatabase db) {
Cursor rec = db.rawQuery(sql, null );
rec.moveToLast();
long recSize = rec.getLong( 0 ); // 取得总数
rec.close();
int pageNum = ( int ) (recSize / TableRowCount) + 1 ; // 取得分页数
srcPageID.clear();
for ( int i = 0 ; i < pageNum; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put( "ItemText" , "No." + String.valueOf(i)); // 添加图像资源的ID
srcPageID.add(map);
}
saPageID.notifyDataSetChanged();
}
// ---------------------------------------------------------
/**
* 表格被点击时的回调函数
*/
public void setTableOnClickListener(OnTableClickListener click) {
this .clickListener = click;
}
public interface OnTableClickListener {
public void onTableClickListener( int x, int y, Cursor c);
}
// ---------------------------------------------------------
/**
* 分页栏被点击时的回调函数
*/
public void setOnPageSwitchListener(OnPageSwitchListener pageSwitch) {
this .switchListener = pageSwitch;
}
public interface OnPageSwitchListener {
public void onPageSwitchListener( int pageID, int pageCount);
}
}
|