2

I'm getting the "ScrollView can only host one direct child" error. I realise that this is often (always?) caused by the ScrollView having more than one child - mulitple answers here, here, here, here and here on Stack say to wrap the child in a LinearLayout or similar.

However I am sure that I only have one child of my ScrollView. Please see the below code:

layout\menu.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_medium"
    android:orientation="vertical">

    <include
        android:id="@+id/menu_header"
        layout="@layout/header" />

    <ScrollView
        android:id="@+id/menu_wrapper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <LinearLayout
            android:id="@+id/menu_content"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">


            <!-- Various LinearLayouts displaying menu items -->
            
        </LinearLayout>
    </ScrollView>
</LinearLayout>

menu.java

// When one of the menu items is clicked
FragmentTransaction transaction = getParentFragmentManager().beginTransaction();
transaction.replace(R.id.menu_wrapper, fragment);
transaction.addToBackStack(null);
transaction.commit();

layout\fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_light"
    android:orientation="vertical">

    <include
        android:id="@+id/list_header"
        layout="@layout/header" />

    <include
        android:id="@+id/list_sort"
        layout="@layout/sort" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/inspection_list_header"
        android:layout_alignParentBottom="true">

        <ListView
            android:id="@+id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_above="@+id/list_loading"
            android:divider="@color/background_medium"
            android:dividerHeight="1dp"
            android:listSelector="@drawable/default_focused"
            android:textSize="18sp">

        </ListView>

        <ProgressBar
            android:id="@+id/list_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:indeterminate="true"
            android:indeterminateOnly="true" />
    </RelativeLayout>
</LinearLayout>

fragment.java

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
  View rootView = inflater.inflate(R.layout.list, container, false);
  this.inspectionListView = rootView;
  return rootView;
}

And here is the stack trace:

2022-04-25 13:12:59.725 14833-14833/com.*******.*******.mobile E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.*******.*******.mobile, PID: 14833
    java.lang.IllegalStateException: ScrollView can host only one direct child
        at android.widget.ScrollView.addView(ScrollView.java:494)
        at androidx.fragment.app.FragmentStateManager.addViewToContainer(FragmentStateManager.java:833)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:523)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:216)
        at android.app.ActivityThread.main(ActivityThread.java:7211)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

I'm sure I'm missing something really simple, but I can't work out what. I've inherited this code and am not an Android developer so any help would be much appreciated

Fletch
  • 769
  • 1
  • 12
  • 33
  • I think you should remove scrollview and add fragment to menu_content linearlayout – Jinal Patel Apr 25 '22 at 12:19
  • Thanks @Jinal. When I add my fragment to menu_content it doesn't fill the space. (Although I'm not removing the ScrollView - how can I do that programmatically?) Do I need to adjust my width and height somewhere? – Fletch Apr 25 '22 at 12:26
  • 3
    `transaction.replace(R.id.menu_wrapper, fragment);` – That transaction is adding that `Fragment`'s `View` to `menu_wrapper`, which is the `` that already has the one `` child. Is that really where you meant to put that? It's not going to remove that `` first, if that's what you were thinking. Did you maybe mean to transact it into `R.id.menu_content` instead? – Mike M. Apr 25 '22 at 12:52
  • Why r you using a `ScrollView` as Fragment container thats the issue . Not Sure what u want to achieve . If u want fragment to scroll just have ScrollView inside Fragment don't use it as container . – ADM Apr 25 '22 at 12:54
  • Ah I see, thanks @Mike. I think that makes things a little clearer. Actually I want to replace the entire menu. Is that possible with a fragment or should I convert the fragment into an activity? – Fletch Apr 25 '22 at 13:58
  • 1
    A `FragmentTransaction` will affect only `View`s that belong to `Fragment`s. It will not remove or replace any other `View`s. Additionally, the `R.id` passed in the `replace()` call is for the `Fragment`s' container, not a specific `View` that you want replaced; the `Fragment`s' `View`s are added/removed/replaced/etc. within that container. Given that, yes, you can probably use `Fragment`s here, but you'd need to change the setup a bit; e.g., make the menu section into its own `Fragment` that's loaded at startup into the shared container, and then transact the others as needed. – Mike M. Apr 25 '22 at 14:13
  • 1
    @Mike, ah I see, thanks for the info. I've read through the documentation, but you've summarised it far better! I'll have a bit of a think about how to rearrange things to make it fit what I need. Really appreciate your help – Fletch Apr 26 '22 at 12:16

1 Answers1

0

Give height and width match_parent to menu_content

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/background_medium"
        android:orientation="vertical">
    
        <include
            android:id="@+id/menu_header"
            layout="@layout/header" />
    

        <!-- This view will be used as fragment container -->

        <LinearLayout
                android:id="@+id/menu_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"/>

    </LinearLayout>
Jinal Patel
  • 229
  • 2
  • 7