ListView onClick und Sortierung

  • 28 Antworten
  • Letztes Antwortdatum
S

SaschaHa²

App-Anbieter (In-App)
38
Hallo Liebe Community,

ich habe zwei kleine Probleme, für die ich bisher keine verständliche Lösung gefunden habe. Und zwar:

1. Wie kann ich mit jedem ListView-Eintrag eine bestimmte Methode oder ein Layout aufrufen? Und zwar möchte ich die ListView als Menü für eine App benutzen, bei der bei jedem Eintrag ein bestimmtes Layout aufgerufen wird. Bisher habe ich das mit Buttons und onClick-Methoden gemacht, aber das scheint hier nicht so leicht zu funktionieren.

2. Und als nächstes würde ich meine Liste gerne nach Namen sortieren. Da ich am Ende Strings aus der Strings.xml verwende, konnten mir andere Tutorials auch nicht wirklich weiterhelfen.

Hier erstmal ein provisorischer Code eines Tutorials, an dem ich mich orientiere:

Hier die MainActivity.java

public class MainActivity extends Activity {
private List<Car> myCars = new ArrayList<Car>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

populateCarList();
populateListView();
registerClickCallback();
}
private void populateCarList() {
myCars.add(new Car("Ford", 1998, R.drawable.help, "Needing work"));
myCars.add(new Car("Toyota", 1994, R.drawable.heart, "Lovable"));
myCars.add(new Car("Honda", 1999, R.drawable.fish, "Wet"));
myCars.add(new Car("Porche", 2005, R.drawable.lightning, "Fast!"));
myCars.add(new Car("Jeep", 2004, R.drawable.star, "Awesome"));
myCars.add(new Car("Rust-Bucket", 2010, R.drawable.bug, "Not *very* good"));
myCars.add(new Car("Moon Lander", 1971, R.drawable.up, "Out of this world"));
}
private void populateListView() {
ArrayAdapter<Car> adapter = new MyListAdapter();
ListView list = (ListView) findViewById(R.id.carsListView);
list.setAdapter(adapter);
}

private void registerClickCallback() {
ListView list = (ListView) findViewById(R.id.carsListView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long id) {

Car clickedCar = myCars.get(position);
String message = "You clicked position " + position
+ " Which is car make " + clickedCar.getMake();
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
}
});
}

