Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Aloha, ich suche ein gutes Tutorial zum designen von Views unter verwendung von .xml Dateien mit android.
Gern auch mit einer detaillierten Einführung in .xml Dateien und deren Aufbau.
Prinzipiell geht es mir darum zu verstehen wie ich z.B ListView Einträge unter der Verwendung einer selber erstellten .xml Datei anpassen kann.
Wenn ich in einem neuen Android eine neue .xml Datei anlegen und ein Layout verwende ( z.B Lineares Layout) nimmt dieses ja immer den kompletten Screen ein .
Ich vermute ich muss auf einen LayoutInflater zurückgreifen , bin mir aber nicht sicher, wäre super wenn jemand ein guten Tutorial kennt und mir nen Link oder auch gern ein Buch darüber vorschlagen könnte
Wenn ich es richtig verstehe, ist der konkrete Use-Case ein ListView, oder? Hier wirst du im dazugehörigen Adapter nicht um den Inflater herumkommen. Klappt bei mir aber wunderbar (auch bei Listen von 10'000 Einträgen aus einer DB).
Ein einzelnes Tutorial, dass dir alles erklärt, wirst du (leider) nicht finden - ich habe Lars Vogels Tutorials genutzt, wobei die häufig nur der Einstiegspunkt waren. Konkrete Probleme habe ich dann meist mit Google-suche, oder - wenn möglich - StackOverflow geklärt.
Grundsätzlich muss ein (Basis-)Layout nicht immer die ganze Seite einer Activity oder eines Fragments, etc., einnehmen. Wie jedes andere hat es die Attribute für die layout_width und _height - wie gut das in der Praxis dann funktioniert, ist eine andere Sache und auch nach 1.5 Jahren Android ist mir noch nicht immer alles sofort klar und muss noch häufig suchen (vor allem, wenn man nicht ausschliesslich Android entwickelt).
Aber bitte erläutere doch einmal dein konkretes Problem etwas näher. Was genau bereitet dir im Moment noch Kopfzerbrechen?
ich habe eine Listview , in welcher ich 4 Verschiedene Strings darstelle, dazu nutze ich zzt. das Layout Simple_List_item1,
ich würde gerne selber festlegen wie dieses Layout aussehen soll, ich habe bereits gelesen das dies über einen LayoutInflater in verbindung mit einer .xml Datei machbar ist und das Design bzw. der Aufbau des Layouts dazu eben wie für jedes andere layout in einer .xml datei festgelegt wird,
da ich bislang noch nicht wirklich mit xml dateien gearbeitet habe ( bis auf die "vollständigen" layouts für die einzelnen Activitys)
suche ich halt ein Tutorial oder ähnliches wo ich mir nochmal anschauen kann wie man die xml Datei richtig aufbaut (bzw. für solche fälle verwendet) , und diese dann anschließend in Android in über den Inflater o.ä als Layout für die Elemente nutzen kann.
Ich zeige es dir am besten an dem konkreten Beispiel (Achtung, das ist 1:1 kopiert und vielleicht etwas komplexer...):
[XML]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
androidrientation="vertical" >
Das ist ein Auszug aus dem Fragment-Code - ich habe versucht es soweit zu bereinigen, dass es wenigstens halbwegs übersichtlich bleibt... Nicht, dass das wirklich gelungen ist :-/
Als nächstes kommt das Layout der Listen-Items:
[XML]
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/result_row"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/result_list_selector"
android:stretchColumns="4,5" >
</TableLayout>
[/XML]
Das ist recht Straight-Forward. Baue den genau so, also wolltest du eine ganze Seite damit füllen - am besten zentriere den Content und checke es immer wieder mal im Preview. Dieses XML hier ist recht alt (aus einer nicht von mir geschriebenen Vorgängerversion der Anwendung) und macht immer wieder Probleme, wenn es nur noch wenig Platz auf dem Bildschirm hat. Aber für alle normale Geräte (Tablets mit Tablet-UI und Phones mit Phone-UI) sieht es gut. Erst Tablet-UI auf Phone sieht wirklich bescheuert aus.
Jetzt das wichtigste: Der "ResultCursorAdapter", der oben im Code war. Hier kannst du den Inflater verwenden - musst du aber nicht zwingenderweise, wenn du im Konstruktor des Adapters dein XML angibst - dann inflated Android es für dich und du musst es "nur" noch updaten.
Java:
public class ResultCursorAdapter extends SimpleCursorAdapter {
private int sortby = 0;
public void setSortById(int id) {
sortby = id;
}
private final Typeface bold;
private final Typeface boldItalic;
public ResultCursorAdapter(Context context, Cursor c, String[] from, int[] to, int flags) {
super(context, R.layout.result_row, c, from, to, flags);
bold = Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
boldItalic = Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
}
private Set<Long> selection = null;
public Set<Long> getSelection() {
if (selection == null) {
selection = new HashSet<Long>();
}
return selection;
}
public void setSelection(Set<Long> selection) {
this.selection = selection;
}
public Set<Long> addSelection(Long selection) {
if (this.selection == null) {
this.selection = new HashSet<Long>();
}
if ((selection == null) || (selection < 1)) {
return this.selection;
}
this.selection.add(selection);
return this.selection;
}
// XXX Hack of the week...
private static final int rid = Resources.getSystem().getIdentifier("btn_check_holo_dark", "drawable", "android");
@SuppressWarnings(value = { "unused" })
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView ids = (TextView) view.findViewById(R.id.HC_Ids);
TextView date = (TextView) view.findViewById(R.id.HC_Date);
TextView time = (TextView) view.findViewById(R.id.HC_Time);
ImageView icon = (ImageView) view.findViewById(R.id.HC_Icon);
ImageView iconDown = (ImageView) view.findViewById(R.id.HC_icon_down);
ImageView iconUp = (ImageView) view.findViewById(R.id.HC_icon_up);
ImageView iconRtt = (ImageView) view.findViewById(R.id.HC_icon_rtt);
ImageView iconServer = (ImageView) view.findViewById(R.id.HC_icon_upload_to_server_failed);
TextView download = (TextView) view.findViewById(R.id.HC_Download);
TextView upload = (TextView) view.findViewById(R.id.HC_Upload);
TextView rtt = (TextView) view.findViewById(R.id.HC_RTT);
TextView server = (TextView) view.findViewById(R.id.HC_Server);
TextView location = (TextView) view.findViewById(R.id.HC_Location);
TextView conn = (TextView) view.findViewById(R.id.HC_Connection);
ids.setTypeface(bold);
download.setTypeface(Typeface.DEFAULT);
upload.setTypeface(Typeface.DEFAULT);
rtt.setTypeface(Typeface.DEFAULT);
// First Column
long timestamp = cursor.getLong(cursor.getColumnIndex(ResultTable.Cols.TIMESTAMP));
Calendar cal = new GregorianCalendar();
cal.setTimeInMillis(timestamp);
date.setText(String.format("%tF", cal));
time.setText(String.format("%tH:%tM", cal, cal));
ids.setText(context.getString(R.string.test_format, cursor.getInt(cursor.getColumnIndex(ResultTable.Cols.SERIES_ID)),
cursor.getInt(cursor.getColumnIndex(ResultTable.Cols.TEST_ID))));
// Second Column
long down = cursor.getLong(cursor.getColumnIndex(ResultTable.Cols.SPEED_DOWN));
String downSpeed = SpeedFormatter.formatSpeed(context, down);
if (SpeedFormatter.emptyString(context) != downSpeed) {
download.setText(context.getString(R.string.average) + SpeedTestConstants.ONESPACE_STRING + downSpeed);
} else {
download.setText(downSpeed);
}
long up = cursor.getLong(cursor.getColumnIndex(ResultTable.Cols.SPEED_UP));
long upClient = cursor.getLong(cursor.getColumnIndex(ResultTable.Cols.SPEED_UP_CLIENT));
String upSpeed = SpeedFormatter.formatSpeed(context, (up > 0 ? up : upClient > 0 ? upClient : SpeedTestConstants.PREF_DEFAULT_INTEGER));
if (SpeedFormatter.emptyString(context) != upSpeed) {
upload.setText(context.getString(R.string.average) + SpeedTestConstants.ONESPACE_STRING + upSpeed);
} else {
upload.setText(upSpeed);
}
if (cursor.getInt(cursor.getColumnIndex(ResultTable.Cols.RTT)) > 0) {
// TODO if we use nanoseconds use the formatTime method
rtt.setText(context.getString(R.string.average) + SpeedTestConstants.ONESPACE_STRING
+ TimeFormatter.formatTimeDeleteIt(context, cursor.getInt(cursor.getColumnIndex(ResultTable.Cols.RTT))));
} else {
rtt.setText(context.getString(R.string.notAvailable));
}
// Third Column
server.setText(cursor.getString(cursor.getColumnIndex(ResultTable.Cols.SERVER_NAME)));
LocationEnum loc = LocationEnum.findByKey(cursor.getString(cursor.getColumnIndex(ResultTable.Cols.LOCATION)));
location.setText(loc != null ? loc.getLabel(context) : SpeedTestConstants.EMPTY_STRING);
conn.setText(cursor.getString(cursor.getColumnIndex(ResultTable.Cols.CONNECTION)));
int size = 32;
// Icon
icon.getLayoutParams().height = size;
icon.getLayoutParams().width = size;
if (cursor.getString(cursor.getColumnIndex(ResultTable.Cols.CONNECTION)).equalsIgnoreCase(SpeedTestConstants.CONNTYPE_WIFI)) {
icon.setImageResource(R.drawable.wifi_dark);
} else {
icon.setImageResource(R.drawable.wwan_dark);
}
iconDown.getLayoutParams().height = size;
iconDown.getLayoutParams().width = size;
iconDown.setImageResource(R.drawable.arrow_down);
iconUp.getLayoutParams().height = size;
iconUp.getLayoutParams().width = size;
iconUp.setImageResource(R.drawable.arrow_up);
iconRtt.getLayoutParams().height = size;
iconRtt.getLayoutParams().width = size;
iconRtt.setImageResource(R.drawable.arrow_up_down);
if (sortby == R.id.HC_Ids) {
ids.setTypeface(boldItalic);
} else if (sortby == R.id.HC_Download) {
download.setTypeface(boldItalic);
} else if (sortby == R.id.HC_Upload) {
upload.setTypeface(boldItalic);
} else if (sortby == R.id.HC_RTT) {
rtt.setTypeface(boldItalic);
} else {
ids.setTypeface(boldItalic);
}
}
@Override
public View getView(int position, View parent, ViewGroup container) {
boolean error = false;
Object item = getItem(position);
if (item instanceof CursorWrapper) {
int index = ((CursorWrapper) item).getColumnIndex(ResultTable.Cols.SUCCESS);
int success = 1;
if (index != -1) {
success = ((CursorWrapper) item).getInt(index);
}
if (success == 0) {
error = true;
}
}
View view = super.getView(position, parent, container);
if (!error) {
view.setBackgroundResource(((position % 2) != 0) ? R.drawable.result_list_selector_2 : R.drawable.result_list_selector);
} else {
view.setBackgroundResource(((position % 2) != 0) ? R.drawable.result_list_selector_2_error : R.drawable.result_list_selector_error);
}
return view;
}
}
Wenn du doch einen Inflater verwenden möchtest, dann hole ihn dir im Konstruktor mit
.
Ich verwende die #getView-Methode nur, um jeden zweiten View mit einem alternativen Hintergrund zu belegen, damit man die Zeilen besser unterscheiden kann. Der Rest geschieht in der
Code:
#bindView(View, Context, Cursor)
-Methode.
Der Rest ist bla bla und keine Hexerei.
Schau mal durch, ob dir das als Gedankenstütze hilft. Wenn du fragen dazu hast, immer her damit.
Grüsse,
Daniel
PS: Wenn du es dir in Aktion ansehen möchtest, installier dir einmal die Anwendung und spiele damit herum. Playstore: cnlab SpeedTest
PPS: Und wenn du Feedback hast, immer her damit ;-)
doch relativ komplex das ganze.... dazu muss ich mich auch erstmal in die Fragments Doku einlesen denke ich , aber trotzdem schon mal danke,
ich stehe aber grad noch vor einem anderen Problem, vielleicht hast du sowas ähnliches ja schon mal realisieren müssen.
Und zwar wird mein ListView ( bzw. der Adapter) mit Elementen aus einer ArrayList gefüllt, diese sind von einem eigenen Typ, nun möchte ich bei Klick auf eines der Items eine Kopie dieses Elementes anfertigen können.
Die Idee war dieses Element in die Zwischenablage zu kopieren und und bei bedarf wieder in den ListView einfügen zu können , nun habe ich aber in der API Dokumentation zum ClipboardManager nichts gefunden was mir helfen würde , da ich eben keine Strings kopieren will sondern eigene Objekte .
mein erster Gedanke war eine Methode zu erstellen die mir eine Kopie meines Objektes returned
z.B
Java:
public myObject copyListViewItem(MyObject obj){
if(!(obj == null)){
MyObject copy = new MyObject();
copy.addValue(/* Aufruf der Setter von MyObject zum setzen der Werte*/);
return copy;
}
return new MyObject().setDefaultValues(); // Zum umgehen einer NPE
}
Einfügen in den Adapter kann ich ja dann einfach über add() realisieren, allerdings muss ich mein Objekt dazu ja irgendwo Zwischenspeichern ( sonst bliebe nur Serialisieren, und das wäre Overkill oder nicht ?)
Java:
adapter.add(/* Objekt aus der Zwischenablage */);
nun stellt sich mir aber die Frage wie und wo ich diese Kopie nun temporär zwischenspeichern kann ?
ich nutzen btw. den OnItemLongClickListener der dann die Methode zur Objektkopie aufrufen soll.
(ich habe hier erstmal bewusst nicht Cloneable implementiert da die Objektkopie auch so leicht zu realisieren ist).
Hast du vielleicht schon etwas ähnliches realisieren müssen ?
Da ich heute schon einen zu langen Tag hatte: Ich schau es mir morgen noch mal an. Eine erste Idee wäre recht pragmatisch - speicher es in eine Liste, für die es einen Getter in deinem Adapter gibt. Ist vielleicht nicht schön, sollte aber gehen.
Aber wie gesagt, ist es schon zu spät für mich und ich habe deine Antwort nur überflogen: Morgen!
Ok, die Idee mit der Liste ist vielleicht garnicht verkehrt, ich werde das mal teste und für meine zu Verarbeitende Klasse eine Methode schreiben welche mir ein Objekt zurückliefert welches identisch belegte werte hat, da es wie gesagt nicht um Objektgleichheit geht kann ich auch einfach ein neues mit selben werten erzeugen anstatt clone() zu implementieren.
ich probiere mich mal ein bisschen aus und geb dann mal rückmeldung