Layouts - Medieninformatik (B.Sc.)

Layouts – Übersicht
●
FrameLayout – Vermeiden
–
●
–
●
Alles links oben
–
–
Horizontal und vertikal, nebeneinander
Verschachteln (kann langsam werden)
Neuer Vertreter, wie Web-Layouttools
Flexibel, interessante Alternative
RelativeLayout – wer damit klar kommt
–
–
Relative Lage zueinander
Effizient
Prof. Dr. Peter Barth, Mobile Computing
LinearLayout
●
LinearLayout
–
–
●
Vertikal, horizontal
nebeneinander
Verschachtelt
Beispiel
–
mXw bedeutet
layout_width:
match_parent
layout_height:
wrap_content
Prof. Dr. Peter Barth, Mobile Computing
FrameLayout: Links oben
–
TableLayout – nur für Tabellen
GridLayout – Geordnetes Layout
–
●
●
LinearLayout – Standard
–
●
FrameLayout – Vermeiden
1
LinearLayout
vertical, mXm
Positioniert alle Views links oben
Wenn mehrere dann übereinander
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Diese TextView geht über alles"/>
<TextView android:layout_width="wrap_content"
android:layout_height="match_parent"
android:width="60dp"
android:gravity="center"
android:background="#00FF00"
android:text="Diese TextView geht über die gesamte Höhe" />
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:height="60dp"
android:gravity="center"
android:background="#FF0000"
android:text="Diese
Prof.
Dr. Peter Barth, MobileTextView
Computinggeht über die gesamte Breite" />
</FrameLayout>
2
TableLayout
LinearLayout
horizontal, mXw
●
Tabelle mit Views
–
LinearLayout
horizontal, mXw
–
–
LinearLayout
vertical, mXw
–
●
Optionen
–
–
3
Zeilenbasiert, <TableRow>
Jede Spalte so breit wie die Breiteste
strechColumns, um zu füllen
Gut zum skalieren
padding, gravity, …
Trick zum Rahmen zeichnen*
<TableLayout xmlns:android=...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1" >
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="@drawable/back"
android:text="Eins" />
<TextView ...
android:gravity="left" />
<TextView … />
</TableRow>
<TableRow>
<TextView … />
<TextView
android:gravity="right" />
</TableRow>
</TableLayout>
*http://stackoverflow.com/questions/3496269/how-to-put-a-border-around-an-android-textview
Prof. Dr. Peter Barth, Mobile Computing
4
GridLayout
●
RelativeLayout
GridLayout
–
–
–
–
–
Anordnung in Zeilen/Spalten Grid
Automatische oder
explizite Zellenzuordnung
Elemente können mehrere
Zellen umfassen
Gravity
Space für Leerbereiche
(Gewichte erst ab API 21)
<GridLayout xmlns:...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alignmentMode="alignBounds"
android:useDefaultMargins="true"
android:columnCount="4" >
<TextView android:text="span4 cent_h"
android:layout_columnSpan="4"
android:layout_gravity="center_horizontal" />
<TextView
android:text="span2 cent_h"
android:layout_gravity="center_horizontal"
android:layout_columnSpan="2" />
<TextView android:text="span2"
android:layout_columnSpan="2" />
<TextView android:text="Vier sehr groß" />
<TextView android:text="Fünf" />
<TextView android:text="Sechs" />
<TextView android:text="Sieben right"
android:layout_gravity="right"/>
<TextView android:text="Sieben left"
android:layout_gravity="left"
android:layout_column="3" />
</GridLayout>
http://android-developers.blogspot.de/2011/11/new-layout-widgets-space-and-gridlayout.html
Prof. Dr. Peter Barth, Mobile Computing
Menus
●
Menus
–
–
●
Ressource
–
–
–
–
●
Mehrere mögliche
(Inter-)Aktionen
Deklarativ, Ressource
res/menu/*.xml
item mit ID, Title und Icon
Vordefinerte Android-Icons
Darstellung in ActionBar,
meist never|ifRoom|always
Gruppierung möglich
●
Relative Layout: Relative Lage
–
–
–
Relative Anordnung zueinander
Alle Views mit ID
Lagespezifikation layout_*
above
toLeftOf
toRightOf
below
–
●
5
<menu … >
<item android:id="@+id/menu_search"
android:title="Suche"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom" />
<item android:id="@+id/menu_rotate"
android:title="Sort"
android:icon="@android:drawable/ic_menu_rotate"
android:showAsAction="always"
/>
<group android:id="@+id/menu_group_admin">
<item android:id="@+id/menu_preferences"
android:title="Einstellungen"
android:icon="@android:drawable/ic_menu_preferences"
android:showAsAction="never" />
…
</group>
</menu>
Kombinationen möglich und sinnvoll
Das effiziente, empfohlene Layout...
Prof. Dr. Peter Barth, Mobile Computing
ActionBar
●
–
●
–
Standard seit API-11
Obere Leiste als zentrales
Interaktionselement
Overflow-Bereich
Interaktion für App, Options-Menu
Interaktion für ausgewählte
Elemente, Kontext-Menu
res/menu/actions.xml
Kontext-Aktionen
für ausgewählte
Alle
(anderen)
Aktionen
Kontext-Aktionen
beenden
OptionMenu (2.x) veraltet
Prof. Dr. Peter Barth, Mobile Computing
showAsAction
always
ActionBar
–
●
6
Logo (meist App-Icon)
und Name
Darstellung: ActionBar, obere Leiste
http://developer.android.com/guide/topics/ui/menus.html
<RelativeLayout xmlns:android=...
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/tv1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FF0000"
android:text="TextView Eins" />
<TextView android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00FF00"
android:layout_below="@id/tv1"
android:text="TextView Zwei" />
<TextView android:id="@+id/tv3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#6666FF"
android:layout_toRightOf="@id/tv2"
android:layout_below="@id/tv1"
android:text="TextView Drei" />
</RelativeLayout>
7
http://developer.android.com/guide/topics/ui/actionbar.html
Prof. Dr. Peter Barth, Mobile Computing
8
ActionBar aktivieren
●
API-Level >= 11, alles ok
–
–
–
●
Festlegen mindestens API-11,
wir nehmen sowieso 15
App-Style von Theme.Holo.* erben
In Java
import android.app.ActionBar;
getActionBar()
API-Level < 11
–
–
–
–
ActionBar/Menus verwenden
<manifest … >
<uses-sdk android:minSdkVersion="15" />
…
</manifest>
●
AndroidManifest.xml
–
–
<resources>
<style name="AppTheme"
parent="android:Theme.Holo.Light">
</style>
</resources>
●
res/values/style.xml
–
●
public class MenuActivity extends Activity {
…
private ActionBar actionBar;
@Override
protected void onCreate( …
ActionBar actionBar = getActionBar();
}
…
–
–
9
Anpassen des Menus
●
–
●
–
–
●
Prof. Dr. Peter Barth, Mobile Computing
●
Objekt-Baum verändern
Nicht jedes Mal aufblasen
(teuer)
Wird gerufen vor jedem anzeigen
Manipulation der Elemente
möglich
Hinzufügen/Entfernen möglich
Beispiel
–
Bei jedem Anzeigen
Such-Aktion mal aktiviert,
mal deaktiviert
Prof. Dr. Peter Barth, Mobile Computing
Contextual Action Mode
–
Auswahl eines/mehrerer Elemente
●
–
Lösung: onPrepareOptionsMenu
–
Diskriminierung über
ID des gewählten item
true heißt abgearbeitet,
falls nicht,
dann super handeln lassen
public class MenuActivity extends Activity {
…
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actions, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_finish:
finish();
return true;
case ...
default:
return super.onOptionsItemSelected(item);
}
10
}
Interaktion für ausgewählte Elemente in ActionBar
Ziel: Anpassen des Menus
–
Inflater um XML nach Java-Objekt
zu transformieren (aufblasen)
Übergebenes menu füllen
onOptionsItemSelected
MenuActivity
Prof. Dr. Peter Barth, Mobile Computing
Aktionen unabhängig vom Kontext
Callbacks
onCreateOptionsMenu
–
import android.app.ActionBar;
Support library
Alle Pfade/Methoden etwas anders
Von ActionBarActivity erben
Doku lesen...
ActionBar – Generell
–
●
–
–
–
11
Eins meist mit long click
Aktion für diese Elemente
Anzeige in ActionBar,
ActionBar ändert sich
Aktivieren
–
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem searchItem = menu.findItem(R.id.menu_search);
if (searchItem.isEnabled()) {
searchItem.setEnabled(false);
} else {
searchItem.setEnabled(true);
}
return super.onPrepareOptionsMenu(menu);
}
Kontext-Aktionen
für ausgewählte
ActionMode starten
und merken, keine
zwei gleichzeitig
Callback (gleich)
Bei ListView item
merken/selektieren
Im Beispiel LongClick
Prof. Dr. Peter Barth, Mobile Computing
Kontext-Aktionen
beenden
private ActionMode actionMode = null;
ListView.OnItemLongClickListener oilcl =
new ListView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent,
View view, int position, long id) {
if (actionMode != null) { return false; }
actionMode=MenusActivity.this.startActionMode(actionModeCallback);
pairsAdapter.setSelectedPosition(position);
return true;
}
};
public void onCreate(... ) {
lvPairs.setOnItemLongClickListener(oilcl); ...
12
ActionMode.CallBack
●
onCreate..
–
●
onPrepare
–
●
Wie OptionsMenu, anpassen
onActionItemClicked
–
–
●
Wie OptionsMenu, aufblasen
Mit item herausfinden was
gemeint war
Selektierte(s) separat merken!
OnDestroy...
–
Freigeben, dass neu anlegen
wieder klappt
Eigentliche Behandlung
ActionMode.Callback actionModeCallback =
new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode,
Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.contextactions, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode,
Menu menu) {
return false; // nothing done
}
@Override
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
return handleMenuItemSelected(item);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
MenusActivity.this.actionMode = null;
}
};
Prof. Dr. Peter Barth, Mobile Computing
●
–
●
●
–
–
13
–
–
●
Prof. Dr. Peter Barth, Mobile Computing
●
Eins meist mit long click
–
Aktion für diese Elemente
Anzeige als überlagertes Auswahlelement,
modales Kontext-Menu/Dialog
–
–
–
–
registerForContextMenu
●
Im Beispiel ListView
ContextMenu
traditionell
automatisch
bei LongClick
onCreateContextMenu
–
Aktivieren
–
●
–
–
15
Vor jeder Anzeige (immer neu)
menu: Anzuzeigendes Menu
view: Die darunterliegende View
(im Beispiel das Layout mit
der ListView)
menuInfo: Extra-Information
Einfach wieder aufblasen und
zu menu hinzufügen
onContextItemSelected
–
public void onCreate(...
registerForContextMenu(lvPairs);
Prof. Dr. Peter Barth, Mobile Computing
14
Kontext-Menu-Behandlung mit Callbacks
Auswahl eines/mehrerer Elemente
●
delete: löschen
edit: Groß/Kleinschreibung
Realisierung im Adapter
}
Floating Context Menu
–
Durch Adapter (später)
Auswahl Aktion über ID
Aktionen
–
Alternative – Interaktion für Ausgewählte als Kontext-Menu
●
private boolean handleMenuItemSelected(MenuItem item) {
int pos = pairsAdapter.getSelectedPosition();
if (pos == -1) { // nothing selected
return super.onContextItemSelected(item);
}
switch (item.getItemId()) {
case R.id.menu_edit:
Pair<String, String> pair =
pairsAdapter.getItem(pos);
String first = null;
if (Character.isUpperCase(pair.first.charAt(0))) {
first = pair.first.toLowerCase();
} else {
first = pair.first.toUpperCase();
}
pairsAdapter.update(pos, first, pair.second);
return true;
case R.id.menu_delete:
pairsAdapter.delete(pos);
return true;
default:
return super.onContextItemSelected(item);
}
Selektierte finden
@Override
public void onCreateContextMenu(
ContextMenu menu,
View view,
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.contextactions, menu);
}
@Override
public boolean onContextItemSelected(
MenuItem item) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo)
item.getMenuInfo();
pairsAdapter.setSelectedPosition(info.position);
return handleMenuItemSelected(item);
}
Bei Auswahl von Aktion (z.B. edit)
Zusätzliche Information extrahierbar (info), bei ActionMode nicht zuverlässig,
besser Selektiertes in Adapter merken
Behandeln der Aktion wie gehabt
Prof. Dr. Peter Barth, Mobile Computing
16
ScrollView
●
Problem: Zu viele Elemente
–
–
–
●
ScrollView – Verwenden
●
Lösung: Weniger Elemente
Lösung: Widget erlaubt Scrolling,
zum Beispiel ListView
Lösung: Separater ScrollView
–
●
–
–
●
HorizontalScrollView
Aber das ist Usability-Todsünde
Prof. Dr. Peter Barth, Mobile Computing
res/layout/scrollview.xml
17
Preferences
●
–
–
●
●
Einfache Daten über
Lebenszyklus
der Anwendung hinaus
merken
Meist Einstellungen
der Anwendung
Vordefiniertes Layout
und Ablage
–
–
–
–
–
●
Preferences als
XML-Datei
Keine vordefinierte Ressource
Aber vorkompiliert
Üblich: Werte in Ressourcen
<string name="key_vorname">
vorname</string>
<string name="key_nachname">
nachname</string> …
<string-array name="stdg_entries">
<item>Angewandte Informatik</item>
<item>Medieninformatik</item> …
</string-array>
<string-array name="stdg_entries_values">
<item>ai</item>
<item>mi</item> …
</string-array>
Schlüssel/Wert Paare
Texte, Ja/Nein, Auswahl,
Zahlen, Kategorien
Zugriff aus allen Activities einer App
Prof. Dr. Peter Barth, Mobile Computing
Deklaration
–
Preferences
19
ScrollViewActivity.onCreate
Prof. Dr. Peter Barth, Mobile Computing
Preferences – Deklaration
Einstellungen/Settings
–
Beispiel: mit Java-Code
<ScrollView ...
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:id="@+id/ll_scrollview"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</ScrollView>
Ein Layout, von FrameLayout abgeleitet
Nur Widgets ohne eigenes Scrolling
verwenden
Vertikales Scrolling
●
LinearLayout als Kind zum Füllen
LinearLayout füllen
–
ScrollView
–
Layout mit ScrollView-Wurzel
super.onCreate(savedInstanceState);
setContentView(R.layout.scrollview);
LinearLayout linearLayout =
(LinearLayout) findViewById(R.id.ll_scrollview);
ViewGroup.LayoutParams layoutParams =
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
View.OnClickListener ocl =
new View.OnClickListener() {
@Override public void onClick(View view) {
CharSequence msg = ((TextView) view).getText();
Toast.makeText(ScrollViewActivity.this, msg,
Toast.LENGTH_SHORT).show();
}
};
for (int i=0; i < 123; i+=1) {
TextView textView = new TextView(this);
textView.setLayoutParams(layoutParams);
textView.setText(String.format("TextView %03d", i));
textView.setClickable(true);
textView.setOnClickListener(ocl);
linearLayout.addView(textView);
}
Prof. Dr. Peter Barth, Mobile Computing
18
<PreferenceScreen … >
<PreferenceCategory android:title="Persönlich" >
<EditTextPreference
android:key="@string/key_vorname"
android:title="Vorname"
android:defaultValue="Susi" />
…
</PreferenceCategory>
<PreferenceCategory android:title="Anwendung" >
<CheckBoxPreference
android:key="@string/key_bafoeg"
android:title="Bafög"
android:defaultValue="false" />
<ListPreference
android:key="@string/key_stdg"
android:title="Studiengang"
android:entries="@array/stdg_entries"
android:entryValues="@array/stdg_entries_values"
android:defaultValue="mi"
/>
</PreferenceCategory>
…
</PreferenceScreen>
res/xml/preferences.xml
Anzeige bei Auswahl
Wert in Preferences, gut als Key in Map
20
Preferences – Ändern
●
Separate Activity
–
–
–
–
PreferencesFragment
PreferenceActivity deprecated
PreferenceFragment
Nutzen in Activity
immer so verwenden
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
Prof. Dr. Peter Barth, Mobile Computing
public class Settings extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction()
.replace(android.R.id.content,
new SettingsFragment())
.commit();
}
}
21
Preferences – Zugriff
●
In jeder Activity
–
–
–
●
PreferenceManager
setDefaultValues
Sicherstellen initialisiert
(zumindest in
Main Activity)
getDefault
SharedPreferences
für Zugriff
get*
–
–
Je Typ ein Getter,
Schlüssel,
Vorgabewert
getString häufig
Prof. Dr. Peter Barth, Mobile Computing
Prof. Dr. Peter Barth, Mobile Computing
22
Preferences – Map für Auswahl
ShowPreferences.onCreate
●
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
preferences = PreferenceManager.getDefaultSharedPreferences(this);
Map
–
–
tvVorname = (TextView) findViewById(R.id.tv_vorname); …
Resources resources = getResources();
keyVorname = resources.getString(R.string.key_vorname);
–
ShowPreferences.refresh
String → String
Wert, der in den
Preferences abgelegt
wird ist Schlüssel in der
Map
AnzeigeString ist Wert
in der Map
ShowPreferences.onCreate
String[] stdgEntries =
resources.getStringArray(R.array.stdg_entries);
String[] stdgEntriesValues =
resources.getStringArray(R.array.stdg_entries_values);
stdgMap = new HashMap<String, String>();
for (int i=0; i < stdgEntries.length; i+=1) {
stdgMap.put(stdgEntriesValues[i], stdgEntries[i]);
}
tvVorname.setText(preferences.getString(keyVorname, null));
tvBafoeg.setText("" + (preferences.getBoolean(keyBafoeg, false)));
tvStdg.setText(stdgMap.get(preferences.getString(keyStdg, null)));
…
23
Prof. Dr. Peter Barth, Mobile Computing
24
Preferences –
Änderungen
●
Änderungen in
Settings
–
●
Reagieren mit
Callbacks/Listener
OnShared
Preference
ChangeListener
–
–
SharedPreferences.OnSharedPreferenceChangeListener
ospcl =
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if (key.equals(keyAutoUpdate)) {
String t = sharedPreferences.getString(keyAutoUpdate, "0");
tvAutoUpdate.setText(t);
}
}
};
…
protected void onCreate(...
preferences = PreferenceManager.getDefaultSharedPreferences(this);
preferences.registerOnSharedPreferenceChangeListener(ospcl);
}
Parameter
Preferences und
geänderter Schlüssel
Registrieren, am besten in onCreate
Preferences – Ändern
●
Ziel
–
●
Von Java aus
Settings ändern
–
●
–
Prof. Dr. Peter Barth, Mobile Computing
Hierarchy Viewer – im DDMS
25
Ausgewähltes Element
in Baumhierarchy
Start
Wahl
Screen
Element
mit
Mouseover
Prof. Dr. Peter Barth, Mobile Computing
Details zu Element
27
SharedPreferences
Editor
Zu festen
Zeitpunkten
–
Bei Änderung
automatisch aktualisiert
AutoUpdate-Wert
alle 3 Sekunden
erhöhen
Executor
Start/Stop
für Lebenszyklus
Prof. Dr. Peter Barth, Mobile Computing
private void incrementAutoUpdate() {
int val = Integer.parseInt(
preferences.getString(keyAutoUpdate, "0"));
SharedPreferences.Editor editor = preferences.edit();
editor.putString(keyAutoUpdate, "" + (val + 1));
editor.commit();
}
private ScheduledExecutorService scheduleTaskExecutor;
protected void onStart() {
super.onStart();
scheduleTaskExecutor = Executors.newSingleThreadScheduledExecutor();
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
incrementAutoUpdate();
}},0,3,TimeUnit.SECONDS);
}
protected void onStop() {
super.onStop();
if (scheduleTaskExecutor != null) {
scheduleTaskExecutor.shutdown();
scheduleTaskExecutor = null;
}
}
26