約1週間前に私はこの問題を再訪し、解決策を思いつきました。このソリューションでは、このグリッドの列の手動幅の設定を多くする必要があります。この日および年齢では、非常にサブパールになると考えています。残念なことに、私は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);
}
このリスナーを実装ScrollViewクラス: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);
}
}
}
本の本当に重要な部分は、3倍の一種である:
- ObservableHorizontalScrollViewは、ヘッダテーブルおよびコンテンツテーブルをスクロールすることができますに同期中。基本的に、これはグリッドのすべての水平移動を提供します。
- 列が一致する方法は、列内にある最大の文字列を検出することです。これは
PopulateMainTable()
の最後に行われます。それぞれのTextViewを処理して行に追加しているうちに、最大の文字列値が何であるかを把握している2つの配列maxFrozenChars
とmaxContentChars
があることがわかります。 PopulateMainTable()
の最後に、各行をループし、各セルについて、その列で見た最大の文字列に基づいて最小幅と最大幅を設定します。これはsetChildTextViewWidths
によって処理されます。
- この作業を行う最後の項目は、モノスペースフォントを使用することです。
onCreate
でconsola.ttfフォントを読み込み、後でグリッドのセルとして機能する各グリッドのTextViewに適用していることがわかります。これにより、テキストが前のステップで最小と最大の幅に設定されているよりも大きくレンダリングされないことを合理的に確かめることができます。私はここで少し気が利いています。cellWidthFactor全体とその列の最大サイズはどういう意味ですか?これは実際には小さな文字列が確実に収まるようにするためですが、大文字ではない大きな文字列の空白を最小限に抑えることができます。これを使用して問題が発生した場合、設定したカラムサイズに合わない文字列がある場合は、これを編集したい場所です。 50 * widths[i]
など、セル幅を決定するための式を使用してreplacementWidth
変数を変更したい場合があります。しかし、いくつかの欄には空白を残しておきます。基本的には、グリッドを配置する予定に応じて、これを微調整する必要があります。上記は私のために働いたものです。
今後これが他の人に役立つことを祈っています!
+1の素敵な書き込みのために –
@Kevek:「これは既にどこかに存在しないとは思えません」 - それは存在する可能性がありますが、再利用可能なコンポーネントとしてパッケージ化されていることは知らないオープンソースです。 – CommonsWare
@CommonsWareこれは非常によく似ているかもしれませんが、将来私が使用すると思われるUIコントロール/アルゴリズムのブックマークをブックマークしたり、プラットフォーム/言語ではないと思っています。同じ、これを以前に見つけました。そうでないかもしれない! – Kevek