android listview display all available items without scroll with static header
Asked Answered
M

13

39

I'm having a little difficulties while trying to get a certain layout to work: I want to have list. List does not have to be scrollable, but should be shown completely. But the page itself should be able to scroll (with the lists in it), if the total content ist higher than the screen.

<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >

     <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/linear_layout"
         android:orientation="vertical"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:background="#ff181818"
         >
           <Textview android:id="@+id/my_text" text="header contents goes here" android:layout_width="fill_parent" android:layout_height="wrap_content"/>
           <Textview android:id="@+id/headertext" text="header contents goes here" android:layout_width="fill_parent" android:layout_height="wrap_content"/>

          <ListView
               android:id="@+id/my_list1"
               android:layout_height="wrap_content"
               android:layout_width="fill_parent"
          /> 
     </LinearLayout> 

</ScrollView>

it only uses a small part of the screen (about 2 lines per list), instead of filling the available height, and the lists themselves can be scrolled. How can I change the layout to always show the whole lists but have the screen be scrollalbe?

Merce answered 22/11, 2009 at 11:39 Comment(2)
anddev.org/viewtopic.php?p=25194 On another forum i found comment some thing like this "since a ListView already has scrolling capacity. Therefore I have rewritten my custom list to inherit from LinearLayout, which works fine in a ScrollView. I don't know if that's the only way, but it achieves what I wanted to do for now." can you guys help me out how to code above scenario ?Merce
..could you please provide us with some code and the xml layout in which you could achieve the entire the screen to be scrolled...thanks...Camillacamille
T
65

The solution I used is to replace ListView with LinearLayout. You can create all your items inside LinearLayout, they will all be displayed. So there's really no need to use ListView.

LinearLayout list = (LinearLayout)findViewById(R.id.list_recycled_parts);
for (int i=0; i<products.size(); i++) {
  Product product = products.get(i);
  View vi = inflater.inflate(R.layout.product_item, null);
  list.addView(vi);
}
Touch answered 24/12, 2009 at 14:20 Comment(10)
Shouldn't you pass the object to inflate?Magbie
what is R.layout.product_item??Barneybarnhart
Linear layout is hardly a replacement. List view has built-in adapter (to fill the item views), dividers between items, item states, item click event.Selfdrive
But how can we handle OnItemClick?Trigon
Not to mention, listview has performance benefits in reusing the row views. If you have a large number of rows then linear layout isn't going to work, scrolling will be extremely choppy.Interradial
What about ListView's benefits? Are they all gone because of the scroll?Ribosome
This is a roundabout at best, not real solution.Jetty
This is bad approach, because ListView can use Adapter, and LinearLayout can't.Cookson
I know everyone says this is a bad approach but a ListView shouldnt be placed inside of a ScrollView. This approach would allow such if you don't need click ability and are only showing a few things. FYI. For those wondering you can populate using the "vi" view as it is your layout for the row. Just my 2 cents.Fester
You can follow this answer: #40861636Melancholic
G
48

As @Alex noted in the accepted answer that LinearLayout is hardly a replacement. I had a problem where LinearLayout was not an option, that's when i came across this blog. I will put the code here for reference purposes. Hope it helps someone out there!

public class UIUtils {

    /**
     * Sets ListView height dynamically based on the height of the items.
     *
     * @param listView to be resized
     * @return true if the listView is successfully resized, false otherwise
     */
    public static boolean setListViewHeightBasedOnItems(ListView listView) {

        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter != null) {

            int numberOfItems = listAdapter.getCount();

            // Get total height of all items.
            int totalItemsHeight = 0;
            for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
                View item = listAdapter.getView(itemPos, null, listView);
                item.measure(0, 0);
                totalItemsHeight += item.getMeasuredHeight();
            }

            // Get total height of all item dividers.
            int totalDividersHeight = listView.getDividerHeight() *
                    (numberOfItems - 1);

            // Set list height.
            ViewGroup.LayoutParams params = listView.getLayoutParams();
            params.height = totalItemsHeight + totalDividersHeight;
            listView.setLayoutParams(params);
            listView.requestLayout();

            return true;

        } else {
            return false;
        }

    }
}

Usage:

//initializing the adapter
listView.setAdapter(adapter);
UIUtils.setListViewHeightBasedOnItems(listView);

