Yury Fedorov
Yury Fedorov

Reputation: 14938

PercentRelativeLayout 23.2.1 inside ScrollView incorrect zero height

I have a layout that contains a ScrollView with a LinearLayout and its children: a PercentRelativeLayout 23.2.1, another LinearLayout below it and another PercentRelativeLayout after that. Inside the middle LinearLayout I have a RecyclerView (LinearLayoutManager, vertical). You may see an example below.

At runtime, when I fill the RecyclerView with data, its size grows since I start with an empty one. Once its height changes to exceed the screen size, the upper image of a car (id = car), that has a percentage value as its height, is gone from a screen completely. When I scroll this screen up and down, I reach both top and bottom edges and don't see the image.

I also have percentage values in one more place in this layout, and they define marginTop. These margins disappear as well. Width-dependent percentage values work fine. The java code does not contain visibility changes for an image and does not adjust margins.

I'm currently not sure whether this issue is related to the specific version of a support library, I was building this screen at the same time that this library was released. Also, I don't see this issue on Marshmallow, only on Lollipop and below. I would appreciate any help on how to solve this issue.

<!-- a container for all views that should scroll -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <!-- the first block of views - they need percents -->
    <android.support.percent.PercentRelativeLayout
        android:id="@+id/carHolder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/car"
            android:layout_width="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:src="@drawable/car"
            app:layout_heightPercenet="25%"/>

        <ImageView
            android:id="@+id/sliderBg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/car"
            android:layout_centerHorizontal="true"
            android:src="@drawable/slider_bg"/>

    </android.support.percent.PercentRelativeLayout>

    <!-- a middle block of views, they don't need percents -->
     <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

         <android.support.v7.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

    </LinearLayout>

    <!-- another block of views, they need percents -->
    <android.support.percent.PercentRelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <!-- some other views --> 

    </android.support.percent.PercentRelativeLayout>

</LinearLayout>

UPDATE

I see this issue in support library 23.3.0 as well, and not only when I populate the RecyclerView, but each time the ScrollView exceeds the screen height.

Upvotes: 4

Views: 1415

Answers (3)

Sai Krishna
Sai Krishna

Reputation: 261

Unfortunately, percent layout won't work with ScrollView before M. The reason for that is that they depend on the size hint being delivered in the measuring step. Before M most layouts would provide size hint 0 when sending unspecified measure spec.

You can try to fix that by creating your own subclass of ScrollView and overriding measureChild and measureChildWithMargins (fortunately both are protected) to provide the size hint. source- plus.google.com

You can use this CustomScrollView to make percentRelativeLayout to work

public class CustomScrollView extends ScrollView {


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

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

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

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int size = 0;
    int width = getMeasuredWidth();
    int height = getMeasuredHeight();

    if (width > height) {
        size = height;
    } else {
        size = width;
    }
    setMeasuredDimension(size, size);
}
}

Source is PercentRelativeLayout inside ScrollView

Upvotes: 2

Yury Fedorov
Yury Fedorov

Reputation: 14938

It happens that layout_aspectRatio parameter works fine here, and since I know the width of the view as well, I can get to the preferred height by using this parameter and percent based width. With this solution the height will depend on the screen's width, which may be a problem with varying sizes.

<ImageView
    android:id="@+id/car"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:src="@drawable/car"
    app:layout_aspectRatio="175%"
    app:layout_widthPercent="70%"/>

I'll mark this answer as a temporal solution and accept any other answer that helps solving the issue the right way.

Upvotes: 1

Pablo Baxter
Pablo Baxter

Reputation: 2234

Although this isn't an answer on how to solve the issue with PercentRelativeLayout, this is an example of how to use percentages in a layout, in case that is all you are looking for.

<!-- a container for all views that should scroll -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <!-- the first block of views - they need percents -->
    <LinearLayout
        android:id="@+id/carHolder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:weightSum="1">

        <ImageView
            android:id="@+id/car"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="0.25"
            android:layout_gravity="center_horizontal"
            android:src="@drawable/car" />

        <ImageView
            android:id="@+id/sliderBg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:src="@drawable/slider_bg"/>

    </LinearLayout>

    <!-- a middle block of views, they don't need percents -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </LinearLayout>

    <!-- another block of views, they need percents -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:weightSum="1">

        <!-- some other views -->

    </LinearLayout>

</LinearLayout>

Here's a nice explanation about it too!

LinearLayout weightSum Reference

Upvotes: 0

Related Questions