大約一個星期前,我重新探討了這個問題,並提出了一個解決方案。該解決方案要求我爲這個網格中的列做很多手動寬度設置,並且我認爲在這個時代和這個時代是非常不相稱的。不幸的是,我也一直在尋找一種更適合Android平臺的更全面的解決方案,但我沒有做出任何改變。
以下是創建同一個網格的代碼,如果任何一個跟隨我需要它。我將在下面解釋一些更相關的細節!
佈局:grid.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/lightGrey">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="2dip"
android:layout_weight="1"
android:minHeight="100dip">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TableLayout
android:id="@+id/frozenTableHeader"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="2dip"
android:layout_marginLeft="1dip"
android:stretchColumns="1"
/>
<qvtcapital.mobile.controls.ObservableHorizontalScrollView
android:id="@+id/contentTableHeaderHorizontalScrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/frozenTableHeader"
android:layout_marginTop="2dip"
android:layout_marginLeft="4dip"
android:layout_marginRight="1dip">
<TableLayout
android:id="@+id/contentTableHeader"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"/>
</qvtcapital.mobile.controls.ObservableHorizontalScrollView>
</LinearLayout>
<ScrollView
android:id="@+id/verticalScrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TableLayout
android:id="@+id/frozenTable"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="2dip"
android:layout_marginLeft="1dip"
android:stretchColumns="1"
/>
<qvtcapital.mobile.controls.ObservableHorizontalScrollView
android:id="@+id/contentTableHorizontalScrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/frozenTable"
android:layout_marginTop="2dip"
android:layout_marginLeft="4dip"
android:layout_marginRight="1dip">
<TableLayout
android:id="@+id/contentTable"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"/>
</qvtcapital.mobile.controls.ObservableHorizontalScrollView>
</LinearLayout>
</ScrollView>
</TableLayout>
活性:Grid.java
:
public class ResultGrid extends Activity implements HorizontalScrollViewListener {
private TableLayout frozenHeaderTable;
private TableLayout contentHeaderTable;
private TableLayout frozenTable;
private TableLayout contentTable;
Typeface font;
float fontSize;
int cellWidthFactor;
ObservableHorizontalScrollView headerScrollView;
ObservableHorizontalScrollView contentScrollView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.result_grid);
font = Typeface.createFromAsset(getAssets(), "fonts/consola.ttf");
fontSize = 11; // Actually this is dynamic in my application, but that code is removed for clarity
final float scale = getBaseContext().getResources().getDisplayMetrics().density;
cellWidthFactor = (int) Math.ceil(fontSize * scale * (fontSize < 10 ? 0.9 : 0.7));
Button backButton = (Button)findViewById(R.id.backButton);
frozenTable = (TableLayout)findViewById(R.id.frozenTable);
contentTable = (TableLayout)findViewById(R.id.contentTable);
frozenHeaderTable = (TableLayout)findViewById(R.id.frozenTableHeader);
contentHeaderTable = (TableLayout)findViewById(R.id.contentTableHeader);
headerScrollView = (ObservableHorizontalScrollView) findViewById(R.id.contentTableHeaderHorizontalScrollView);
headerScrollView.setScrollViewListener(this);
contentScrollView = (ObservableHorizontalScrollView) findViewById(R.id.contentTableHorizontalScrollView);
contentScrollView.setScrollViewListener(this);
contentScrollView.setHorizontalScrollBarEnabled(false); // Only show the scroll bar on the header table (so that there aren't two)
backButton.setOnClickListener(backButtonClick);
InitializeInitialData();
}
protected void InitializeInitialData() {
ArrayList<String[]> content;
Bundle myBundle = getIntent().getExtras();
try {
content = (ArrayList<String[]>) myBundle.get("gridData");
} catch (Exception e) {
content = new ArrayList<String[]>();
content.add(new String[] {"Error", "There was an error parsing the result data, please try again"});
e.printStackTrace();
}
PopulateMainTable(content);
}
protected void PopulateMainTable(ArrayList<String[]> content) {
frozenTable.setBackgroundResource(R.color.tableBorder);
contentTable.setBackgroundResource(R.color.tableBorder);
TableLayout.LayoutParams frozenRowParams = new TableLayout.LayoutParams(
TableLayout.LayoutParams.WRAP_CONTENT,
TableLayout.LayoutParams.WRAP_CONTENT);
frozenRowParams.setMargins(1, 1, 1, 1);
frozenRowParams.weight=1;
TableLayout.LayoutParams tableRowParams = new TableLayout.LayoutParams(
TableLayout.LayoutParams.WRAP_CONTENT,
TableLayout.LayoutParams.WRAP_CONTENT);
tableRowParams.setMargins(0, 1, 1, 1);
tableRowParams.weight=1;
TableRow frozenTableHeaderRow=null;
TableRow contentTableHeaderRow=null;
int maxFrozenChars = 0;
int[] maxContentChars = new int[content.get(0).length-1];
for (int i = 0; i < content.size(); i++){
TableRow frozenRow = new TableRow(this);
frozenRow.setLayoutParams(frozenRowParams);
frozenRow.setBackgroundResource(R.color.tableRows);
TextView frozenCell = new TextView(this);
frozenCell.setText(content.get(i)[0]);
frozenCell.setTextColor(Color.parseColor("#FF000000"));
frozenCell.setPadding(5, 0, 5, 0);
if (0 == i) { frozenCell.setTypeface(font, Typeface.BOLD);
} else { frozenCell.setTypeface(font, Typeface.NORMAL); }
frozenCell.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize);
frozenRow.addView(frozenCell);
if (content.get(i)[0].length() > maxFrozenChars) {
maxFrozenChars = content.get(i)[0].length();
}
// The rest of them
TableRow row = new TableRow(this);
row.setLayoutParams(tableRowParams);
row.setBackgroundResource(R.color.tableRows);
for (int j = 1; j < content.get(0).length; j++) {
TextView rowCell = new TextView(this);
rowCell.setText(content.get(i)[j]);
rowCell.setPadding(10, 0, 0, 0);
rowCell.setGravity(Gravity.RIGHT);
rowCell.setTextColor(Color.parseColor("#FF000000"));
if (0 == i) { rowCell.setTypeface(font, Typeface.BOLD);
} else { rowCell.setTypeface(font, Typeface.NORMAL); }
rowCell.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize);
row.addView(rowCell);
if (content.get(i)[j].length() > maxContentChars[j-1]) {
maxContentChars[j-1] = content.get(i)[j].length();
}
}
if (i==0) {
frozenTableHeaderRow=frozenRow;
contentTableHeaderRow=row;
frozenHeaderTable.addView(frozenRow);
contentHeaderTable.addView(row);
} else {
frozenTable.addView(frozenRow);
contentTable.addView(row);
}
}
setChildTextViewWidths(frozenTableHeaderRow, new int[]{maxFrozenChars});
setChildTextViewWidths(contentTableHeaderRow, maxContentChars);
for (int i = 0; i < contentTable.getChildCount(); i++) {
TableRow frozenRow = (TableRow) frozenTable.getChildAt(i);
setChildTextViewWidths(frozenRow, new int[]{maxFrozenChars});
TableRow row = (TableRow) contentTable.getChildAt(i);
setChildTextViewWidths(row, maxContentChars);
}
}
private void setChildTextViewWidths(TableRow row, int[] widths) {
if (null==row) {
return;
}
for (int i = 0; i < row.getChildCount(); i++) {
TextView cell = (TextView) row.getChildAt(i);
int replacementWidth =
widths[i] == 1
? (int) Math.ceil(widths[i] * cellWidthFactor * 2)
: widths[i] < 3
? (int) Math.ceil(widths[i] * cellWidthFactor * 1.7)
: widths[i] < 5
? (int) Math.ceil(widths[i] * cellWidthFactor * 1.2)
:widths[i] * cellWidthFactor;
cell.setMinimumWidth(replacementWidth);
cell.setMaxWidth(replacementWidth);
}
}
public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY) {
if (scrollView==headerScrollView) {
contentScrollView.scrollTo(x, y);
} else if (scrollView==contentScrollView) {
headerScrollView.scrollTo(x, y);
}
}
滾動視圖監聽器(鉤住兩個上):HorizontalScrollViewListener.java
:
public interface HorizontalScrollViewListener {
void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY);
}
實現這個監聽器滾動視圖類:ObservableHorizontalScrollView.java
:
public class ObservableHorizontalScrollView extends HorizontalScrollView {
private HorizontalScrollViewListener scrollViewListener=null;
public ObservableHorizontalScrollView(Context context) {
super(context);
}
public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(HorizontalScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (null!=scrollViewListener) {
scrollViewListener.onScrollChanged(this, x, y, oldX, oldY);
}
}
}
這樣做的真正重要的部分是那種三方面的:
- 的ObservableHorizontalScrollView允許標題表和內容表中滾動同步中。基本上,這提供了網格的所有水平運動。
- 它們保持對齊的方式是通過檢測列中最大的字符串。這是在
PopulateMainTable()
結束時完成的。在我們瀏覽每個TextView並將它們添加到行時,您會注意到有兩個數組maxFrozenChars
和maxContentChars
可以跟蹤我們看到的最大字符串值。在PopulateMainTable()
的末尾,我們循環遍歷每一行,並根據我們在該列中看到的最大字符串,爲每個單元格設置其最小和最大寬度。這由setChildTextViewWidths
處理。
- 使這項工作的最後一項是使用等寬字體。您會注意到,在
onCreate
中,我加載了一個consola.ttf字體,稍後將其應用於網格的每個TextView,這些TextView充當網格中的單元格。這使我們可以合理確信文本不會比我們在上一步中設置的最小和最大寬度大。我在這裏做了一些幻想,整個cellWidthFactor和那個列的最大尺寸。這確實是爲了讓更小的字符串能夠適合,而我們可以最小化大字符串(對於我的系統)不會全部爲大寫字母的空格。如果您遇到麻煩,並且您的字符串不符合您設置的列大小,則這是您想要編輯的地方。你會想改變replacementWidth
變量與其他公式,以確定單元格的寬度,如50 * widths[i]
這將是非常大的!但是會在某些列中留下大量空白。基本上,根據你打算放入網格的計劃,這可能需要調整。以上是爲我工作的。
我希望這可以幫助別人在未來!
+1,用於很好的寫作 –
@Kevek:「我不能相信這個東西已經不存在了」 - 它可能存在,但我不知道它被封裝爲可重用組件,更不用說可能是一個可重用組件是開源的。 – CommonsWare
@CommonsWare很可能是這種情況,但正如我經常收藏我期望在將來使用的UI控件/算法的書寫,或者認爲對於平臺/語言缺少想法,或許有人會這樣做一樣的,並且之前已經找到了。也許不會! – Kevek