Android 动态添加视图后 WRAP_CONTENT 不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20982632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:46:31  来源:igfitidea点击:

WRAP_CONTENT not working after dynamically adding views

androidandroid-layout

提问by brainfree

I'm trying to create a fragment that lays out a series of custom views dynamically. The main content for this layout is a RelativeLayout nested in a LinearLayout (to center it horizontally), nested in a ScrollView.

我正在尝试创建一个动态布局一系列自定义视图的片段。此布局的主要内容是嵌套在 LinearLayout 中的 RelativeLayout(使其水平居中),嵌套在 ScrollView 中。

The RelativeLayout has a few TextViews and a 9 patch ImageView that is meant to scale with the dynamically added custom views. However, the image (achievements_bgImageView below) is ending up as the size of the screen, and is not respecting the size of its parent RelativeLayout even after I've added the appropriate amount of custom views. The image scales fine when I manually set the size of achievements_mainLayout (see the commented out lines below), but does nothing if I try to let that RelativeLayout's wrap_content handle its own sizing.

RelativeLayout 有几个 TextViews 和一个 9 补丁 ImageView,旨在随着动态添加的自定义视图进行缩放。但是,图像(下面的achievements_bgImageView)最终是屏幕的大小,并且即使在我添加了适当数量的自定义视图之后也不尊重其父RelativeLayout的大小。当我手动设置 results_mainLayout 的大小时,图像可以很好地缩放(请参阅下面注释掉的行),但是如果我尝试让该 RelativeLayout 的 wrap_content 处理它自己的大小,则不会执行任何操作。

The ScrollView IS respecting the size of the RelativeLayout, as all the content is present, it's simply the imageView that isn't stretching to match the content at this point.

ScrollView 尊重RelativeLayout 的大小,因为所有内容都存在,所以此时只是imageView 没有拉伸以匹配内容。

Any help would be appreciated... My manual calculations don't seem to be good enough to account for different devices, despite the fact I'm accounting for screen density and I'm manually forcing the RelativeLayout to a constant width.

任何帮助将不胜感激...我的手动计算似乎不足以说明不同的设备,尽管我考虑了屏幕密度并且我手动将相对布局强制为恒定宽度。

It's worth noting that the measured size of the RelativeLayout is always equal to the height of the screen, regardless of whether or not the sum of its content is greater or less than that height. So, essentially, WRAP_CONTENT is simply not doing what it's supposed to be doing. I have nothing referencing any edge of of the RelativeLayout, so circular dependencies shouldn't be a problem.

值得注意的是,RelativeLayout 的测量大小始终等于屏幕的高度,无论其内容的总和是否大于或小于该高度。所以,本质上, WRAP_CONTENT 根本没有做它应该做的事情。我没有引用 RelativeLayout 的任何边缘,所以循环依赖应该不是问题。

fragment_achievements.xml

fragment_achievements.xml

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true" >

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal">

        <RelativeLayout
                android:layout_width="320dp"
                android:layout_height="wrap_content"
                android:id="@+id/achievements_mainLayout">

            <ImageView
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:id="@+id/achievements_bgImageView"
                    android:src="@drawable/bkg_achievements9"
                    android:adjustViewBounds="true"
                    android:layout_marginLeft="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_centerHorizontal="true"
                    android:scaleType="fitXY"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Name Field"
                    android:id="@+id/achievements_nameTextView"
                    android:layout_alignParentTop="true"
                    android:layout_alignParentLeft="true"
                    android:layout_marginLeft="28dp"
                    android:layout_marginTop="30dp"/>

            <ImageView
                    android:layout_width="52dp"
                    android:layout_height="52dp"
                    android:id="@+id/achievements_avatarImageView"
                    android:layout_below="@+id/achievements_nameTextView"
                    android:layout_alignLeft="@+id/achievements_nameTextView"
                    android:src="@drawable/achieve_avatar"
                    android:layout_marginTop="5dp"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:text="Top Moment:"
                    android:id="@+id/textView2"
                    android:layout_alignBottom="@+id/achievements_avatarImageView"
                    android:layout_toRightOf="@+id/achievements_avatarImageView"
                    android:layout_marginBottom="16dp"
                    android:layout_marginLeft="4dp"
                    android:textSize="12dp"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:text="Me Overall:"
                    android:id="@+id/textView3"
                    android:layout_alignTop="@+id/textView2"
                    android:layout_alignLeft="@+id/textView2"
                    android:layout_marginTop="16dp"
                    android:textSize="12dp"/>

            <TextView
                    android:layout_width="52dp"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:text="153"
                    android:id="@+id/achievements_totalPointsTextView"
                    android:gravity="center"
                    android:layout_alignTop="@+id/achievements_avatarImageView"
                    android:layout_alignRight="@+id/achievements_bgImageView"
                    android:layout_alignEnd="@+id/achievements_bgImageView"
                    android:layout_marginRight="31dp"
                    android:textColor="#f7a033"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Moment"
                    android:id="@+id/achievements_topMomentTextView"
                    android:layout_alignTop="@+id/textView2"
                    android:layout_toRightOf="@+id/textView2"
                    android:layout_marginLeft="5dp"
                    android:textSize="12dp"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="153"
                    android:id="@+id/achievements_overallTextView"
                    android:layout_alignTop="@+id/textView3"
                    android:layout_toRightOf="@+id/textView3"
                    android:layout_marginLeft="5dp"
                    android:textSize="12dp"/>

        </RelativeLayout>
    </LinearLayout>