private class MyListAdapter extends ArrayAdapter<Car> {
public MyListAdapter() {
super(MainActivity.this, R.layout.item_view, myCars);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Make sure we have a view to work with (may have been given null)
View itemView = convertView;
if (itemView == null) {
itemView = getLayoutInflater().inflate(R.layout.item_view, parent, false);
}

// Find the car to work with.
Car currentCar = myCars.get(position);

// Fill the view
ImageView imageView = (ImageView)itemView.findViewById(R.id.item_icon);
imageView.setImageResource(currentCar.getIconID());

// Make:
TextView makeText = (TextView) itemView.findViewById(R.id.item_txtMake);
makeText.setText(currentCar.getMake());

// Year:
TextView yearText = (TextView) itemView.findViewById(R.id.item_txtYear);
yearText.setText("" + currentCar.getYear());

// Condition:
TextView condionText = (TextView) itemView.findViewById(R.id.item_txtCondition);
condionText.setText(currentCar.getCondition());

return itemView;

Und hier die Car.java

public class Car {
private String make;
private int year;
private int iconID;
private String condition;

public Car(String make, int year, int iconID, String condition) {
super();
this.make = make;
this.year = year;
this.iconID = iconID;
this.condition = condition;
}

public String getMake() {
return make;
}
public int getYear() {
return year;
}
public int getIconID() {
return iconID;
}
public String getCondition() {
return condition;

Wie gesagt: Das ist erstmal nur der Code eines Tutorials. Die Liste und die einzelnen Elemente werden verändert, vom Aufbau her möchte ich es aber ähnlich haben. Beim ListView-Eintrag für - sagen wir mal - einen BMI-Rechner möchte ich halt das entsprechende BMI-Layout aufrufen, das ich vorher in einer xml erstellt habe. Und so weiter.

Ich wäre für Hilfe echt dankbar, weil ich einfach nicht weiterkomme. Da ich ein totaler Neueisteiger bin, habt bitte etwas Nachsicht, wenn meine Fragen etwas doof erscheinen :p

Am liebsten hätte ich in den Zeilen, wo ich die Werte meiner ListView eintrage, auch den Namen der Methode/des Layouts, die/das aufgerufen wird, also zum Beispiel hier hinter:
myCars.add(new Car("Ford", 1998, R.drawable.help, "Needing work"));

LG und vielen Dank schonmal! :)
Sascha
 
Unterschiedliche Layouts kannst du je nach Position in deinem Adapter setzen.
Und unterschiedliche Methoden im clicklistener mit der position Angabe switchen

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
  • Danke
Reaktionen: SaschaHa²
Erstmal danke! Ja aber wie genau mache ich das? Wenn ich zum Beispiel meine Sortierung ändere, ändert sich ja auch die Reihenfolge, in der ich die einzelnen Methoden zuordnen muss. Und generell muss ich ja sämtliche bestehende Methoden mit dem clicklistener aufrufen, das heißt, ich muss alle angeben.. und genau dazu fehlt mir aktuell das Wissen bzw. ich finde im Internet einfach keine Infos, wie ich genau das mache.
 
Die Sortierung ist wirklich ein Problem, bzw macht viel Arbeit, wenn man was ändert. Was besseres fällt mir aber leider nicht ein.

Bei den Methoden kannst du im onClickListener einen switch einbauen. Da kannst du dann für jede Position die entsprechende Methode aufrufen lassen.

Definierst die also in deiner Klasse und rufst die nur noch auf.

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
  • Danke
Reaktionen: SaschaHa²
Danke, so ähnlich habe ich das jetzt provisorisch auch gelöst. Funktioniert und bin schon sehr zufrieden damit! :)
Lediglich mit der Sortierung habe ich so meine Probleme... Ich schätze mal, dass die Methoden der Stelle der Liste zugeordnet sind und nicht der Programmierzeile, in der ich die Items definiere. Somit würde eine automatische Sortierung nach Namen tatsächlich alles durcheinander würfeln. Aber soweit so gut.

Andere Frage: Wie komme ich zurück ins Hauptmenü, wenn ich über setContentView andere Layouts aufgerufen habe? Es soll ja mit Intent gehen, aber da ich keine eigenen Klassen erstellt habe, sondern nur die XML-Layouts, die ich aufrufe, habe ich da kleine Schwierigkeiten. Ich kann zwar mit einer kleinen Methode zurück ins Menü-Layout, jedoch wird dort die Listview nicht mehr geladen. Erst, wenn ich das Handy drehe und er gezwungen ist, alles anzupassen, initialisiert er die ListView neu :/

Des Weiteren fliege ich beim Drehen auch aus meinen aufgerufenen Layouts raus und lande automatisch im Menü-Layout.
 
Zuletzt bearbeitet:
Naja beim Drehen wird ja onCreate erneut aufgerufen, also alles neu geladen.

Wieso nimmst du denn keine eigenen Klassen? Oder Fragments?
 
Die App ist mittlerweile sehr umfangreich mit über 30 Methoden (wird ein Taschenrechner, so viel sei verraten). Bisher hat eine Klasse ausgereicht, daher habe ich es dabei gelassen, um keinen "Klassensalat" zu bekommen. Ist (meiner Meinung nach) etwas übersichtlicher, wenn man alles in einer Klasse hat.

Und Fragments... ehrlich gesagt weiß ich bis jetzt noch nicht, was das genau ist... Ich habe erst vor 2 Woche überhaupt mit Programmieren angefangen, bis dato hatte ich nie etwas mit Informatik oder Programmiersprachen zu tun. Das hier ist meine erste App, daher fehlt mir noch ein wenig das Verständnis für manche Sachen :) Aber danke, ich werde mich mal über Fragments informieren und es versuchen :)
 
Ist das 2. layout denn was vollkommenes anderes, oder was soll da passieren?

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
Ja genau. Das erste Layout, das beim App-Start erzeugt wird, ist lediglich das Menü, in der sich sämtliche Verknüpfungen zu allen anderen Layouts und Methoden befinden.

Ich habe nun den Ratschlag befolgt und alle 30 Methoden in separate Klassen unterteilt. Nun scheint es recht gut zu funktionieren. Danke nochmal dafür :)

Mit der Sortierung muss ich noch ein wenig rumspielen. Das komplizierte liegt in diesem Fall ja wirklich nur darin, dass die aufgerufenen Klassen aktuell der Position in der ListView zugeordnet sind, sodass es Probleme geben könnte, wenn die Positionierung der einzelnen Elemente sich ändert. Aber ich schätze, dass sich das auch irgendwie umgehen lässt ;)
 