//whenever the data changes
adapter.notifyDataSetChanged();
UIUtils.setListViewHeightBasedOnItems(listView);
Guardant answered 12/3, 2016 at 7:47 Comment(7)
The best solution for this issue :)Shepperd
Works like a charm, but shouldn't UIUtils.setListViewHeightBasedOnItems(adapter); be UIUtils.setListViewHeightBasedOnItems(listView); ?Mcnutt
Seems to work. Pretty much the same as https://mcmap.net/q/37329/-disable-scrolling-of-a-listview-contained-within-a-scrollview, I think.Acre
if text in item in listview have more than one line it's not work ,How to fix itDisputation
Oh man, love you. You are awesome, it worked as required. @Merce this should be the accepted answerDapple
This worked great! Minor modification when you use relative inflated layouts: Before measure: v.setLayoutParams(new ViewGroup.LayoutParams(0,0));Chinaman
The best solution.. Thank youMinda
C
17

You can make your own customlistview. (It can extends ListView/ExpandableListView/GridView) and override the onMeasure method with this. With this you'll never need to call a function or anything. Just use it in your xml.

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
            MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
}
Campo answered 5/12, 2016 at 14:51 Comment(3)
This is a much better answer as it is an extensible and clean approach.Ultramicroscopic
It looks very clean. I wonder with this one can we place listview inside scrollview?Fairlead
@Fairlead I haven't try that... But the only thing that change is the onMeasure method, all the scroll methods of the ListView are still working but with nothing to scroll. So if the listview is inside the scrollview I think it will still override those methods. I would look for another approach to do that.Campo
L
13

I had a ListView in my layout and wanted to use a library which can't handle a ListView here because it wraps it into a ScrollView. The best solution for me is based on Fedor´s answer.

Since I already got an ArrayAdapter for the ListView I wanted to re-use it:

LinearLayout listViewReplacement = (LinearLayout) findViewById(R.id.listViewReplacement);
NamesRowItemAdapter adapter = new NamesRowItemAdapter(this, namesInList);
for (int i = 0; i < adapter.getCount(); i++) {
    View view = adapter.getView(i, null, listViewReplacement);
    listViewReplacement.addView(view);
}

For me this works fine because I just need to display dynamic data varying from 1 to 5 elements. I just had to add my own divider.

Lachellelaches answered 7/3, 2015 at 17:13 Comment(1)
this is the best idea to make a static list with all visible itemsVibrio
C
5

If someone still has the problem then you can make customList and add onMesure() method just like I implemented it:

public class ScrolleDisabledListView extends ListView {

private int mPosition;

public ScrolleDisabledListView(Context context) {
    super(context);
}

public ScrolleDisabledListView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public ScrolleDisabledListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;

    if (actionMasked == MotionEvent.ACTION_DOWN) {
        // Record the position the list the touch landed on
        mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
        return super.dispatchTouchEvent(ev);
    }

    if (actionMasked == MotionEvent.ACTION_MOVE) {
        // Ignore move events
        return true;
    }

    if (actionMasked == MotionEvent.ACTION_UP) {
        // Check if we are still within the same view
        if (pointToPosition((int) ev.getX(), (int) ev.getY()) == mPosition) {
            super.dispatchTouchEvent(ev);
        } else {
            // Clear pressed state, cancel the action
            setPressed(false);
            invalidate();
            return true;
        }
    }

    return super.dispatchTouchEvent(ev);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
            MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
}
}
Counterblast answered 10/3, 2017 at 10:47 Comment(1)
This is exactly what I was looking for! I have a ListView, it contains 3-4 items. I cannot use static elements as I need all the functionality of the ListView and that solved my problem when I put it in the ScrollView!Baptiste
H
1

Check this out:

ListView ignoring wrap_content

Using android:layout_height and android:layout_weight solved it for me:

<ListView
    android:layout_height="0dp"
    android:layout_weight="1"
    />
Horsa answered 18/11, 2011 at 20:3 Comment(0)
M
1

I just did it using setting params of ListView

