LinearLayout with weight-attributes on children in

2019-07-21 08:45发布

问题:

The usual question regarding ScrollViews seems to be how to use fillViewport to let the ScrollView stretch to the whole screen. My problem is similar, but going the other way :)

I got a LinearLayout that contains multiple elements. All except one element have a fixed height, the special one is an ImageView that should stretch to fill the remaining space. This works fine :)

Now I want to put the LinearLayout into a ScrollView, as some of my elements should expand at runtime (e.g. click on "more"-icon that expands a TextView). In the unexpanded version I would like to have all elements fit on the screen, as if the ScrollView wouldn't exist.

Unfortunately, when wrapping the ScrollView around the LinearLayout, the ImageView is scaled to maxSize und the screen does not fit the screen. Do you have any ideas how to achieve my goal?

I reproduced the problem in an example app to share it with you:

<ScrollView 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:fillViewport="true" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="0px"
            android:layout_weight="1"
            android:background="#ffff0000"
            android:scaleType="fitCenter"
            android:src="@drawable/background" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="80dp"
        android:background="#ff00ff00"
        android:text="element 2"
        tools:context=".MainActivity" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="80dp"
            android:background="#ff00ff00"
            android:text="element 1"
            tools:context=".MainActivity" />
    </LinearLayout>

</ScrollView>

Here are the screenshots from the two versions:

The one above is the Layout with ScrollView (notice the scrollbar and cropping on element 1), the one below without.

Update: The original height of the image in the image-view is bigger than the screen. So it should be downscaled (that's why it has weight 1 and scaleType set).

Solution: The following code solved the problem for me (based on Luksprog answer)

Main Activity (excerpt, change of layout is induced by click on ImageView):

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    scrollView = (ScrollView) findViewById(R.id.scroller);
    frame = (FrameLayout) findViewById(R.id.frame);
    layout = (LinearLayout) findViewById(R.id.layout);

    final ImageView image = (ImageView) findViewById(R.id.image);
    image.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            ImageView image = (ImageView) findViewById(R.id.image);
            frame.removeView(layout);
            scrollView.addView(layout);
            image.getLayoutParams().height = image.getHeight();
        }
    });

}

Layout XML file

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     >

    <ScrollView 
        android:id="@+id/scroller"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent"
        android:fillViewport="true"
        >

    </ScrollView>

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

        <ImageView
            android:id="@+id/image"
            android:layout_width="fill_parent"
            android:layout_height="0px"
            android:layout_weight="1"
            android:background="#ffff0000"
            android:scaleType="fitCenter"
            android:src="@drawable/background" />

        <TextView
            android:id="@+id/text1"
            android:layout_width="fill_parent"
            android:layout_height="80dp"
            android:background="#ff00ff00"
            android:text="element 2"
            tools:context=".MainActivity" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="80dp"
            android:background="#ff00ff00"
            android:text="element 1"
            tools:context=".MainActivity" />
        <TextView
            android:layout_width="fill_parent"
            android:layout_weight="0.1"
            android:layout_height="0px"
            android:background="#ff00ff00"
            android:text="element 3"
            tools:context=".MainActivity" />
    </LinearLayout>

</FrameLayout>

回答1:

As I said in my comments, I don't know if what you're trying to do is possible at the xml level. One option would be to modify your current layout and add a root FrameLayout to which you'll, initially, add the ScrollView and above it, the LinearLayout. In this position the ImageView will behave as you want as the user didn't modify the layout. When you need to show more in your layout you'll detach the LinearLayout from the view hierarchy(with removeView) and attach it to the ScrollView(with addView). You'll reverse this when the user goes back to the initial layout.

This will make the ImageView to have different heights when making the views switch so you'd want to get the height of the ImageView and re set it when doing the switch. To get the height, you could do it in a listener or using the post method in onCreate(as the views haven't been laid out yet at that moment). Also, remember that the user could turn the phone, I don't know if this will affect your layout, but take it consideration.



回答2:

Firstly i tried running your code and it didn't cause any issue for me. The scrollView did not show up although the image was scaled to a ScreenHeight-160dp height which i expected because you have used weight 1 for this imageview.

I would suggest that you remove the weight and give height as wrapcontent. In that case the Imageview will just enclose the Image. When it becomes bigger in size, automatically scrollview come into use if the total heights of all screen contents is more than the screenheight.