Ich habe ja keine Ahnung was du genau vorhast aber es klingt auf jeden Fall nach einer Katastrophe wenn es um die Navigation innerhalb der App geht :smile:
 
Wie gesagt.. meine erste App und vorher keine Programmierkenntnisse :D
So schlimm ist es aber nicht, wie es klingt. Eigentlich ist das genau der typische Weg, den man von den meisten Apps kennt. Nur an der Umsetzung hapert es zur Zeit noch etwas, aber es wird besser ;)
 
Wenn ich das richtig sehe hast du ja eine Liste mit Autos.
Warum hast du für jedes Auto ein eigenes layout?
Ist das richtig bzw wo unterscheiden sich die layouts?

Was vermutlich aber besser wäre, wenn du nach jedem klick die gleiche neue Activity aufrufst und das entsprechende Car Objekt übergibts und dann in der neuen Activity entsprechend das layout auswählst anhand des Autos.

Dann bist du auf der "Listenseite" viel flexibler und musst dort nicht für jedes Auto eine neue If-Abfrage einbauen.

Die Frage bleibt aber ob du wirklich jedes mal ein anderes layout brauchst.
 
Die Liste mit den Autos habe ich provisorisch gepostet (kam von einem Tutorial), weil meine Liste noch nicht fertig war. Meine App beherbergt nun eine mathematische Formelsammlung, bei der man Variablen in Textfelder eingeben kann und einem die übrigen Werte berechnet werden. Ganz ähnlich der App "Mathe Experte". Die verschiedenen Layouts sind nötig, weil man immer unterschiedliche und unterschiedlich viele Variablen hat. Auch da habe ich mir überlegt, ob man das nicht mit einer dynamischen ListView oder ähnlichem lösen kann, jedoch funktioniert es aktuell auch prima und mir fehlen dazu einfach noch die Kenntnisse. Sobald die App etwas weiter entwickelt ist, kann ich sie gerne hier zeigen ;)
 
Ah ok.. dann ergibt das evtl sogar Sinn ;)

Du könntest aber den Listview einträgen noch irgend Attribute hinzufügen, dass sie eindeutig kennzeichnet.
Anhand dieses Attributes kannst du dann ja verschiedene layouts aufrufen.
Dann hast du keine probleme mit der Sortierung da du bei einem Click immer ein eindeutiges Attribute hast was du zuordnen kannst.

Das könntest du sogar in einer HashMap speichern, dann sparst du dir noch weitere If-Abfragen oder switches.
 
  • Danke
Reaktionen: SaschaHa²
Danke für den Tipp, das werde ich versuchen :)
 
Leider gestaltest sich das gerade mit meinen Anfänger-Kenntnissen etwas schwieriger, als gedacht.

Hier ist erstmal meine MainActivity. Ich habe die Liste für die Mail auf 3 Items reduziert, damit es übersichtlicher ist.

public class MainActivity extends Activity{
private List<MenuListAdapter> meineFormeln = new ArrayList<MenuListAdapter>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainmenu);

populateCarList();
populateListView();
registerClickCallback();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

private void populateCarList() {
meineFormeln.add(new MenuListAdapter(getString(R.string.BMI), getString(R.string.BMIBeschreibung)));
meineFormeln.add(new MenuListAdapter(getString(R.string.DPI), getString(R.string.DPIBeschreibung)));
meineFormeln.add(new MenuListAdapter(getString(R.string.Beschleunigung), getString(R.string.BeschleunigungBeschreibung)));

// [...]

}
private void populateListView() {
ArrayAdapter<MenuListAdapter> adapter = new MyListAdapter();
ListView list = (ListView) findViewById(R.id.ListViewMenu);
list.setAdapter(adapter);
}

private void registerClickCallback() {
ListView list = (ListView) findViewById(R.id.ListViewMenu);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long id) {

switch(position)
{
case 0:
startActivity(new Intent(MainActivity.this, BMI.class));
break;

case 1:
startActivity(new Intent(MainActivity.this, DPI.class));
break;

case 2:
startActivity(new Intent(MainActivity.this, Beschleunigung.class));
break;
// [...]
}
}
});
}

