From 46cd1fa1170444064f18d175db10268b30b9e858 Mon Sep 17 00:00:00 2001 From: "HandStar Co., Ltd" Date: Sat, 30 Jul 2011 15:19:47 +0800 Subject: [PATCH] import sources --- .classpath | 7 + .gitignore | 3 + .project | 33 ++ AndroidManifest.xml | 18 + README.markdown | 10 +- default.properties | 11 + proguard.cfg | 36 ++ res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes .../zpaged_hscroll_table_down_arrow.png | Bin 0 -> 1303 bytes .../zpaged_hscroll_table_left_arrow.png | Bin 0 -> 1337 bytes .../zpaged_hscroll_table_right_arrow.png | Bin 0 -> 1323 bytes .../zpaged_hscroll_table_up_arrow.png | Bin 0 -> 1292 bytes res/layout/demo.xml | 13 + res/layout/zpaged_hscroll_table.xml | 101 ++++ .../zpaged_hscroll_table_col_view_a.xml | 6 + .../zpaged_hscroll_table_col_view_b.xml | 6 + res/layout/zpaged_hscroll_table_fixed_row.xml | 7 + res/layout/zpaged_hscroll_table_head_view.xml | 6 + .../zpaged_hscroll_table_scrollable_row.xml | 7 + res/values/strings.xml | 5 + res/values/zpaged_hscroll_table_colors.xml | 4 + res/values/zpaged_hscroll_table_styles.xml | 44 ++ src/demo/DemoActivity.java | 99 ++++ src/info/zhangxing/ZPagedHScrollTable.java | 478 ++++++++++++++++++ .../ZPagedHScrollTableDataAdapter.java | 55 ++ src/info/zhangxing/ZPagedHScrollTableHSV.java | 76 +++ 28 files changed, 1024 insertions(+), 1 deletion(-) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 AndroidManifest.xml create mode 100644 default.properties create mode 100644 proguard.cfg create mode 100644 res/drawable-hdpi/icon.png create mode 100644 res/drawable-ldpi/icon.png create mode 100644 res/drawable-mdpi/icon.png create mode 100644 res/drawable/zpaged_hscroll_table_down_arrow.png create mode 100644 res/drawable/zpaged_hscroll_table_left_arrow.png create mode 100644 res/drawable/zpaged_hscroll_table_right_arrow.png create mode 100644 res/drawable/zpaged_hscroll_table_up_arrow.png create mode 100644 res/layout/demo.xml create mode 100644 res/layout/zpaged_hscroll_table.xml create mode 100644 res/layout/zpaged_hscroll_table_col_view_a.xml create mode 100644 res/layout/zpaged_hscroll_table_col_view_b.xml create mode 100644 res/layout/zpaged_hscroll_table_fixed_row.xml create mode 100644 res/layout/zpaged_hscroll_table_head_view.xml create mode 100644 res/layout/zpaged_hscroll_table_scrollable_row.xml create mode 100644 res/values/strings.xml create mode 100644 res/values/zpaged_hscroll_table_colors.xml create mode 100644 res/values/zpaged_hscroll_table_styles.xml create mode 100644 src/demo/DemoActivity.java create mode 100644 src/info/zhangxing/ZPagedHScrollTable.java create mode 100644 src/info/zhangxing/ZPagedHScrollTableDataAdapter.java create mode 100644 src/info/zhangxing/ZPagedHScrollTableHSV.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..609aa00 --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bdab58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +gen +bin/* + diff --git a/.project b/.project new file mode 100644 index 0000000..1f3d24e --- /dev/null +++ b/.project @@ -0,0 +1,33 @@ + + + ZPagedHScrollTable + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..11c5b79 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.markdown b/README.markdown index 0314a3b..ba2ee2a 100644 --- a/README.markdown +++ b/README.markdown @@ -2,9 +2,17 @@ ZPagedHScrollTable 是一个 Android 表格控件, 具备手势翻页功能, 并能支持对总宽度大于展现区域的数据列进行横向滚动, 实现移动设备上对大数据集的直观展示. +# 使用方法 + +1. 在界面 Layout XML 中添加 Custom & Library Views 组中的 ZPagedHScrollTable 控件 +1. 实现 ZPagedHScrollTableDataAdapter 数据适配器接口,完成其中各个数据获取回调方法 +1. 设置 ZPagedHScrollTable 控件的每页显示记录数和数据适配器对象,并调用其 refreshTable 方法完成内容显示. 后续翻页时, 控件会自行调用数据适配器完成数据加载, 不需要主控程序干预. + +demo/ 目录下为一个实际的例子, 可供参考. + # 授权信息 - 本项目为 BSD 授权. 以下为正式的授权说明文本: +本项目为 BSD 授权. 以下为正式的授权说明文本: Copyright (C) 2011 HandStar Co., Ltd. ( http://zhangxing.info ). All rights reserved. diff --git a/default.properties b/default.properties new file mode 100644 index 0000000..e2e8061 --- /dev/null +++ b/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-8 diff --git a/proguard.cfg b/proguard.cfg new file mode 100644 index 0000000..12dd039 --- /dev/null +++ b/proguard.cfg @@ -0,0 +1,36 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c GIT binary patch literal 1723 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 N002ovPDHLkV1i*UWzhft literal 0 HcmV?d00001 diff --git a/res/drawable/zpaged_hscroll_table_left_arrow.png b/res/drawable/zpaged_hscroll_table_left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e1f2ff358e82cd19ac58bdbf5b010822fd51ed GIT binary patch literal 1337 zcmV-91;+Y`P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipe+ z5GoUFDU4$P000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000D(Nkl1V21^Pv?n>4J9AH-bMAAWd+soU zuJ_n&svO39-#=J=ibj6dgbAJZZOg7aTd#%d+g= z;EJN)$`6@(BF zLZB$hj_2+e@1hqE?hiUdkGm(HoLygkkMYNk+m^gborz$(J@@coq-SL8J5LC~OZQ8R z4FAyypbY@n*}wjV^T~8qVnvD7@_Ie0t52c5{VU|>NcL4zR{JE=H zk|f(++-7H6P*-0M`{~o*I1ZFj5Jfp~AJ!xZp80v(@sbnGoX72HQ7MI{4oacd>rq^C z0u7CgC_YhwIJtsEglAcOz_l9P2XnM~k$eqT-# z56KSAgK8TajYP1qu_16Q%LWM{9|3^-r5iWCyMe~W2Ar#_gV~&_fvKtr-^v>V0s)PV zM0@Ld3t5)85~!e*204?-B>MgSvUt#f=)tWYf57tcG8&qi@JUe-03a0Fz`eV_Vsc^v z*rgVRVGs-i5DJArDFwqa;CWu;^78X0T`pHyqP$|UDDL$2!R2zn(b|fdvu8jlh0o`M zD2fM4k>fa|q@*A%Ep3u3DJ|`P@L;Gj91499=$xL$l6MgcqKN968pyJYXf%2txWRA; z1qJyKjK+ShqN-}3w6xSYIx=FTdvwCrub1)t&6}8-`V*2QAsUVB$$8vLKP^LfMTJwZ z*AH-6Sy^cQthxKe-0bazg@r^WwNWGz!Pw~7RzGJx&`G>Q78Vxb!si!othl(FVOVes z!{Y3@bG;t7`}(zO-*#>UgZRHjDTO6F8(&|(jEbtN>pY**tMzl9PeFS}$5lc|=FdOf za)_b`y3b`1=R0x!=+UG2=E@aZZ2j^s&+}Kci726(zYB(N`yw#HXEu>*Py3r#`T-2=w-^5cx8|Sn+2zS000000NkvXXu0mjfM0sPw literal 0 HcmV?d00001 diff --git a/res/drawable/zpaged_hscroll_table_right_arrow.png b/res/drawable/zpaged_hscroll_table_right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..43695482921f56ed8f8da897256f4fe5480e094b GIT binary patch literal 1323 zcmV+`1=RY9P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipe+ z5GgG2V)C5;000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000DrNklvuP9AQFziU@&fS+P0l#$!+F=WFm>)o}N}m zY3Wc+ZEY82Oo#8$qc-3^ z3jt_a9632Tdx8ss09%O-j#39o>~`Gl?#ACUGhj@|*1Jw6lbH1R>S;I}u8hTE;CUXD zQb>{nQId8#gE3gGRuDpvn`^>{7cZj3ZpVPzjr;e85RI;9oMJJsSV>h?wKJVz-@bhi z1OXRnYVg7N^I0{QBni2>rgX+x=7go700#~nK!5)LmV-;sbsYepD2kmDLPVbD!1Fu= zK|q1E0M4?q*RmcV9L#1j>Ki^nvCW1bfA}7AvvV7Nxh_(Z$rQ~o81i_Y2hZ~$AYe@2 z6)an*stQF>5RWIoaU2LC;CVhuEf$O4Y?dpQgF$c{2Sr(fe|C0@=4?}Ph?0cDqN0o@ zfxrR=-ENEwk6?X$9h6c4fYE65Q-jgyaXOt9Gf!raN~JI~G=$;d;hl=>4DXydgXT|L zAc_*=@i?ZZCNa?8kLk%NXqpCo0~i3Tg@qnUDebMOaJBaL4f<)_X+K$B4vzcJHM_0A;v#O|yoIr`KcH$FD5X1UD5Y?ndb|DT z@nhI*+jXw`{m$T0uyuZ6eplw9)m1RYG9=hubLjA)&Z@I#yYlk(zZ$u^u4Cfi!|uCx ze{Xp9^jX?1dyU?$HM*|DYAw87d$IOXWmOd@rJ0WfV>%`tj(6O@cdym&_rLy3Cj`aC z#humF)mKlQKApDXjyF`-bu7%!H~#7Iw9Pzz>{?S4q*AG^NNL7`Kp{zz_sye6+s{;0 zbsa7)P6Gn~aZf5)$>_-hqM@gCtBbSst1E%Zm(dsYL?R)AAu0&eZ#3n3@(U04<{xzQ h?YABRCm45N{0r~RAjsB4I*b4S002ovPDHLkV1iy%W10W} literal 0 HcmV?d00001 diff --git a/res/drawable/zpaged_hscroll_table_up_arrow.png b/res/drawable/zpaged_hscroll_table_up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..f124616c53c6cfe8d2a2ba6f16ee6a7d533ec6b5 GIT binary patch literal 1292 zcmV+n1@roeP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipe+ z5Gfiy*k=R)000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000DMNklh3*&k;|1A%}eo5?_yW$-)?j^hp&W1xgURnySqo6 zotdNZyy}S2n z1wj~W@95a8Inem$yFZOj-J107BobwMprhW@fNP(8iUF?|27>|63*{t)U~Mhx_51zf zE0M?{csLv$x^?sBa3~Zi0VV`c6aze-9yr?1;lg`PbY1L%D2gSylu|?@k>R-~Plj?@ z5;T{~;lcg;qmLgyf}UqXj(}5qaK(+wZZ{a?p(w}D-P;R$TWi@HLf5hU{Q2nC+A3%) zw%PaSmxqp>ot?7D%`GkH>FtH8R^|6CmbcO4@xWxNKSJm*;_#$XuHXkJ5^*rb z(CKo)Y_Sx`LkNMUWvq-4qU4)#SdLgMhHs{(!1Fw6Yin`UJAisq0{|fU`ZatrK4kVu zrPJvmaymeuuqste2!c?VN~Mk@5d0YoVs&K|qA0>@wc<**8}+7r*6}!gotr~Co!-|4~lL?jDec(IINFbL>-!|Gs}EoSt1JQJtv_AkR5yM<ZAP9vv$8iuu5k^(TJ7><|(&hIjthUAxN@?EaSg~%BB#)f3+aG9}HhSVj zjUyb6Ael@;&*|Ve3Q>|^G^%K7YQovG4%nKS7G+r;18}>f2j$%VV1A_2>Aplf-oLrI z=}e_kRziqkFc=awH8mkgmggB`K1#XSa`pbDZTt&M?z=%AoEnG#0000 + + + + + + + diff --git a/res/layout/zpaged_hscroll_table.xml b/res/layout/zpaged_hscroll_table.xml new file mode 100644 index 0000000..d87a41b --- /dev/null +++ b/res/layout/zpaged_hscroll_table.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/zpaged_hscroll_table_col_view_a.xml b/res/layout/zpaged_hscroll_table_col_view_a.xml new file mode 100644 index 0000000..c91fe46 --- /dev/null +++ b/res/layout/zpaged_hscroll_table_col_view_a.xml @@ -0,0 +1,6 @@ + + + + diff --git a/res/layout/zpaged_hscroll_table_col_view_b.xml b/res/layout/zpaged_hscroll_table_col_view_b.xml new file mode 100644 index 0000000..ad8253d --- /dev/null +++ b/res/layout/zpaged_hscroll_table_col_view_b.xml @@ -0,0 +1,6 @@ + + + + diff --git a/res/layout/zpaged_hscroll_table_fixed_row.xml b/res/layout/zpaged_hscroll_table_fixed_row.xml new file mode 100644 index 0000000..206e804 --- /dev/null +++ b/res/layout/zpaged_hscroll_table_fixed_row.xml @@ -0,0 +1,7 @@ + + + + diff --git a/res/layout/zpaged_hscroll_table_head_view.xml b/res/layout/zpaged_hscroll_table_head_view.xml new file mode 100644 index 0000000..7ca2494 --- /dev/null +++ b/res/layout/zpaged_hscroll_table_head_view.xml @@ -0,0 +1,6 @@ + + + + diff --git a/res/layout/zpaged_hscroll_table_scrollable_row.xml b/res/layout/zpaged_hscroll_table_scrollable_row.xml new file mode 100644 index 0000000..8f25406 --- /dev/null +++ b/res/layout/zpaged_hscroll_table_scrollable_row.xml @@ -0,0 +1,7 @@ + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..91bd4cb --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World, ZPagedHScrollTableActivity! + ZPagedHScrollTable + diff --git a/res/values/zpaged_hscroll_table_colors.xml b/res/values/zpaged_hscroll_table_colors.xml new file mode 100644 index 0000000..f606df7 --- /dev/null +++ b/res/values/zpaged_hscroll_table_colors.xml @@ -0,0 +1,4 @@ + + + #ffcfe1f5 + diff --git a/res/values/zpaged_hscroll_table_styles.xml b/res/values/zpaged_hscroll_table_styles.xml new file mode 100644 index 0000000..b70bd82 --- /dev/null +++ b/res/values/zpaged_hscroll_table_styles.xml @@ -0,0 +1,44 @@ + + + + + + diff --git a/src/demo/DemoActivity.java b/src/demo/DemoActivity.java new file mode 100644 index 0000000..4a07a29 --- /dev/null +++ b/src/demo/DemoActivity.java @@ -0,0 +1,99 @@ +package demo; + +import info.zhangxing.R; +import info.zhangxing.ZPagedHScrollTable; +import info.zhangxing.ZPagedHScrollTableDataAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Toast; + +public class DemoActivity extends Activity { + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.demo); + + ZPagedHScrollTable pht = (ZPagedHScrollTable) findViewById(R.id.pagedHScrollTable1); + pht.setPageSize(10); // 设置每页展现记录数 + pht.setAdapter(new DataAdaptor()); + + // 刷新表格,展现数据 + pht.refreshTable(); + } + + class DataAdaptor implements ZPagedHScrollTableDataAdapter { + + Map colHeaders; + + { + colHeaders = new HashMap(); + colHeaders.put(ZPagedHScrollTableDataAdapter.FIXED_COLUMN, + new String[] { "固定列A", "固定列B" }); + colHeaders.put(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN, + new String[] { "滑动列A1", "滑动列B1", "滑动列C1", "滑动列A2", "滑动列B2", + "滑动列C2", "滑动列A3", "滑动列B3", "滑动列C3" }); + } + + @Override + public Map getColHeaders() { + return colHeaders; + } + + @Override + public int getTotalRows() { + // 整个数据集共30行 + return 30; + } + + @Override + public List>> getRows(int startRow, int endRow) { + List>> rows = new ArrayList>>(); + for (int i = startRow; i <= endRow; ++i) { + Map> row = new HashMap>(); + + List fCols = new ArrayList(); + fCols.add("固定列A数据" + i); + fCols.add("固定列B数据" + i); + row.put(ZPagedHScrollTableDataAdapter.FIXED_COLUMN, fCols); + + List sCols = new ArrayList(); + for (int j = 0; j < 9; ++j) { + sCols.add("滑动列" + j + "数据" + i); + } + row.put(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN, sCols); + + rows.add(row); + } + + // 模拟数据获取延迟 + try { + Thread.sleep(200); + } catch (Exception e) { + } + + return rows; + } + + @Override + public OnClickListener getOnClickListener(final int row) { + return new OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(DemoActivity.this, "你点击了第" + row + "行", + Toast.LENGTH_SHORT).show(); + } + }; + } + + } +} diff --git a/src/info/zhangxing/ZPagedHScrollTable.java b/src/info/zhangxing/ZPagedHScrollTable.java new file mode 100644 index 0000000..0cb9206 --- /dev/null +++ b/src/info/zhangxing/ZPagedHScrollTable.java @@ -0,0 +1,478 @@ +package info.zhangxing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.app.ProgressDialog; +import android.content.Context; +import android.graphics.Color; +import android.os.AsyncTask; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; +import android.widget.Toast; + +/** + * 带分页功能的可滚动列数据表格 + * + * FIXME: ProgressDialog 正在显示时若改变设备方向,会导致出错退出...目前只能在 AndroidManifest.xml 中设置 + * screen 保持特定方向(portrait/landscape) + * + * @author open@zhangxing.info + * + */ +public class ZPagedHScrollTable extends FrameLayout { + private static final float OFFSET_THRESHOLD_DP = 30.0f; // 判断上下翻页的位移阈值(单位dp) + + private float pixelPerDp; + private int pageSize = 10; // 表格每页显示记录条数,默认为 10 + private int totalNum = 0; // 待显示总记录条数 + private int startRow = 0; // 起始行号 + private int endRow = 0; // 结束行号 + private ZPagedHScrollTableDataAdapter adapter = null; // 使用方传入的数据适配器对象 + + private LayoutInflater layoutInflater; + private ImageView upIndicator; + private ImageView downIndicator; + private ImageView leftIndicator; + private ImageView rightIndicator; + + private float startX = 0.0f; + private float startY = 0.0f; + private float endX = 0.0f; + private float endY = 0.0f; + + /** + * 获取每页展现记录数 + * + * @return 当前设置的每页显示记录条数 + */ + public int getPageSize() { + return pageSize; + } + + /** + * 设置每页展现记录数 + * + * @param pageSize + * 每页展现记录数 + */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + /** + * 获取当前所用的表格数据适配器对象 + * + * @return 表格数据适配器对象 + */ + public ZPagedHScrollTableDataAdapter getAdapter() { + return adapter; + } + + /** + * 设置表格数据适配器对象 + * + * @param adapter + * 待使用的表格数据适配器对象 + */ + public void setAdapter(ZPagedHScrollTableDataAdapter adapter) { + this.adapter = adapter; + } + + /** + * 强制重置并刷新表格 + */ + public void refreshTable() { + new InitTableStruct().execute((Void[]) null); + } + + public ZPagedHScrollTable(Context context, AttributeSet attrs) { + super(context, attrs); + + // 当前设备屏幕 1 dp 对应的像素数 + pixelPerDp = getContext().getResources().getDisplayMetrics().density; + + init(context); + } + + private void init(Context context) { + // 从 Layout XML 文件中加载控件 + layoutInflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + layoutInflater.inflate(R.layout.zpaged_hscroll_table, this); + + upIndicator = (ImageView) findViewById(R.id.upIndicator); + downIndicator = (ImageView) findViewById(R.id.downIndicator); + leftIndicator = (ImageView) findViewById(R.id.leftIndicator); + rightIndicator = (ImageView) findViewById(R.id.rightIndicator); + + // 创建时表格总是位于首页,可滚动区域位于最左边,控件刚创建时没有内容,故隐藏对应方向的指示符 + upIndicator.setVisibility(INVISIBLE); + downIndicator.setVisibility(INVISIBLE); + + ZPagedHScrollTableHSV scrollableArea = (ZPagedHScrollTableHSV) findViewById(R.id.scrollableArea); + scrollableArea.setLeftIndicator(leftIndicator); + scrollableArea.setRightIndicator(rightIndicator); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + handleTouchEvent(ev); + return false; + } + + private class InitTableStruct extends AsyncTask { + ProgressDialog waitDiag; + + @Override + protected void onPreExecute() { + waitDiag = ProgressDialog.show(getContext(), "请稍等...", + "获取数据中,请稍等..."); + } + + @Override + protected PageData doInBackground(Void... params) { + totalNum = adapter.getTotalRows(); + + startRow = 0; + endRow = (totalNum < pageSize ? totalNum : pageSize) - 1; + + PageData pageData = new PageData(); + pageData.headData = adapter.getColHeaders(); + pageData.rowData = adapter.getRows(startRow, endRow); + pageData.rowOnClick = new ArrayList(); + + int dataSize = pageData.rowData.size(); + for (int i = 0; i < dataSize; ++i) { + pageData.rowOnClick.add(adapter + .getOnClickListener(startRow + i)); + } + endRow = startRow + dataSize - 1; + + return pageData; + } + + @Override + protected void onPostExecute(PageData pageData) { + // FIXME: 若不将表格背景色设为透明,在清空表格后会出现两条竖线,需要考虑有没有在 XML layout + // 文件中直接更改的方法... + TableLayout fixedTable = (TableLayout) findViewById(R.id.fixedTable); + TableLayout scrollableTable = (TableLayout) findViewById(R.id.scrollableTable); + fixedTable.setBackgroundColor(Color.argb(0, 0, 0, 0)); + scrollableTable.setBackgroundColor(Color.argb(0, 0, 0, 0)); + + setTableHead(pageData); + setTableData(pageData); + + fixedTable + .setBackgroundResource(R.color.zPagedHScrollTableBorderColor); + scrollableTable + .setBackgroundResource(R.color.zPagedHScrollTableBorderColor); + + waitDiag.dismiss(); + } + + } + + private class ShowPage extends AsyncTask { + ProgressDialog waitDiag; + + @Override + protected void onPreExecute() { + waitDiag = ProgressDialog.show(getContext(), "请稍候...", "获取数据中..."); + } + + @Override + protected PageData doInBackground(Void... params) { + PageData pageData = new PageData(); + pageData.headData = adapter.getColHeaders(); + pageData.rowData = adapter.getRows(startRow, endRow); + pageData.rowOnClick = new ArrayList(); + + int dataSize = pageData.rowData.size(); + for (int i = 0; i < dataSize; ++i) { + pageData.rowOnClick.add(adapter + .getOnClickListener(startRow + i)); + } + endRow = startRow + dataSize - 1; + + return pageData; + } + + @Override + protected void onPostExecute(PageData result) { + setTableData(result); + waitDiag.dismiss(); + } + + } + + private void clearHeadRow() { + int[] tables = { R.id.fixedTable, R.id.scrollableTable }; + for (int id : tables) { + TableLayout table = (TableLayout) findViewById(id); + // 清空表头 + TableRow headRow = (TableRow) table.getChildAt(0); + headRow.removeAllViews(); + } + } + + private void clearDataRow() { + int[] tables = { R.id.fixedTable, R.id.scrollableTable }; + for (int id : tables) { + TableLayout table = (TableLayout) findViewById(id); + // 删除除表头以外的所有数据行 + ArrayList rows = new ArrayList(); + for (int i = 1; i < table.getChildCount(); ++i) { + rows.add(table.getChildAt(i)); + } + for (View row : rows) { + table.removeView(row); + } + } + } + + private void setTableHead(PageData pageData) { + clearHeadRow(); + + Map colHeaders = pageData.headData; + TableRow fixedColHeadRow = (TableRow) findViewById(R.id.fixedColHeadRow); + boolean firstCol = true; + for (String colHead : colHeaders + .get(ZPagedHScrollTableDataAdapter.FIXED_COLUMN)) { + // 填充固定列表头 + TextView head = (TextView) layoutInflater.inflate( + R.layout.zpaged_hscroll_table_head_view, null); + head.setText(colHead); + + TableRow.LayoutParams layoutParams = new TableRow.LayoutParams( + TableRow.LayoutParams.FILL_PARENT, + TableRow.LayoutParams.FILL_PARENT, 1.0f); + + if (firstCol) { + firstCol = false; + layoutParams.setMargins(0, 0, 0, 0); + } else { + layoutParams.setMargins(d2p(1), 0, 0, 0); + } + head.setLayoutParams(layoutParams); + + fixedColHeadRow.addView(head); + } + + TableRow scrollableColHeadRow = (TableRow) findViewById(R.id.scrollableColHeadRow); + firstCol = true; + for (String colHead : colHeaders + .get(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN)) { + TextView head = (TextView) layoutInflater.inflate( + R.layout.zpaged_hscroll_table_head_view, null); + head.setText(colHead); + + TableRow.LayoutParams layoutParams = new TableRow.LayoutParams( + TableRow.LayoutParams.FILL_PARENT, + TableRow.LayoutParams.FILL_PARENT, 1.0f); + if (firstCol) { + firstCol = false; + layoutParams.setMargins(0, 0, 0, 0); + } else { + layoutParams.setMargins(d2p(1), 0, 0, 0); + } + head.setLayoutParams(layoutParams); + + scrollableColHeadRow.addView(head); + } + } + + private void setTableData(PageData pageData) { + clearDataRow(); + if (startRow > 0) { + upIndicator.setVisibility(VISIBLE); + } else { + upIndicator.setVisibility(INVISIBLE); + } + if (endRow < totalNum - 1) { + downIndicator.setVisibility(VISIBLE); + } else { + downIndicator.setVisibility(INVISIBLE); + } + + int[] layoutIds = { R.layout.zpaged_hscroll_table_fixed_row, + R.layout.zpaged_hscroll_table_scrollable_row }; + Integer[] colTypes = { ZPagedHScrollTableDataAdapter.FIXED_COLUMN, + ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN }; + TableLayout[] tables = { (TableLayout) findViewById(R.id.fixedTable), + (TableLayout) findViewById(R.id.scrollableTable) }; + + // 准备表格填充空行数据 + Map> dummyRow = new HashMap>(); + String[] fHead = pageData.headData + .get(ZPagedHScrollTableDataAdapter.FIXED_COLUMN); + String[] sHead = pageData.headData + .get(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN); + if (fHead != null) { + dummyRow.put(ZPagedHScrollTableDataAdapter.FIXED_COLUMN, + Arrays.asList(fHead)); + } else { + dummyRow.put(ZPagedHScrollTableDataAdapter.FIXED_COLUMN, null); + } + if (sHead != null) { + dummyRow.put(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN, + Arrays.asList(sHead)); + } else { + dummyRow.put(ZPagedHScrollTableDataAdapter.SCROLLABLE_COLUMN, null); + } + + int actualDataSize = pageData.rowData.size(); + boolean isRowA = true; + for (int i = 0; i < pageSize; ++i) { + Map> rowData = null; + if (i < actualDataSize) { + rowData = pageData.rowData.get(i); + } else { + rowData = dummyRow; + } + + // 顺序填充固定列和滑动列数据 + for (int areaId = 0; areaId < layoutIds.length; ++areaId) { + List cols = rowData.get(colTypes[areaId]); + + TableRow rowLayout = (TableRow) layoutInflater.inflate( + layoutIds[areaId], null); + TableLayout.LayoutParams rowLayoutParams = new TableLayout.LayoutParams( + TableLayout.LayoutParams.WRAP_CONTENT, + TableLayout.LayoutParams.FILL_PARENT, 1.0f); + if (colTypes[areaId] == ZPagedHScrollTableDataAdapter.FIXED_COLUMN) { + // 固定列数据行布局属性 + rowLayoutParams.setMargins(d2p(1), 0, d2p(1), d2p(1)); + } else { + // 滑动列数据行布局属性 + rowLayoutParams.setMargins(0, 0, d2p(1), d2p(1)); + + } + rowLayout.setLayoutParams(rowLayoutParams); + + boolean firstCol = true; + for (String col : cols) { + TextView cell = null; + + // 以不同的配色分隔相邻行 + if (isRowA) { + cell = (TextView) layoutInflater.inflate( + R.layout.zpaged_hscroll_table_col_view_a, null); + } else { + cell = (TextView) layoutInflater.inflate( + R.layout.zpaged_hscroll_table_col_view_b, null); + } + cell.setText(col); + // XXX: 让超出列宽的文本开始走马灯动画展示 + cell.setSelected(true); + // 隐藏超过有效数据行范围的填充文本 + if (i >= actualDataSize) { + cell.setTextColor(Color.argb(0, 0, 0, 0)); + } + + TableRow.LayoutParams layoutParams = new TableRow.LayoutParams( + TableRow.LayoutParams.WRAP_CONTENT, + TableRow.LayoutParams.FILL_PARENT, 1.0f); + if (firstCol) { + firstCol = false; + layoutParams.setMargins(0, 0, 0, 0); + } else { + layoutParams.setMargins(d2p(1), 0, 0, 0); + } + cell.setLayoutParams(layoutParams); + + rowLayout.addView(cell); + } + + // 为有效数据行范围内的行添加点击处理器 + if (i < actualDataSize) { + rowLayout.setOnClickListener(pageData.rowOnClick.get(i)); + } else { + // XXX: 空白区域的 TableRow 也必须有 OnClickListener,才能正常识别固定列向上翻页动作 + rowLayout.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + } + }); + } + + tables[areaId].addView(rowLayout); + } + + // 切换行背景配色 + isRowA = !isRowA; + } + } + + private void handleTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + startX = endX = event.getX(); + startY = endY = event.getY(); + break; + case MotionEvent.ACTION_UP: + // Y 轴滑动速度高于阈值时触发上下翻页操作 + endX = event.getX(); + endY = event.getY(); + if (Math.abs(startX - endX) < Math.abs(startY - endY)) { + // X 轴位移没有 Y 轴位移大,若 Y 轴位移达到阈值则触发上下翻页操作 + float offY = endY - startY; + if (offY > d2p(OFFSET_THRESHOLD_DP)) { + doPageUp(); + } else if (offY < -d2p(OFFSET_THRESHOLD_DP)) { + doPageDown(); + } + } + break; + case MotionEvent.ACTION_CANCEL: + break; + } + } + + private void doPageDown() { + if (endRow >= 0 && endRow < totalNum - 1 && pageSize > 0) { + startRow = endRow + 1; + endRow += pageSize; + if (endRow > totalNum - 1) { + endRow = totalNum - 1; + } + new ShowPage().execute((Void[]) null); + } else { + String msg = "已经是最后一页"; + Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); + } + } + + private void doPageUp() { + if (startRow >= pageSize && pageSize > 0) { + endRow = startRow - 1; + startRow -= pageSize; + new ShowPage().execute((Void[]) null); + } else { + String msg = "已经是第一页"; + Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); + } + } + + private int d2p(float dp) { + return (int) (dp * pixelPerDp + 0.5); + } + + private class PageData { + public Map headData; + public List>> rowData; + public List rowOnClick; + } + +} diff --git a/src/info/zhangxing/ZPagedHScrollTableDataAdapter.java b/src/info/zhangxing/ZPagedHScrollTableDataAdapter.java new file mode 100644 index 0000000..30d6e58 --- /dev/null +++ b/src/info/zhangxing/ZPagedHScrollTableDataAdapter.java @@ -0,0 +1,55 @@ +package info.zhangxing; + +import java.util.List; +import java.util.Map; + +import android.view.View.OnClickListener; + +/** + * 数据适配器接口,用于获取待展现的数据内容 + * + * @author open@zhangxing.info + * + */ +public interface ZPagedHScrollTableDataAdapter { + final static Integer FIXED_COLUMN = 0; + final static Integer SCROLLABLE_COLUMN = 1; + + /** + * 获取列标题列表 + * + * @return 一个 HashMap,其中 FIXED_COLUMN 为键的列表是固定列标题数据;SCROLLABLE_COLUMN + * 为键的列表是滑动列数据。两个键必须都存在,对应列类型没有需要展现的列时应取值空数组。 + */ + Map getColHeaders(); + + /** + * 获取总数据行数 + * + * @return 总数据行数 + */ + int getTotalRows(); + + /** + * 获取指定范围内的记录数据 + * + * @param startRow + * 起始行号,从 0 开始计算 + * @param endRow + * 结束行号,从 0 开始计算 + * @return 包含若干行记录的列表,每行记录是一个 HashMap,其中 FIXED_COLUMN + * 为键的列表是固定列数据,顺序同固定列标题的顺序;SCROLLABLE_COLUMN + * 为键的列表是滑动列数据,顺序同滑动列标题的顺序。若数据少于要求的行号范围,则仅返回实际数量的数据。无数据时应返回一个空 List。 + */ + List>> getRows(final int startRow, + final int endRow); + + /** + * 获取指定行对应的点击事件处理对象 + * + * @param row + * 在整个数据集中的行号,并非当前页内的行号,从 0 开始计算 + * @return 点击事件处理对象,不需要处理点击事件时应返回 null + */ + OnClickListener getOnClickListener(final int row); +} diff --git a/src/info/zhangxing/ZPagedHScrollTableHSV.java b/src/info/zhangxing/ZPagedHScrollTableHSV.java new file mode 100644 index 0000000..f29f7bb --- /dev/null +++ b/src/info/zhangxing/ZPagedHScrollTableHSV.java @@ -0,0 +1,76 @@ +package info.zhangxing; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.HorizontalScrollView; + +/** + * 自定义横向滚动视图,可自动控制左右滚动指示控件显示与否 + * + * @author open@zhangxing.info + * + */ +public class ZPagedHScrollTableHSV extends HorizontalScrollView { + + View leftIndicator; + View rightIndicator; + + public ZPagedHScrollTableHSV(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setLeftIndicator(View leftIndicator) { + this.leftIndicator = leftIndicator; + } + + public void setRightIndicator(View rightIndicator) { + this.rightIndicator = rightIndicator; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (leftIndicator != null) { + leftIndicator.setVisibility(INVISIBLE); + } + + if (rightIndicator != null) { + if (getChildAt(0).getMeasuredWidth() <= getWidth()) { + rightIndicator.setVisibility(INVISIBLE); + } else { + rightIndicator.setVisibility(VISIBLE); + } + } + super.onLayout(changed, l, t, r, b); + } + + @Override + protected void onScrollChanged(final int l, final int t, final int oldl, + final int oldt) { + if (leftIndicator != null) { + if (l == 0) { + leftIndicator.setVisibility(INVISIBLE); + } else { + leftIndicator.setVisibility(VISIBLE); + } + } + + /* + * 对于横向 ScrollView,判断滚动到最右侧的标准为 LinearLayout.getMeasuredWidth() <= l + + * getWidth() + * + * 对于纵向 ScrollView,判断滚动到最底部的标准为 LinearLayout.getMeasuredHeight() <= t + + * getHeight() + */ + if (rightIndicator != null) { + if (getChildAt(0).getMeasuredWidth() <= l + getWidth()) { + rightIndicator.setVisibility(INVISIBLE); + } else { + rightIndicator.setVisibility(VISIBLE); + } + } + + super.onScrollChanged(l, t, oldl, oldt); + } + +}