Wenn man für Android-Geräte entwickelt speziell jedoch für Mobilegeräte stößt man sehr schnell an die Displaygrenzen. Hier möchte ich nun zeigen wie man eine Tabelle mit einem festen Tabellenkopf und scrollbarem Inhalt erstellt.
Als erstes das Layout als kurze Skizze aus welchem schon ersichtlich sein sollte wie später die Layoutdatei (*.xml) aussehen sollte.
Das Layout
Aus der obigen Skizze sehen Sie die Widgets welche benötigt werden.
Hier nun das Layout der späteren Activity.
Dieses wird in dem Verzeichnis „layout“ unter dem Namen „scrollabletablelayout.xml“ gespeichert.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fillable_area" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="vertical"> <TableLayout android:id="@+id/table_header" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/col0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col0Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> <HorizontalScrollView android:id="@+id/tblHeaderhorzScrollView" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/tableHeaderScrollContent" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/col1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col1Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> <TextView android:id="@+id/col2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col2Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> <TextView android:id="@+id/col3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col3Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> <TextView android:id="@+id/col4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col4Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> <TextView android:id="@+id/col5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tableheaderborder" android:text="@string/col5Text" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/black" /> </LinearLayout> </HorizontalScrollView> </TableRow> </TableLayout> <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/fillable_area2" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="horizontal"> <TableLayout android:id="@+id/fixed_column" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <HorizontalScrollView android:id="@+id/horizontalScrollView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbarStyle="insideOverlay"> <TableLayout android:id="@+id/scrollable_part" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </HorizontalScrollView> </LinearLayout> </ScrollView> </LinearLayout>
Die Activity
Zuerst erstellen wir uns eine „normale“ Java Klasse welche die Klasse Activity erweitert.
public class ScrollableTable extends Activity
Nun noch die Methode um das zuvor erstellte Layout in dieser Activity zu laden.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.scrollabletablelayout); }
Wenn man nun die App startet, sieht das Layout zunächst unscheinbar aus.
Als Nächstes müssen die Spaltenbreiten und Spaltenhöhen vergeben werden dazu legen wir folgende Membervariablen an.
private final static int[] COLUMN_WIDTHS = new int[]{40, 40, 40, 40, 40, 40}; private final static int CONTENT_ROW_HEIGHT = 80; private final static int FIXED_HEADER_HEIGHT = 60;
In diesem Beispiel haben alle Spalten dieselbe Breite und man könnte problemlos ohne ein Array arbeiten, jedoch soll es später möglich sein jede Spalte eine andere Breite zu vergeben und damit ist das Array in seiner Existenz bestätigt.
private void setTableHeaderWidth() { TextView textView; textView = (TextView) findViewById(R.id.col0); setHeaderWidth(textView, COLUMN_WIDTHS[0]); textView = (TextView) findViewById(R.id.col1); setHeaderWidth(textView, COLUMN_WIDTHS[1]); textView = (TextView) findViewById(R.id.col2); setHeaderWidth(textView, COLUMN_WIDTHS[2]); textView = (TextView) findViewById(R.id.col3); setHeaderWidth(textView, COLUMN_WIDTHS[3]); textView = (TextView) findViewById(R.id.col4); setHeaderWidth(textView, COLUMN_WIDTHS[4]); textView = (TextView) findViewById(R.id.col5); setHeaderWidth(textView, COLUMN_WIDTHS[5]); } private void setHeaderWidth(TextView textView, int width) { textView.setWidth(width * getScreenWidth() / 100); textView.setHeight(FIXED_HEADER_HEIGHT); } private int getScreenWidth() { return getResources().getDisplayMetrics().widthPixels; }
Wenn wir nun die App starten können wir schon einmal den Tabellenkopf nach links scrollen wobei die erste Spalte fest stehen bleibt.
Es fehlt jetzt noch die Logik um die Tabelle bzw. Tabellen zu befüllen.
In diesem Beispiel wird durch eine einfache For-Schleife ein Zahlenwert in jede Spalte geschrieben. Über den Index kann man ggf. den Hintergrund später modifizieren sodass jede 2. Zeile anders dargestellt wird.
private void fillTable() { Context ctx = getApplicationContext(); for (int i = 0; i <= 100; i++) { for (int col = 1; col <= 5; col++) { fixedTableLayout.addView(createTextView(String.valueOf(i), COLUMN_WIDTHS[0], i)); TableRow row = new TableRow(ctx); row.addView(createTextView(String.valueOf(col), COLUMN_WIDTHS[1], i)); row.addView(createTextView(String.valueOf(col), COLUMN_WIDTHS[2], i)); row.addView(createTextView(String.valueOf(col), COLUMN_WIDTHS[3], i)); row.addView(createTextView(String.valueOf(col), COLUMN_WIDTHS[4], i)); row.addView(createTextView(String.valueOf(col), COLUMN_WIDTHS[5], i)); scrollableTableLayout.addView(row); } } } private TextView createTextView(String text, int width, int index) { TextView textView = new TextView(getApplicationContext()); textView.setText(text); textView.setWidth(width * getScreenWidth() / 100); textView.setHeight(CONTENT_ROW_HEIGHT); return textView; }
Wenn nun die App gestartet wird, wird die befüllte Tabelle angezeigt.
Jedoch ist zwar nun der Inhalt der Tabelle scrollbar und der Tabellenkopf, jedoch scrollt dieser (noch) nicht zusammen in die gewünschte Richtung.
Um nun das simultane Scrollen der beiden android.widget.HorizontalScrollView zu implementieren wird die Methode onCreate wie folgt erweitert.
final HorizontalScrollView tblHeaderhorzScrollView = (HorizontalScrollView) findViewById(R.id.tblHeaderhorzScrollView); final HorizontalScrollView horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView); horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { tblHeaderhorzScrollView.setScrollX(horizontalScrollView.getScrollX()); } });
Schauen wir uns nun das Ergebnis ansieht es schon viel besser aus, wenn nun die Tabelle nach links oder rechts gescrollt wird läuft der Tabellenkopf mit.
Was mich persönlich gestört hat ist der Umstand das beim scrollen nun 2 Scrollleisten zusehen sind, einmal die vom Tabellenkopf und die vom Tabelleninhalt. Die für mich überflüssige Scrollleiste im Tabellenkopf entferne ich mit folgendem Code:
tblHeaderhorzScrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); tblHeaderhorzScrollView.setHorizontalScrollBarEnabled(false);
Wenn nun gescrollt wird, wird die Scrollleiste im Tabellenkopf nicht angezeigt.
Der fertige Quellcode zum Download und einsetzen in einer Android App
Die Zip Datei enthält folgende Dateien:
- ScrollableTable.java
- scrollabletablelayout.xml
- strings.xml
Hallo,
Ich finde die Anleitung sehr gut.
Gib es da auch eine, damit man die Tabelle mit Daten aus einer
Mysql DB füllen kann.
Danke
Hallo Helmut,
wenn du bereits ein ResultSet hat dann kannst du mit einer „einfachen“ Schleife dieses durchlaufen und dann die einzelnen Tabellen mit TextView Objekten befüllen.
Gruß,
Stefan