2017年8月15日更新
升級版 TableLayout
針對簡友的反饋嗽元,在TableView的基礎(chǔ)上做了一些小的提升:
- 內(nèi)容超出屏幕范圍可以滑動顯示
- 單元格可被選中
在編輯模式下預(yù)覽,可以看出修改不同屬性產(chǎn)生的變化
編輯模式預(yù)覽
屬性表
attr | meaning | defaultValue | 備注 |
---|---|---|---|
tableRowHeight | 單元格的高度 | 36dp | |
tableDividerSize | 分割線大小 | 1px | |
tableDividerColor | 分割線顏色 | Color.GRAY | |
tableColumnPadding | 單元格左右padding | 0 | |
tableTextGravity | 單元格對齊方式 | center | 可選center/leftCenter/rightCenter |
tableTextSize | 字體大小 | 12dp | |
tableTextColor | 文字顏色 | Color.GRAY | |
tableTextColorSelected | 選中后文字顏色 | Color.BLACK | |
backgroundColorSelected | 單元格選中后的背景色 | Color.TRANSPARENT |
使用方法
- 在GitHub上檢出此項目肮砾,將tableLayout這個library module導(dǎo)入到項目中掂林,并在application module中添加對tableLayout的依賴
dependencies {
compile project(':tableLayout')
}
- 在xml中定義表格基礎(chǔ)樣式
<win.smartown.android.library.tableLayout.TableLayout
android:id="@+id/main_table"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:backgroundColorSelected="@color/colorAccent"
app:tableColumnPadding="32dp"
app:tableDividerColor="#ddd"
app:tableDividerSize="1px"
app:tableRowHeight="48dp"
app:tableTextColor="#333"
app:tableTextColorSelected="#fff"
app:tableTextSize="14dp" />
- 在Java代碼中填充展示數(shù)據(jù)
TableLayout tableLayout = (TableLayout) findViewById(R.id.main_table);
contentList = new ArrayList<>();
contentList.add(new Content("姓名", "語文", "數(shù)學(xué)", "英語", "物理", "化學(xué)", "生物"));
contentList.add(new Content("張三", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
contentList.add(new Content("李四", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
contentList.add(new Content("王二", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
contentList.add(new Content("王尼瑪", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
contentList.add(new Content("張全蛋", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
contentList.add(new Content("趙鐵柱", newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber(), newRandomNumber()));
tableLayout.setAdapter(new TableAdapter() {
@Override
public int getColumnCount() {
return contentList.size();
}
@Override
public String[] getColumnContent(int position) {
return contentList.get(position).toArray();
}
});
- 現(xiàn)在運行就可以看到下圖的效果了
Demo
部分源碼分析
這里由內(nèi)而外的分析进宝,從基礎(chǔ)的單元開始恨搓。
-
win.smartown.android.library.tableLayout.TableColumn
這個類表示表格中的一列,比較關(guān)鍵的點在于根據(jù)填充到此列的數(shù)據(jù)來確定此列的寬度1.根據(jù)填充內(nèi)容確定一個單元格(TextView)顯示這些文本要占用的寬度:
// 計算出該TextView中文字的長度(像素) public static float measureTextViewWidth(TextView textView, String text) { // 得到使用該paint寫上text的時候,像素為多少 return textView.getPaint().measureText(text); }
2.遍歷此列中所有的單元格娜汁,得到最大單元格的寬度maxTextViewWidth 嫂易,將其作為此列的寬度
private void initContent() { int padding = callback.getTableLayout().getTableColumnPadding(); maxTextViewWidth = 0; ArrayList<TextView> textViews = new ArrayList<>(); for (String text : content) { TextView textView = new TextView(getContext()); textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, callback.getTableLayout().getTableTextSize()); textView.setTextColor(callback.getTableLayout().getTableTextColor()); maxTextViewWidth = Math.max(maxTextViewWidth, Util.measureTextViewWidth(textView, text)); textView.setGravity(getTextGravity(callback.getTableLayout().getTableTextGravity())); textView.setPadding(padding, 0, padding, 0); textView.setText(text); textViews.add(textView); } LayoutParams layoutParams = new LayoutParams((int) (padding * 2 + maxTextViewWidth), callback.getTableLayout().getTableRowHeight()); for (TextView textView : textViews) { addView(textView, layoutParams); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension((int) (callback.getTableLayout().getTableColumnPadding() * 2 + maxTextViewWidth), callback.getTableLayout().getTableRowHeight() * getChildCount()); }
-
win.smartown.android.library.tableLayout.TableLayout
TableLayout就是最終呈現(xiàn)的完整表格,實際上他就是多個TableColumn的組合掐禁,其主要負責(zé)整個表格的大小測量炬搭、分割線繪制和接受數(shù)據(jù)填充。
1.單元格大小測量@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = 0; int height = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); width += child.getMeasuredWidth(); height = Math.max(height, child.getMeasuredHeight()); } setMeasuredDimension(width, height); }
2.繪制分割線
在ViewGroup要重寫onDraw()穆桂,需要設(shè)置setWillNotDraw(false)宫盔,否者onDown()中的繪制不會生效,具體的分割線繪制參見TableLayout源碼的onDraw()享完;
3.數(shù)據(jù)的填充
public void setAdapter(TableAdapter adapter) { this.adapter = adapter; useAdapter(); } //設(shè)置adapter后灼芭,先清空原來的數(shù)據(jù),然后根據(jù)新數(shù)據(jù)添加TableColumn private void useAdapter() { removeAllViews(); int count = adapter.getColumnCount(); for (int i = 0; i < count; i++) { addView(new TableColumn(getContext(), adapter.getColumnContent(i), this)); } }
-
win.smartown.android.library.tableLayout.FreeScrollView
顧名思義般又,此類用來實現(xiàn)子View的自用滾動彼绷,當(dāng)子view大小超過FreeScrollView的大小,就可以拖動顯示超出的內(nèi)容
1.處理滾動@Override from GestureDetector (重寫GestureDetector 的onScroll()) public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { View view = getChildAt(0); int childHeight = view.getHeight(); int childWidth = view.getWidth(); int toX, toY; if (distanceX > 0) { if (childWidth > getWidth()) { if (getScrollX() + getWidth() >= childWidth) { toX = childWidth - getWidth(); } else { toX = (int) (getScrollX() + distanceX); } } else { toX = 0; } } else { if (getScrollX() + distanceX < 0) { toX = 0; } else { toX = (int) (getScrollX() + distanceX); } } if (distanceY > 0) { if (childHeight > getHeight()) { if (getScrollY() + getHeight() >= childHeight) { toY = childHeight - getHeight(); } else { toY = (int) (getScrollY() + distanceY); } } else { toY = 0; } } else { if (getScrollY() + distanceY < 0) { toY = 0; } else { toY = (int) (getScrollY() + distanceY); } } scrollTo(toX, toY); return false; }
2.處理點擊事件茴迁,達到選中效果
//由于FreeScrollView攔截了TouchEvent寄悯,所以要在FreeScrollView處理點擊事件, //通過計算坐標來定位點擊的是哪個單元格堕义,點擊處理順序: //FreeScrollView.onSingleTapUp() -> TableLayout.onClick() -> TableLayout.onClick() -> TableColumn.onClick() @Override from GestureDetector public boolean onSingleTapUp(MotionEvent e) { View view = getChildAt(0); if (view instanceof TableLayout) { ((TableLayout) view).onClick(e.getX() + getScrollX(), e.getY() + getScrollY()); } return false; }
Github
- TableLayout
-
TableView
TableView