Android: genaue layout_height einer Listview (genauso wie wrap_content)

Manchmal könnte ich ausrasten, wenn ich mit XML-Layouts von Android arbeite. Besonders bei trivialen Anforderungen, die einfach so funktionieren sollten. Heute hatte ich folgendes Problem:
Ich wollte 2 Listviews passgenau in einem Navigation-Drawer platzieren, jedoch wurde mir nur ein Eintrag jeder Liste angezeigt. (Siehe Abbildung rechts) Theoretisch hätte es mit den Attributen

            <ListView
            android:id="@+id/NavigationDrawer_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#cccc"
            android:choiceMode="singleChoice"
            android:divider="@android:color/white"
            android:dividerHeight="1dp" />

funktionieren sollen. Jedoch stellte sich heraus, dass eine Listview noch einmal in einer ScrollView eingepackt ist und das Attribut „android:layout_height“ mit dem Parameter wrap_content nicht funktioniert. Aus diesem Grund habe ich mir folgende Methode geschrieben.

 

Die Methode

Die Methode hat eine ganz einfache Aufgabe – Sie ermittelt die reale Höhe der Listview und aktualisiert diese.

	/** Berechnet die Hoehe einer Listview aufgrund seiner Eintraege.
	 * @param listView die Liste
	 */
	private void setListViewHeight(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            throw new IllegalArgumentException("ListView beinhaltet keinen ListAdapter");
        }

        int totalHeight = 0;
        int desiredWidth = 0;
        
        // Breite der Liste bestimmen
        // +++ ACHTUNG +++ BITTE DIE RICHTIGE METHODE AUSWAEHLEN!!!!!!!
        // Methode fuer eine Activity
        desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
        // Wenn die Variable "desiredWidth" -21212.. ist, dann nur mit listView.getWidth() oder mit einem anderen Element arbeiten!
        // Methode fuer eine Liste in einem Naviagation-Drawer
        //desiredWidth = Math.round(getActivity().getResources().getDimension(R.dimen.navigation_drawer_width));
        
        // fuer jedes Element die Groesse bestimmen und dazu addieren
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
            totalHeight += listItem.getMeasuredHeight();
        }

        // neue Hoehe der Listview setzen und Element aktualisieren
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
        listView.requestLayout();
    }

 

Die Anwendung

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

		// View holen
		View v = inflater.inflate(R.layout.navigation_drawer_fragment, container, false);
		
		// Listen holen
		ListView list1 = (ListView) v.findViewById(R.id.NavigationDrawer_list);
		ListView list2 = (ListView) v.findViewById(R.id.NavigationDrawer_list2);
		
		// irgendwie einen Adapter setzen ;-)
		mDrawerListView.setAdapter(new ArrayAdapter<String>(getActionBar().getThemedContext(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, new String[] { getString(R.string.title_section1), getString(R.string.title_section2), getString(R.string.title_section3), }));
		omg.setAdapter(new ArrayAdapter<String>(getActionBar().getThemedContext(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, new String[] { getString(R.string.title_section1), getString(R.string.title_section2), getString(R.string.title_section3), getString(R.string.title_section3),  getString(R.string.title_section3) }));
		
		// die neue Methode aufrufen!
		setListViewHeight(list1);
		setListViewHeight(list2);
		
		return v;
	}

 

Anmerkung

Wenn ihr einen eigenen Adapter schreibt müsst ihr darauf achten, dass ihr den „parent“ mit beachtet!!! Sonst kommt: android.view.InflateException: Binary XML file line #14: Error inflating class fragment

public View getView(int position, View convertView, ViewGroup parent) {
    convertView = layoutInflater.inflate(R.layout.dein_layout, parent, false);

 

Variante 2: Nimm keine ListView

Wenn nichts mehr geht und die Funktion nicht funktioniert. Erstell einfach ein leeres LinearLayout und nutze diese Funktion:

		MeinListAdapter myAdapter = new MeinListAdapter(getActivity(), myList);
		LinearLayout ll = (LinearLayout) v.findViewById(R.id.NavigationDrawer_ll);

		 for (int i = 0; i < myAdapter .getCount(); i++) {
	            View listItem = myAdapter .getView(i, null, ll);
	            listItem.setClickable(true);
	            listItem.setOnClickListener(new meinListener(getActivity(), myList.get(i)));
	            ll.addView(listItem);
	            
	            if(i < (myAdapter .getCount() - 1)){
	            	View trenner = new View(getActivity());
	            	float density = getActivity().getResources().getDisplayMetrics().density;
	            	float px = 1 * density;
	            	trenner.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, Math.round(px)));
	            	trenner.setBackgroundColor(Color.GRAY);
	            	ll.addView(trenner);
	            }
	        }
		 ll.requestLayout();

 

Das Ergebnis

Das Ergebnis sieht so aus:
navigationdrawer

 

Copyright © 2014 AxxG – Alexander Gräsel




1 Antwort : “Android: genaue layout_height einer Listview (genauso wie wrap_content)”

  1. DDraum sagt:

    Ein sehr erstklassiger Post, der alles hervorragend zusammen fasst. Ich habe mich damals auch durch alle Anfänger-Guides gelesen bevor ich dann nutzliche Mitteilung gefunden habe. Bei mir ist es immer so, dass ich die meisten Empfehlungen für mehr Einflussbereiche zwar kenne, aber dann doch nicht umsetzte. So einen Publikation zu lesen motiviert dann wieder – habe ich gedacht und bin weiter gesurft. Sowas ist äußerst dienstbeflissen! Aber es gibt noch ein Thema dazu – Virtuelle Datenräume. Es ist vor allem schön zu wissen, dass alle mal klein angefangen habe. Das ist zwar eigentlich klar, aber wird gern vergessen.

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.