public static void setListViewHeightBasedOnChildren(ListView listView) {

    //this comes from value from xml tag of each item
    final int HEIGHT_LARGE=75;
    final int HEIGHT_LARGE=50;
    final int HEIGHT_LARGE=35;
    ViewGroup.LayoutParams params = listView.getLayoutParams();

    int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;

    switch(screenSize) {

    case Configuration.SCREENLAYOUT_SIZE_LARGE:
         params.height =(int) (HEIGHT_LARGE*size);
         break;
    case Configuration.SCREENLAYOUT_SIZE_NORMAL:
         params.height =(int) (HEIGHT_NORMAL*size);
         break;
    case Configuration.SCREENLAYOUT_SIZE_SMALL:
          params.height =(int) (HEIGHT_SMALL*size);
          break;
    }
    listView.setLayoutParams(params);  
}
Mcdougal answered 4/12, 2014 at 8:42 Comment(2)
listview has advantage of using adapter.using linear layout doesn't implement this convenient feature.Mcdougal
you can make it with listview not only linear layoutMcdougal
B
1

I don't have a static header, but using HussoM's post as a clue, here is what I was able to get to work. In my scenario, the height of the items in the list was non-uniform, due to variable text sentences in each of the items, and I am using wrap_content for the height and match_parent for the width.

public class NonScrollableListView extends ListView {

  public NonScrollableListView(Context context) {
      super(context);
  }

  public NonScrollableListView(Context context, AttributeSet attrs) {
      super(context, attrs);
  }

  public NonScrollableListView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
  }

  public NonScrollableListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
      super(context, attrs, defStyleAttr, defStyleRes);
  }

  /**
   * Measure the height of all the items in the list and set that to be the height of this
   * view, so it appears as full size and doesn't need to scroll.
   * @param widthMeasureSpec
   * @param heightMeasureSpec
   */
  @Override
  public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      ListAdapter adapter = this.getAdapter();
      if (adapter == null) {
          // we don't have an adapter yet, so probably initializing.
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          return;
      }

      int totalHeight = 0;

      // compute the height of all the items
      int itemCount = adapter.getCount();
      for (int index=0; index<itemCount; index++) {
          View item = adapter.getView(index, null, this);
          // set the width so it can figure out the height
          item.measure(widthMeasureSpec, 0);
          totalHeight += item.getMeasuredHeight();
      }

      // add any dividers to the height
      if (this.getDividerHeight() > 0) {
          totalHeight += this.getDividerHeight() * Math.max(0, itemCount - 1);
      }

      // make it so
      this.setMeasuredDimension(widthMeasureSpec,
              MeasureSpec.makeMeasureSpec(totalHeight, MeasureSpec.EXACTLY));
  }

}

Bedad answered 27/8, 2018 at 21:30 Comment(0)
C
0

If all items has the same height

        int totalItemsHeight = baseDictionaries.size() * item.getMeasuredHeight();
        int totalDividersHeight = listView.getDividerHeight() * (baseDictionaries.size() - 1);
        int totalPadding = listView.getPaddingBottom() + listView.getPaddingTop();

        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) listTranslationWords.getLayoutParams();
        lp.height = totalItemsHeight + totalDividersHeight + totalPadding;
        listTranslationWords.setLayoutParams(lp);
Cauldron answered 23/2, 2017 at 21:17 Comment(0)
E
0

Iam supprised no one see this.U cant have two scrolls on the same layout. 1st u have a scrollview and then u have a list, i bet u are killing some android good practices there.

Essene answered 23/2, 2017 at 21:46 Comment(0)
V
0

If you want a simple solution to this problem without extending ListView class, this is a solution for you.

 mListView.post(new Runnable() {
        @Override
        public void run() {
            int height = 0;
            for(int i = 0; i < mListView.getChildCount();i++)
                height += mListView.getChildAt(i).getHeight();
            ViewGroup.LayoutParams lParams = mListView.getLayoutParams();
            lParams.height = height;
            mListView.setLayoutParams(lParams);
        }
    });
Vichy answered 17/10, 2017 at 11:8 Comment(0)
C
0

In my case, I had ListView inside ScrollView and scrollview was shrinking listview by default. So I just add this in my ScrollView and it worked for me

android:fillViewport="true"
Carney answered 30/1, 2021 at 11:29 Comment(0)
B
-6

Set android:layout_height="fill_parent" in your LinearLayout

Bresee answered 24/2, 2010 at 23:24 Comment(1)
Nope, sadly this will not help - a ListView will always attempt to scroll its contents. So although it's not as nice as ListView, LinearLayout is the way to go here.Lietuva

© 2022 - 2024 — McMap. All rights reserved.