</ScrollView>

AchievementFragment.java

成就片段.java

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View fragmentView = null;

    fragmentView = inflater.inflate(R.layout.fragment_achievements, container, false);

    ImageView avatarImageView = (ImageView)fragmentView.findViewById(R.id.achievements_avatarImageView);

    ...

    // Basic Achievement List Setup
    RelativeLayout mainLayout = (RelativeLayout)fragmentView.findViewById(R.id.achievements_mainLayout);
    AchievementRow currentRow = null;

    List achievementTypeList = CampaignManager.sharedManager().sortedAchievementTypeList();

    int achievementCount = achievementTypeList.size();

    for (int i = 0; i < achievementCount; i++) {
        AchievementType achievementType = (AchievementType)achievementTypeList.get(i);

        // Every third achievement creates a new row.
        if ((i % 3) == 0) {
            AchievementRow row = (AchievementRow)inflater.inflate(R.layout.widget_achievementrow, null);

            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);

            if (currentRow == null) {
                layoutParams.addRule(RelativeLayout.BELOW, avatarImageView.getId());
                layoutParams.setMargins(10, 70, 10, 0);
            } else {
                layoutParams.addRule(RelativeLayout.BELOW, currentRow.getId());
                layoutParams.setMargins(10, 10, 10, 0);
            }

            layoutParams.addRule(RelativeLayout.ALIGN_LEFT, backgroundImageView.getId());
            layoutParams.addRule(RelativeLayout.ALIGN_RIGHT, backgroundImageView.getId());

            row.setLayoutParams(layoutParams);
            row.setId(i+1);
            mainLayout.addView(row);

            currentRow = row;
        }

        // Now setup the Button
        AchievementButton achievementButton = currentRow.buttonForIndex(i % 3);
        achievementButton.achievementType = achievementType;
        achievementButton.setOnClickListener(achievementButtonListener);
        achievementButton.setVisibility(View.VISIBLE);

        CacheManager.sharedManager().fetchAchievementThumbnail(getActivity(), achievementButton, achievementType);
    }

    // This is the manual scaling of mainLayout
    // float scale = getResources().getDisplayMetrics().density;
    // float headerHeight = scale * 150.0f;
    // float rowHeight = scale * 78.0f;
    // ViewGroup.LayoutParams mainLayoutParams = mainLayout.getLayoutParams();
    // mainLayoutParams.height = (int)(headerHeight + (Math.ceil(achievementCount / 3.0) * rowHeight));

    return fragmentView;
}

回答by elliotbay

Try calling requestLayout on the children.

尝试在孩子上调用 requestLayout 。

I recently had a similar problem and was similarly frustrated that things like invalidate and requestLayout seemed to do nothing. What I didn't understand is that requestLayout doesn't propagate down to its children; it propagates up to its parents. To re-measure something that was previously measured, I had to call requestLayout on the View that changedrather than the View I actually wanted to resize.

我最近遇到了类似的问题,并且同样感到沮丧的是,invalidate 和 requestLayout 之类的东西似乎什么也没做。我不明白的是 requestLayout 不会传播到它的孩子;它传播到它的父母。为了重新测量之前测量过的东西,我不得不在改变的视图上调用 requestLayout而不是我真正想要调整大小的视图。

回答by Eric

Android does NOT refresh layout of views with "wrap_content" once it has been displayed.

显示后,Android 不会使用“wrap_content”刷新视图布局。

So if you add a child view, or modify the content dynamically, you're screwed. I do agree that this is a nightmare and a real flaw in Android UI!