private class MyListAdapter extends ArrayAdapter<MenuListAdapter> {
public MyListAdapter() {
super(MainActivity.this, R.layout.mainmenulistviewformeln, meineFormeln);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = convertView;
if (itemView == null) {
itemView = getLayoutInflater().inflate(R.layout.mainmenulistviewformeln, parent, false);
}

MenuListAdapter currentCar = meineFormeln.get(position);

TextView nameText = (TextView) itemView.findViewById(R.id.ListViewFormel);
nameText.setText(currentCar.getName());

TextView nameTextBuchstabe = (TextView) itemView.findViewById(R.id.ListViewBuchstabe);
nameTextBuchstabe.setText(currentCar.getName());

TextView beschreibungText = (TextView) itemView.findViewById(R.id.ListViewBeschreibung);
beschreibungText.setText(currentCar.getBeschreibung());

return itemView;
}
}

Und hier ist noch der dazugehörige Adapter (habe die Klasse MenuListAdapter genannt:

public class MenuListAdapter {
private String name;
private String beschreibung;

public MenuListAdapter(String name, String beschreibung) {
super();
this.name = name;
this.beschreibung = beschreibung;
}

public String getName() {
return name;
}
public String getBeschreibung() {
return beschreibung;
}
}

Die Frage nun also: Wie sortiere ich das ganze nach dem Namen, also je nach Sprache nach dem ersten Buchstaben des Strings (zum Beispiel R.string.BMI). Und vor allem, wo? Also in der MainActivity oder mache ich das im Adapter? Oder in einer extra Klasse?

Und damit die zugehörigen onItemClicks nicht durcheinander kommen, muss ich diese ja einer ID zuweisen (wo mir ja bereits zu geraten wurde) anstatt der Position. Wie mache ich das?

Tut mir wirklich Leid, dass ich selbst es nicht hinbekomme, hab einfach gewisse Anfangs-Schwierigkeiten.

Vielen Dank schon mal!!
 
Also die ID kannste ja einfach noch zu deiner MenuListAdapter hinzufügen.
Also als drittes Feld neben name und beschreibung.

Du könntest da auch direkt die passende Klasse hinzufügen und bei onCLick nur noch:
startActivity(new Intent(MainActivity.this, meineFormeln.get(position).getClass()));

oder so ähnlich aufrufen.
 
  • Danke
Reaktionen: SaschaHa²
Hallo Leute,
mit der Arbeit bin ich nun ein ganzes Stück weiter gekommen. Aktuell habe ich ein neues Problem, für das ich nicht extra einen Thread aufmachen möchte. Google hat mir jedoch auch wenig weitergeholfen, daher poste ich es mal hier:

Und zwar möchte ich nun mit einem onClick-Listener Werte einlesen, andere Werte daraus berechnen (Taschenrechner eben), und diese schließlich an eine andere Methode übergeben, um sie eine ListView zu schreiben.

Das Problem ist, dass ich nicht weiß, wie ich die Werte aus meiner onClick-Methode an meine Klasse zurückgeben kann, damit andere Methoden (also vor allem meine ListView) darauf zurückgreifen können.
Die Variablen werden anfangs in meiner Klasse mittels "private double" initialisiert, meine onClick-Methode bearbeitet sie dann. Anschließend sollen sie zurückgegeben und in die ListView eingetragen werden.

Kann mir jemand dort weiterhelfen? Das Schwierige scheint zu sein, dass die onClick-Methode vom Typ "void" sein muss, was die Rückgabe von Werten offenbar verhindert.
Danke schonmal! :)
 
Wenn es Klassenvariablen sind kannst du ja von überall in der Klasse drauf zugreifen. Und sonst kannst du doch aus onClick die entsprechenden Methoden aufrufen.
Wenn also onClick beim klicken von '=' aufgerufen wird, kannst du ja in onClick eine Methode aufrufen, die das Ergebnis berechnet und dann eine, die das Ergebnis in die ListView packt.

Ich hoffe ich habe dein Problem richtig verstanden :p

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
  • Danke
Reaktionen: SaschaHa²
Das ist eine gute Idee, so habe ich es bisher noch nicht probiert! Versuchen werde ich es mal, vielen Dank!

Da fällt mir ein, dass mein Fehler auch darin liegen könnte, dass meine ListView beim Aufrufen der Klasse erstellt und nicht geupdated wird. Das werde ich nun einmal testen :)
 
Zurück
Oben Unten