【问题标题】:WRAP_CONTENT not working after dynamically adding views动态添加视图后 WRAP_CONTENT 不起作用
【发布时间】:2014-01-25 18:50:31
【问题描述】:

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

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

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

任何帮助将不胜感激...我的手动计算似乎不足以考虑不同的设备,尽管事实上我正在考虑屏幕密度并且我手动将 RelativeLayout 强制为恒定宽度.

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

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

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;
}

【问题讨论】:

  • 首先,您可能应该为此使用列表视图或网格视图。其次,布局参数在下一次布局传递之后才会应用。您是否尝试过调用 invalidate() 或 requestLayout()?
  • invalidate()、requestLayout() 和 forceLayout() 似乎都什么都不做......我不明白的是这一切还在 onCreateView 中,没有任何东西被绘制或布局添加所有这些视图的时间。

标签: android android-layout


【解决方案1】:

尝试对孩子调用 requestLayout。

我最近遇到了类似的问题,并且同样对像 invalidate 和 requestLayout 这样的事情似乎什么也没做感到沮丧。我不明白的是 requestLayout 不会传播到它的孩子; it propagates up to its parents。要重新测量之前测量的内容,我必须在更改的视图上调用 requestLayout,而不是在我实际想要调整大小的视图上调用。

【讨论】:

  • 你没有在这个答案中展示任何代码示例
  • 如果能添加代码示例就好了。
【解决方案2】:

一旦“wrap_content”显示,Android 不会刷新视图的布局。

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

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

这里提供了代码和使用说明:

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

享受吧!

【讨论】:

  • 提供示例代码来展示您的库的使用将非常有用
【解决方案3】:

使用 WRAP_CONTENT 更新 View 大小的简单方法是将可见性更改为 GONE 并恢复为旧可见性。

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

2014 年在安卓果冻豆上测试

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

【讨论】:

  • 在 JellyBean 上对我不起作用
【解决方案4】:

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

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

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

【讨论】:

  • 为什么是mainLayout.getMeasuredHeight() + 10?这似乎是一个非常糟糕的解决方法
  • 这对我有用。我必须“测量”添加了孩子的 LinearLayout。当我在父 ViewGroup 上尝试测量时,它没有向下传播。 (我还删除了“+10”)(这是在 JellyBean 上)
【解决方案5】:

我在使用LinearLayout 时遇到了同样的问题,wrap_content 和一个孩子为TextView match_parent

为了解决这个问题,我这样做了:

以编程方式删除TextView,然后重新添加。

linearLayout.removeView(textView)
linearLayout.addView(textView)

我知道这听起来很愚蠢,但它确实有效。 在我的情况下,调用 invalidate 不起作用,只有这个起作用。

根据您的实现,您需要处理其父级中的视图索​​引

【讨论】:

    【解决方案6】:

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

    您是在告诉布局包装到还不是他们的内容。抓取内容后尝试使用布局充气器

    【讨论】:

    • 我不需要先膨胀片段以便能够找到需要添加自定义视图的元素吗?还是我误解了你的评论?
    • 这个答案是有史以来最糟糕的建议
    【解决方案7】:

    你应该使用 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>
    

    这是自定义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;
            }
        }
    

    活动中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);
            }
        }
    

    这里是示例 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>
    

    【讨论】:

      【解决方案8】:

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

      如果父 View 是 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);
      

      【讨论】:

        【解决方案9】:

        将 layout_width 设置为某个特定的 dp 解决了我的问题。

        所以从“包装内容”或“匹配父项”更改 到

        android:layout_width="300dp"
        

        会修复它,但我知道它不是适用于所有情况的解决方案。但也许你有一些父宽度,所以你可以将宽度应用于文本视图。 高度离开 wrap_content,它会工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-01-29
          • 2020-05-19
          • 1970-01-01
          • 1970-01-01
          • 2019-08-05
          • 2023-03-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多