所以如果你添加一个子视图,或者动态修改内容,你就完蛋了。我同意这是一场噩梦,也是 Android UI 中的一个真正缺陷!

To solve that, I've written a static class that recomputes the sizes and forces the update of the layout for the views with "wrap_content"

为了解决这个问题,我编写了一个静态类,它重新计算大小并使用“wrap_content”强制更新视图的布局

The code and instructions to use are available here:

代码和使用说明可在此处获得:

https://github.com/ea167/android-layout-wrap-content-updater

https://github.com/ea167/android-layout-wrap-content-updater

Enjoy!

享受!

回答by Jairo Correa

A simple way to update the size of a View with WRAP_CONTENT is change the visibility to GONE and back to the old visibility.

使用 WRAP_CONTENT 更新视图大小的一种简单方法是将可见性更改为 GONE 并返回到旧可见性。

int visibility = view.getVisibility();
view.setVisibility(View.GONE);
view.setVisibility(visibility);


TESTED ON ANDROID JELLY BEAN IN 2014

2014 年在安卓软糖上测试

MAY NOT WORK ON NEWER ANDROID VERSIONS

可能不适用于较新的 Android 版本

回答by Barry Connolly

You are getting this problem because you set your layout first and then add its content dynamically.

您遇到此问题是因为您先设置布局,然后动态添加其内容。

You are telling the layout to wrap to the content that is not yet their. Try using your layout inflater after you have grabbed your content

您正在告诉布局包装到尚不属于它们的内容。抓取内容后尝试使用布局充气器

回答by brainfree

Ok, I solved this by manually measuring the RelativeLayout immediately after adding all the views and setting the mainLayoutParams height explicitly. I wish I was smarter and knew why it wasn't automatically doing this correctly in the first place, but oh well.

好的,我通过在添加所有视图并显式设置 mainLayoutParams 高度后立即手动测量 RelativeLayout 解决了这个问题。我希望我更聪明,并且知道为什么它首先不会自动正确地执行此操作,但是哦,好吧。

    ...
    mainLayout.measure(0, 0);

    ViewGroup.LayoutParams mainLayoutParams = mainLayout.getLayoutParams();
    mainLayoutParams.height = mainLayout.getMeasuredHeight() + 10;
    ...

回答by Md. Taiful Islam

You should use NestedScrollView Instead of simple scrollview. here is my sample Activity Layout code

您应该使用 NestedScrollView 而不是简单的滚动视图。这是我的示例活动布局代码

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F0ECE6"
    >

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="fixed"
            app:tabIndicatorHeight="6dp"
            android:layout_marginTop="-10dp"
            app:tabGravity="fill"/>
    </android.support.design.widget.AppBarLayout>

    <wsit.rentguru.utility.CustomViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"  />
</android.support.design.widget.CoordinatorLayout>

here is code for custom viewpager

这是自定义viewpager的代码

public class CustomViewPager extends ViewPager {

        private boolean enabled;

        public CustomViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.enabled = false;
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (this.enabled) {
                return super.onTouchEvent(event);
            }

            return false;
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            if (this.enabled) {
                return super.onInterceptTouchEvent(event);
            }

            return false;
        }

        public void setPagingEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }

setup function for viewpager in the activity

活动中viewpager的设置功能

private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new SampleFragment(), " ");

        viewPager.setAdapter(adapter);
    }

class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }

here is the sample SampleFragment layout code

