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



Kommentar verfassen