Search code examples
androidandroid-studioandroid-constraintlayoutandroid-scrollview

How to make a nested constraint layout inside scrollview to match the size of main parent layout


EDIT: What I wanted is to make the bottom red part with two buttons to take the whole space in the bottom keeping like 88dp margin from top when the screen size is greater than 6.3. What is happening now: the red background does not take the space until the bottom(see the screenshot). I cannot find a way to make the constraint layout expand I want to make the bottom constraint layout inside the scrollView to match the parent layout size, without creating any gap from the bottom. This only happens in 6.3 and higher screen sizes

Here's a screenshot Sceenshot

I tried taking out only the bottom constraint layout with two buttons. It solves the problem somewhat But it makes the view uglier in small screen sizes

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/ic_background"
    tools:context=".presentation.offers.OfferDetailsActiviy">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar_offer_details"
        style="@style/AppToolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:contentInsetStart="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:titleTextAppearance="@style/ToolbarTextAppearance.Title" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar_offer_details">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.cardview.widget.CardView
                android:id="@+id/cardView_offer_details"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginTop="20dp"
                android:layout_marginEnd="20dp"
                app:cardCornerRadius="10dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <ImageView
                        android:id="@+id/iv_offer_details_image"
                        android:layout_width="0dp"
                        android:layout_height="335dp"
                        android:background="@drawable/food_item_temp"
                        android:scaleType="centerCrop"
                        android:src="@drawable/bg_transparent_gradient"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <TextView
                        android:id="@+id/tv_offer_details_name"
                        style="@style/colorBlackTextStyle.size20"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="12dp"
                        android:layout_marginTop="10dp"
                        android:fontFamily="@font/myraid_pro_bold"
                        android:text="Offer Name Here"
                        app:layout_constraintStart_toStartOf="@id/iv_offer_details_image"
                        app:layout_constraintTop_toTopOf="@id/iv_offer_details_image" />


                </androidx.constraintlayout.widget.ConstraintLayout>
            </androidx.cardview.widget.CardView>

            <TextView
                android:id="@+id/tv_offer_details_ends"
                style="@style/colorLightGrayTextStyle.size18"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginTop="15dp"
                android:fontFamily="@font/myraid_pro_semibold"
                android:text="@string/text_offer_ends"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/cardView_offer_details" />

            <TextView
                android:id="@+id/tv_offer_details_end_countdown"
                style="@style/colorBlackTextStyle.size20"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="5dp"
                android:fontFamily="@font/myraid_pro_semibold"
                android:gravity="start"
                android:text="2 Days 10 Hours"
                app:layout_constraintBottom_toBottomOf="@+id/tv_offer_details_ends"
                app:layout_constraintStart_toEndOf="@+id/tv_offer_details_ends" />

            <TextView
                android:id="@+id/label_offer_details_terms"
                style="@style/colorBlackTextStyle.size16"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginTop="16dp"
                android:fontFamily="@font/myraid_pro_regular"
                android:gravity="start"
                android:text="@string/label_terms"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_offer_details_ends" />

            <TextView
                android:id="@+id/tv_offer_details_terms"
                style="@style/colorBlackTextStyle.size16"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginTop="4dp"
                android:layout_marginEnd="20dp"
                android:fontFamily="@font/myraid_pro_regular"
                android:gravity="start"
                android:text="@string/description_offer_terms"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/label_offer_details_terms" />


            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/layout"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="88dp"
                android:background="@color/colorRed"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_offer_details_terms">

                <Button
                    android:id="@+id/btn_redeem_at_cashier"
                    style="@style/PrimaryButtonStyle.padding4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="15dp"
                    android:fontFamily="@font/myraid_pro_bold"
                    android:text="@string/action_redeem_at_cashier"
                    app:layout_constraintBottom_toTopOf="@+id/btn_redeem_and_order"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_chainStyle="packed" />

                <Button
                    android:id="@+id/btn_redeem_and_order"
                    style="@style/PrimaryButtonStyle.padding4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="16dp"
                    android:layout_marginBottom="16dp"
                    android:fontFamily="@font/myraid_pro_bold"
                    android:text="@string/action_redeem_and_order"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/btn_redeem_at_cashier" />

            </androidx.constraintlayout.widget.ConstraintLayout>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • What you haven't mentioned is what is it doing now. You say you want to do something but it's a little unclear to me.

    Are you referring to android:id="@+id/layout"?

    If that's the case, then you're asking way too much here I believe.

    Your hierarchy looks like this:

    <CL> (ConstraintLayout)
       <Toolbar>
       <ScrollView>
          <CL>
            <CardView>
               <CL>
                 <ImageView />
                 <TextView />
               </CL>
            </CardView>
            <TextView />
            <TextView />
            <TextView />
            <TextView />
            <CL>
               <Button>
               <Button>
            </CL>
         </CL>
       </ScrollView>
    </CL>
    

    My initial suggestion before you use any hacks (that you shouldn't like android:fillViewport) is to evaluate if your constraints are fulfilling all the possible directions and sizes.

    That's quite a bit of calculation to perform by the ScrollView (which has to ask its children for their sizes). Something they can't possibly do as written, for some are "wrap" content, but don't have full constraints, meaning they have to wait and measure themselves before being able to tell "I need this amount of space". Now put all this in the measure/layout pass and imagine how long it can take and how painful it is for the engine.

    ScrollViews aren't the best either, for all must be measured for the scrollview to draw its scrollable part (scrollbars, and content).

    I think the missing bit here is maybe a vertical chain, but keep this in mind:

    when you ask a widget to WRAP its content and you only provide ONE constrain, for e.g a TextView that is set to WRAP its height, but only has a "top_to_" constrain (but not a bottom_to...) then the widget doesn't have a known size nor a way to calculate it, until its text is measured (an expensive and slow operation) for you can have any arbitrary font size, padding, etc. A TextView is a simple example, ImagesViews are another similar, since the image source may now be known at compile time and until runtime.

    The way to avoid most of these issues, is to correctly chain the widgets and have them wrap their contents when needed.

    There's a app:layout_constraintHeight_default="wrap" property you can use to let the widget know it can break the constraints if needed.

    I'd suggest you play around with it a little bit more for there's room to improvement in the way you're declaring your constraints.