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

如何根据父视图调整Android视图的大小';s尺寸,android,layout,Android,Layout,如何根据视图父布局的大小调整视图的大小。例如,我有一个填满整个屏幕的相对视图,我想要一个子视图,比如说图像视图,占据整个高度,1/2宽度 我尝试过覆盖所有的onMeasure,onLayout,onSizeChanged,等等,但我无法让它工作….当您在XML上定义布局和视图时,您可以将视图的布局宽度和高度指定为wrap\u content或fill\u parent。占据一半的面积有点困难,但是如果你在另一半上有你想要的东西,你可以做如下的事情 赋予两件东西相同的重量意味着它们将拉伸以占据

如何根据视图父布局的大小调整视图的大小。例如,我有一个填满整个屏幕的
相对视图
,我想要一个子视图,比如说
图像视图
,占据整个高度,1/2宽度


我尝试过覆盖所有的
onMeasure
onLayout
onSizeChanged
,等等,但我无法让它工作….

当您在XML上定义布局和视图时,您可以将视图的布局宽度和高度指定为
wrap\u content
fill\u parent
。占据一半的面积有点困难,但是如果你在另一半上有你想要的东西,你可以做如下的事情



赋予两件东西相同的重量意味着它们将拉伸以占据屏幕的相同比例。有关布局的详细信息,请参见Roman,如果您想使用Java代码(ViewGroup子代)进行布局,则可以。诀窍是您必须同时实现onMeasure和onLayout方法。
首先调用onMeasure,您需要在那里“测量”子视图(有效地将其调整为所需的值)。您需要在onLayout call中重新调整大小。如果您未能执行此序列,或者在onMeasure代码的末尾未能调用setMeasuredDimension(),您将无法获得结果。我无法理解为什么这个设计如此复杂和脆弱。

您可以通过创建自定义视图并重写onMeasure()方法来解决这个问题。如果总是对xml中的布局宽度使用“fill\u parent”,那么传递到onmeasure()方法的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>
<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>

我不知道是否有人还在读这篇文章,但杰夫的解决方案只能让你走到一半(有点像字面意思)。他的onMeasure将在父对象的一半中显示一半的图像。问题是在
setMeasuredDimension
之前调用super.onMeasure将根据原始大小测量视图中的所有子视图,然后在
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
(不推荐使用,但有时仍然有用)时,才会出现问题。

如果另一侧为空。我想最简单的方法是添加一个空视图(例如线性布局),然后将两个视图的宽度设置为“填充父视图”,并将其权重设置为1


这在线性布局中有效…

我发现最好不要自己设置测量尺寸。实际上,在父视图和子视图之间存在一些协商,您不想重新编写所有这些

但是,您可以做的是修改measurespec,然后使用它们调用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);
}
我相信这是可以做到的。但是,可以通过设置权重和使其更精确,只使用一个视图。我不再称之为黑客,但我认为这是最直接的方法:

<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(和居中)是我喜欢用于按钮的重量。

它是这样的:

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

试试这个

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

现在可以使用PercentRelativeLayout。繁荣问题已解决。

我一直在努力解决这个问题,我想更改抽屉布局的抽屉宽度,它是其父项的第二个子项。 最近我想出来了,但不知道有没有更好的主意

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
}

我不推荐这样做,但是……作为黑客,如果你使用上述方法,你可以将其中一个视图设置为“虚拟”,并将android:visibility=“invisible”设置为填充一半区域,那么只使用一半区域的目的是什么?你打算在另一半展示什么吗?您对剩余区域所做的工作将告诉您最佳的方法这肯定应该是#1-如果您可以在xml中执行,为什么要在java中执行?根据我的经验,这很少起作用,尤其是在调用填充/匹配父项或权重时。最好在设置MeasuredDimension后调用measureChildren(例如,使用MeasureSpec.MakeMasureSpec(newWidth,MeasureSpec.AT_))。
MeasureSpec.getSize(widthMeasureSpec)
真的给出了正确的父级宽度吗?对我来说,它只是返回非常接近实际宽度的随机宽度,但不精确。@M.Schenk有它。我有一个加权布局内的视频视图。我需要的宽度是屏幕大小的一个百分比,我需要保持纵横比。这会拉伸视频,因此
包装内容
不起作用。维克的回答不适用于这种情况,但@M.Schenk的评论适用。它还保存了一个额外的布局过程。您还应该将其作为可见性的答案发布。对
super.onMeasure()
的调用不会简单地覆盖并消除先前对
this.setMeasuredDimension()的调用的影响吗?正如@Spinner所提到的,我也很好奇,为什么要调用
super.onMeasure()
没有覆盖前面的计算。@jeff=>为什么parentWidth/2???@Leon_SFS:问题是:“整个高度,1/2宽度”PercentRelativeLayout在API级别26.0-beta1中被弃用。你说的“在API级别”是什么意思?你是说图书馆版本号吗?