如何根据父视图的尺寸调整Android视图的大小


104

如何根据其父布局的大小调整视图的大小。例如,我有一个RelativeLayout可以填满整个屏幕的,并且我想要一个子视图(例如)ImageView占据整个高度,而宽度占整个宽度的1/2?

我试图重写所有的onMeasureonLayoutonSizeChanged,等我无法得到它的工作....


:可以使用ConstraintLayout要做到这一点,看看这个stackoverflow.com/questions/37318228/...
阿里焾

Answers:


124

我不知道是否有人还在读这个线程,但是Jeff的解决方案只会使您半途而废(按字面意思)。他的onMeasure所要做的就是在一半的父对象中显示一半的图像。问题在于,在之前调用super.onMeasure setMeasuredDimension会根据原始大小测量视图中的所有子项,然后在setMeasuredDimension调整视图大小时将其切成两半。

相反,您需要调用setMeasuredDimension(根据onMeasure覆盖要求)LayoutParams视图提供一个新值,然后调用super.onMeasure。请记住,您LayoutParams是从视图的父类型派生的,而不是视图的类型。

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
   int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
   int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
   this.setMeasuredDimension(parentWidth/2, parentHeight);
   this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

我相信,只有在父母LayoutParams是父母的情况下,父母才会遇到问题AbsoluteLayout(不赞成使用,但有时还是有用的)。


12
以我的经验,这很少起作用,尤其是。当调用fill / match_parent或weights时。在setMeasuredDimension之后更好地调用measureChildren(例如,使用MeasureSpec.makeMeasureSpec(newWidth,MeasureSpec.AT_MOST))。
M. Schenk

1
难道MeasureSpec.getSize(widthMeasureSpec)真的给出正确的parent's宽度是多少?对我来说,它只是返回随机宽度,该宽度与实际宽度非常接近,但不精确。
Konsumierer

1
@ M.Schenk拥有它。我在加权布局中有一个VideoView。我需要将宽度设置为屏幕尺寸的百分比,并且需要保持宽高比。这会拉伸视频,所以wrap_content不会。Vic的答案在这种情况下不起作用,但是@ M.Schenk的注释可以。它还节省了额外的布局通行证。您还应该将其发布为可见性的答案。
dokkaebi 2013年

7
不会super.onMeasure()简单地覆盖并取消先前对的调用的影响this.setMeasuredDimension()吗?
Spinner 2013年

1
正如@Spinner所述,我也很好奇为什么对的调用super.onMeasure()不会覆盖先前的计算。
jwir3 2014年

39

您可以通过创建自定义View并覆盖onMeasure()方法来解决此问题。如果您始终在xml中的layout_width中使用“ fill_parent”,则传递到onMeasusre()方法中的widthMeasureSpec参数应包含父级的宽度。

public class MyCustomView extends TextView {

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        this.setMeasuredDimension(parentWidth / 2, parentHeight);
    }
}   

您的XML看起来像这样:

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <view
        class="com.company.MyCustomView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2
@jeff =>为什么parentWidth / 2 ??
Saeed-rz

6
@Leon_SFS:问题是这样的:“整个高度,是宽度的1/2”
EdgarT 2014年

28

我发现最好不要自己设置测量尺寸。父视图和子视图之间实际上需要进行一些协商,并且您不想重写所有这些代码

但是,您可以做的是修改measureSpecs,然后使用它们调用super。您的视图永远不会知道它正在从其父级收到经过修改的消息,并将为您处理所有事情:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    int myWidth = (int) (parentHeight * 0.5);
    super.onMeasure(MeasureSpec.makeMeasureSpec(myWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}

16

在XML上定义布局和视图时,您可以指定视图的布局宽度和高度,以包装内容或填充父级。占据一半的区域会比较困难,但是如果您想在另一半上拥有某些东西,则可以执行以下操作。

   <LinearLayout android:layout_width="fill_parent"
                android:layout_height="fill_parent">
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
   </LinearLayout>

赋予两个物体相同的重量意味着它们将拉伸以占据屏幕的相同比例。有关布局的更多信息,请参见dev文档。


我不建议这样做,但是...作为一个hack,如果您确实使用上述方法,则可以将其中一个视图设为“虚拟”并设置android:visibility =“ invisible”来填充一半的区域
RickNotFred

仅使用一半面积的目的是什么?您是否打算在另一半显示任何内容?您对其余区域的处理将告知最佳方法
RickNotFred 2010年

这绝对应该是#1-如果可以在xml中进行操作,为什么要在java中进行操作?
fandang 2014年

9

我相信Mayras XML方法可以很简洁。但是,仅通过设置weightSum可以仅使用一个视图使其更准确。我不再将其称为黑客,但我认为这是最简单的方法:

<LinearLayout android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:weightSum="1">
    <ImageView android:layout_height="fill_parent"
               android:layout_width="0dp"
               android:layout_weight="0.5"/>
</LinearLayout>

像这样,您可以使用任何权重,例如0.6(和居中)是我喜欢用于按钮的权重。


3

试试这个

int parentWidth = ((parentViewType)childView.getParent()).getWidth();
int parentHeight = ((parentViewType)childView.getParent()).getHeight();

那么您可以使用LinearLayout.LayoutParams设置chileView的参数

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(childWidth,childLength);
childView.setLayoutParams(params);

2

您现在可以使用PercentRelativeLayout。繁荣!问题解决了。


2
API级别26.0.0-beta1中不推荐使用PercentRelativeLayout。
dzikovskyy

您的意思是“在API级别”?您的意思是库版本号吗?PRL在支持库中,没有API级别。
androidguy

API级别是指Android版本。来自此处的信息developer.android.com/reference/android/support/percent/…。有关API级别的更多信息,请
参见

除非出于某些原因需要版本26.0.0或更高版本,否则您仍然可以使用此类。
androidguy

1

罗马,如果您想使用Java代码(ViewGroup后代)进行布局,则可以。诀窍是您必须同时实现onMeasure和onLayout方法。首先调用onMeasure,然后您需要在那里“测量”子视图(有效地将其调整为所需的值)。您需要在onLayout调用中再次调整其大小。如果您无法执行此序列,或者无法在onMeasure代码的末尾调用setMeasuredDimension(),则不会获得结果。为什么以如此复杂和脆弱的方式设计这个超出了我。


1

如果对方是空的。我猜最简单的方法是添加一个空视图(例如线性布局),然后将两个视图的宽度都设置为fill_parent,并将它们的权重都设置为1。

这适用于LinearLayout ...


0

就像这样:

<RelativeLayout 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"
    tools:context="com.company.myapp.ActivityOrFragment"
    android:id="@+id/activity_or_fragment">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/linearLayoutFirst"
    android:weightSum="100">   <!-- Overall weights sum of children elements -->

    <Spinner
        android:layout_width="0dp"   <!-- It's 0dp because is determined by android:layout_weight -->
        android:layout_weight="50"
        android:layout_height="wrap_content"
        android:id="@+id/spinner" />

</LinearLayout>


<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:layout_below="@+id/linearLayoutFirst"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:id="@+id/linearLayoutSecond">

    <EditText
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="75"
        android:inputType="numberDecimal"
        android:id="@+id/input" />

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="25"
        android:id="@+id/result"/>

</LinearLayout>
</RelativeLayout>

0

很长时间以来,我一直在努力解决这个问题,我想更改DrawerLayout的抽屉宽度,这是其父项的第二个子项。最近我想通了,但不知道是否有更好的主意。

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    super.onLayout(changed, l, t, r, b)
    (getChildAt(1).layoutParams as LayoutParams).width = measuredWidth/2
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.