syllogismos
syllogismos

Reputation: 660

Set of alternate TextViews and ExpandableListView inside a RelativeLayout are not scrollable when they take extra screen space

I have three sets of TextView as a heading and ExpandableListView as content inside a RelativeLayout, that is I have 3 TextViews and 3 ExpandableListViews alternating between each other. Now in devices with smaller screen size, my layouts go out of the view below the screen. So logically the user would try to scroll down. But its not scrolling the way it shouldenter image description here

As shown in the picture above Men, Women, and Kids are TextViews and they have their respective ExpandableListViews each. I also have a list view above for Home and Settings. As seen in the picture most of Kids content is below the screen. But when I try to scroll its having none of it.

Here is my layout file

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#cccc">

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Men"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:layout_below="@id/listView"
        android:id="@+id/menTextView"/>

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/menExpandableListView"
        android:layout_below="@id/menTextView" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="women"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:layout_below="@id/menExpandableListView"
        android:id="@+id/womenTextView"/>

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/womenExpandableListView"
        android:layout_below="@id/womenTextView" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="kids"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:layout_below="@id/womenExpandableListView"
        android:id="@+id/kidsTextView"/>

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/kidsExpandableListView"
        android:layout_below="@id/kidsTextView" />
</RelativeLayout>

This is how I solved it, I just had one Expandable List view and made the other TextViews are Group Headers inside Expandable List View without any children.

As suggested by one of the answers, I had a property that says if my Group is a header, so isHeader() gives if my group is a header or not.

Here is my layout file

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="15"
    android:background="#cccc">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#cccc"
        android:fadeScrollbars="false"
        />

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/expandableListView"
        android:fadeScrollbars="false"
        android:layout_below="@id/listView"
        />
</RelativeLayout>

And my updated getGroupView in the Adapter for expandableListView that extends BaseExpandableListAdapter

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    ProductHeadGroup headGroup = getGroup(groupPosition);
    String header = headGroup.getGroupName();
    if (headGroup.isHeader()) {
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.expandable_list_main_header, null);
        TextView headerTextView = (TextView) convertView.findViewById(R.id.idExpandableHeaderItem);
        headerTextView.setText(header);
    } else {
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.expandable_list_header, null);
        ImageView imageView = (ImageView) convertView.findViewById(R.id.expandableHeaderIcon);
        if (isExpanded){
            imageView.setImageResource(R.drawable.ic_action_collapse_dark);
        } else {
            imageView.setImageResource(R.drawable.ic_action_expand_dark);
        }
        TextView headerTextView = (TextView) convertView.findViewById(R.id.idExpandableHeaderItem);
        headerTextView.setText(header);
    }
    return convertView;
}

As shown above, I implemented my custom expand/collapse indicators having my own ImageView in the GroupLayout. and disabled it in my Activity using

expandableListView.setGroupIndicator(null)

Upvotes: 3

Views: 1188

Answers (2)

Simas
Simas

Reputation: 44188

The whole problem is in your design. First of all RelativeLayout takes up the whole screen (or the free space that's left) thus, the last ExpandableListView becomes very small and practically unscrollable.

To do this right, you should:

  • Make a single ExpandableListView
  • Headers act as empty groups
    • Custom type
      • getGroupTypeCount return 2 (header and non-header)
      • getGroupType return 1 if a header, else return 0
    • Custom layout
      • Determine the group type in getGroupView and inflate accordingly
      • No indicators
  • Custom group indicators
    • Disable default indicators (expListView.setIndicator(null);)
    • Make them a part of your normal group layout (as an ImageView)
    • Set (expanded/collapsed) image at getGroupView and elv.setOnGroupItemClick()
    • Default drawables (action bar icons -> ic_action_expand.png and ic_action_collapse.png)

Looks like a lot of work but in the end it will be worth it.

The result: a dynamic ExpandableListview which scrolls properly no matter how many headers, groups and children you have.

Side note: I'd recommend a CursorTreeAdapter for applying, CursorLoader for fetching and SQLite for storing the data.

Upvotes: 1

Manish Mulimani
Manish Mulimani

Reputation: 17625

RelativeLayout is not scrollable, hence cannot be larger than the physical display.

The first solution that comes to mind is placing RelativeLayout in ScrollView. There are couple of issues with that:

  • You need to set RelativeLayout height to wrap_content when placed inside ScrollView. If ExpandableListView height is set as wrap_content then it's parent height cannot be wrap_content. From docs:

Note: You cannot use the value wrap_content for the android:layout_height attribute of a ExpandableListView in XML if the parent's size is also not strictly specified (for example, if the parent were ScrollView you could not specify wrap_content since it also can be any length. However, you can use wrap_content if the ExpandableListView parent has a specific size, such as 100 pixels.

  • ListView should never be placed under ScrollView. From docs:

You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.

In this specific case, since the view hierarchy is flat (just one level), you should be using LinearLayout instead of RelativeLayout. RelativeLayout will normally make 2 measure pass.

Solution:

Use LinearLayout instead of RelativeLayout and set layout_weight for all the list views including expandable list view, so that left out space is equally divided by all the list views.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#cccc"
    android:orientation="vertical"
    android:weightSum="4">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/listView"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#cccc"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Men"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:id="@+id/menTextView" />

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/menExpandableListView"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="women"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:id="@+id/womenTextView"/>

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/womenExpandableListView"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="kids"
        android:textSize="30dp"
        android:textAllCaps="true"
        android:textAlignment="center"
        android:id="@+id/kidsTextView"/>

    <ExpandableListView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/kidsExpandableListView"/>

</LinearLayout>

Upvotes: 1

Related Questions