这是示例 SampleFragment 布局代码

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#F0ECE6"
    android:fillViewport="true"
    android:scrollbars="vertical"
    android:animateLayoutChanges="true"
    xmlns:android="http://schemas.android.com/apk/res/android">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F0ECE6"
    android:focusableInTouchMode="true"
   >

    <Spinner
        android:id="@+id/product_category"
        android:layout_margin="20dp"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@drawable/edittext_rectangle_box"
        android:gravity="center|left"
        android:textSize="14sp"
        android:paddingLeft="10dp"
        android:drawableRight="@drawable/ic_down_arrow"
        />

    <Spinner
        android:id="@+id/product_sub_category"
        android:layout_below="@+id/product_category"
        android:layout_marginRight="20dp"
        android:layout_marginLeft="20dp"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center|left"
        android:visibility="gone"
        android:paddingLeft="10dp"
        android:background="@android:color/white"
        android:drawableRight="@drawable/ic_down_arrow"
        />
    <EditText
        android:id="@+id/product_title"
        android:layout_below="@+id/product_sub_category"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="15dp"
        android:background="@android:color/white"
        android:hint="PRODUCT TITLE"
        android:singleLine="true"
        android:imeOptions="actionDone"
        android:layout_width="match_parent"
        android:gravity="center|left"
        android:padding="10dp"
        android:textSize="14sp"
        android:textColorHint="#000000"
        android:layout_height="40dp" />

    <LinearLayout
        android:id="@+id/availability_layout"
        android:layout_below="@+id/product_title"
        android:layout_marginRight="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/availability"
            android:textStyle="bold"
            android:paddingBottom="10dp"
            android:textSize="14sp"
            />

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:weightSum="2">

            <Button
                android:id="@+id/from"
                android:background="@android:color/white"
                android:hint="FROM"
                android:layout_weight="1"
                android:gravity="center|left"
                android:padding="10dp"
                android:textSize="14sp"
                android:textStyle="normal"
                android:textColorHint="#000000"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:layout_marginRight="10dp"/>

            <Button
                android:id="@+id/to"
                android:background="@android:color/white"
                android:hint="TO"
                android:layout_weight="1"
                android:gravity="center|left"
                android:padding="10dp"
                android:textSize="14sp"
                android:textColorHint="#000000"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:layout_marginLeft="10dp"/>



        </LinearLayout>


    </LinearLayout>


    <LinearLayout
        android:id="@+id/product_location_layout"
        android:layout_below="@+id/availability_layout"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/product_location"
            android:textStyle="bold"
            android:paddingBottom="10dp"
            android:textSize="14sp"
            />


        <Spinner
            android:id="@+id/state_spinner"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="@drawable/edittext_rectangle_box"
            android:gravity="center|left"
            android:textSize="14sp"
            android:layout_marginBottom="10dp"
            android:drawableRight="@drawable/ic_down_arrow"
            android:paddingLeft="10dp"
            />

        <EditText
            android:id="@+id/area"
            android:background="@android:color/white"
            android:hint="Area"
            android:gravity="center|left"
            android:padding="10dp"
            android:textSize="14sp"
            android:textColorHint="#000000"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:singleLine="true"
            android:imeOptions="actionNext"
            android:layout_marginBottom="10dp"
            />


        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:weightSum="2">

            <EditText
                android:id="@+id/zipCode"
                android:background="@android:color/white"
                android:hint="Zip Code"
                android:layout_weight="1"
                android:gravity="center|left"
                android:padding="10dp"
                android:textSize="14sp"
                android:textColorHint="#000000"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:singleLine="true"
                android:imeOptions="actionNext"
                android:layout_marginRight="10dp"/>

            <EditText
                android:id="@+id/city"
                android:background="@android:color/white"
                android:hint="City"
                android:layout_weight="1"
                android:gravity="center|left"
                android:padding="10dp"
                android:textSize="14sp"
                android:singleLine="true"
                android:imeOptions="actionDone"
                android:textColorHint="#000000"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:layout_marginLeft="10dp"/>



        </LinearLayout>


    </LinearLayout>

    <Button
        android:id="@+id/tab1_next"
        android:layout_width="150dp"
        android:layout_height="40dp"
        android:text="NEXT"
        android:layout_below="@+id/product_location_layout"
        android:layout_margin="20dp"
        android:layout_alignParentRight="true"
        android:background="@color/next_button"
        android:textColor="@android:color/white"
        android:layout_marginBottom="20dp"
        />

</RelativeLayout>

</android.support.v4.widget.NestedScrollView>

回答by kc ochibili

Set the layout parameters again(width and height), right after adding the view. This worked for me.

添加视图后,再次设置布局参数(宽度和高度)。这对我有用。

if the parent View is a FrameLayout, then do something like this:

如果父视图是 FrameLayout,则执行以下操作:

    ImageView view = (ImageView) LayoutInflater.from(activity).inflate(R.layout.image_object_view, null);

    imageObjectsHolder.addView(view);
    FrameLayout.LayoutParams param = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    view.setLayoutParams(param);

回答by Hyman The Ripper

My problem was fixed by seting layout_width to some specific dp.

我的问题是通过将layout_width 设置为某些特定的 dp 来解决的

So changing from "wrap content" or "match parent" to

所以从“包装内容”或“匹配父级”更改为

android:layout_width="300dp"

will fix it, but i know it's not solution for all cases. But maybe you have some parent width, so you can apply the width to the textview. height leave with wrap_content, and it will work.

会解决它,但我知道这不是所有情况的解决方案。但也许您有一些父宽度,因此您可以将宽度应用于 textview。高度离开 wrap_content,它会起作用。