親のサイズに基づいてAndroidビューのサイズを設定する方法


104

親レイアウトのサイズに基づいてビューのサイズを変更するにはどうすればよいですか。たとえばRelativeLayout、画面全体に表示されるがあり、子ビュー、たとえばImageViewを使用して、高さ全体、幅の半分を占めるようにしますか?

私は上のすべてを上書きしようとしたonMeasureonLayoutonSizeChanged...、などと私は仕事にそれを得ることができませんでした


:それはConstraintLayoutを使用してそれを行うことが可能である、このチェックstackoverflow.com/questions/37318228/...
アリNemと

回答:


124

まだこのスレッドを読んでいる人がいるかどうかはわかりませんが、Jeffの解決策では途中までしか表示されません(文字通り)。彼のonMeasureが行うことは、画像の半分を親の半分に表示することです。問題は、の前にsuper.onMeasureを呼び出すsetMeasuredDimensionと、ビューのすべての子が元のサイズに基づいて測定され、setMeasuredDimensionサイズが変更されたときにビューが半分にカットされることです。

代わりに、setMeasuredDimension(onMeasureオーバーライドの必要に応じて)呼び出しLayoutParams、ビューに新しいを提供してから、呼び出す必要がありますsuper.onMeasureLayoutParamsは、ビューのタイプではなく、ビューの親タイプから派生していることに注意してください。

@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の後で(たとえば、MeasureSpec.makeMeasureSpec(newWidth、MeasureSpec.AT_MOST)を使用して)、measureChildrenを呼び出す方が適切です。
M.シェンク、2011

1
MeasureSpec.getSize(widthMeasureSpec)本当に正しいparent'sは幅与えますか?私にとっては、実際の幅に非常に近いが正確ではないランダムな幅を返すだけです。
Konsumierer

1
@M。シェンクはそれを持っています。加重レイアウト内にVideoViewがあります。幅を画面サイズのパーセンテージにする必要があり、アスペクト比を維持する必要があります。これはビデオを引き伸ばすので、しwrap_contentません。Vicの回答はこのシナリオでは機能しませんが、@ M.Schenkのコメントは機能します。また、追加のレイアウトパスも節約できます。また、可視性のために回答として投稿する必要があります。
ドッカビ2013年

7
super.onMeasure()以前の呼び出しの効果を単に無効にして無効にする呼び出しではありthis.setMeasuredDimension()ませんか?
スピナー

1
@Spinnerが述べたように、なぜへの呼び出しsuper.onMeasure()が以前の計算を上書きしないのか、私も興味があります。
jwir3 14年

39

これを解決するには、カスタムビューを作成し、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 2013年

6
@Leon_SFS:質問はそれを要求します:「高さ全体、幅の1/2」
EdgarT '

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>

2つのものに同じ重みを与えると、画面の同じ割合を占めるように伸縮します。レイアウトの詳細については、開発者向けドキュメントをご覧ください


私はこれはお勧めしませんが...ハックとして、上記のアプローチを使用する場合、これらのビューの1つを「ダミー」にして、android:visibility = "invisible"を設定して領域の半分を埋めることができます
RickNotFred

半分の面積だけを使用する目的は何ですか?残り半分に何か展示する予定はありますか?残りの領域で何をするかが最善のアプローチを示します
RickNotFred 2010年

これは間違いなく#1である必要があります-xmlで実行できる場合、なぜJavaで実行できるのですか?
ファンダン14

9

MayrasのXMLアプローチきっとうまくいく思います。ただし、weightSumを設定するだけで、1つのビューでより正確にすることができます。私はこれをハックとは呼びませんが、私の意見では最も簡単なアプローチです:

<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
PercentRelativeLayoutは、APIレベル26.0.0-beta1で廃止されました。
dzikovskyy 2017

「APIレベル」とはどういう意味ですか?ライブラリのバージョン番号ですか?PRLはサポートライブラリにあり、APIレベルはありません。
androidguy 2017

APIレベルとは、Androidのバージョンを意味します。こちらのdeveloper.android.com/reference/android/support/percent/…からの情報。APIレベルについての詳細情報はこちらdeveloper.android.com/guide/topics/manifest/...
dzikovskyy

何らかの理由でバージョン26.0.0以降が必要でない限り、このクラスを引き続き使用できます。
androidguy 2017

1

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

私はこの質問に長い間取り組んでいますが、親の2番目の子である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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.