Как настроить представление Android на основе его родительских измерений

Как я могу определить размер, основанный на размере его родительского макета. Например, у меня есть RelativeLayout, который заполняет весь экран, и я хочу, чтобы дочерний вид, например ImageView, занимал всю высоту и 1/2 ширину?

Я пробовал переопределить все на onMeasure, onLayout, onSizeChanged и т.д., и я не мог заставить его работать.

Ответ 1

Я не знаю, читает ли кто-нибудь еще эту тему или нет, но решение Джеффа только доставит вас на полпути (буквально). То, что сделает его 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 (который устарел, но все же иногда полезен).

Ответ 2

Это можно решить, создав пользовательский вид и переопределите метод onMeasure(). Если вы всегда используете "fill_parent" для layout_width в вашем xml, тогда параметр widthMeasureSpec, который передается в метод onMeasusre(), должен содержать ширину родительского элемента.

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="fill_parent"
    android:layout_height="fill_parent">
    <view
        class="com.company.MyCustomView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Ответ 3

Я обнаружил, что лучше не вмешиваться в настройку измеренных измерений самостоятельно. На самом деле существует немного согласований между родительским и дочерним представлениями, и вы не хотите переписывать все это code.

Что вы можете сделать, тем не менее, изменить measureSpecs, а затем вызвать супер с ними. Ваш взгляд никогда не узнает, что он получает измененное сообщение от своего родителя и будет заботиться обо всем для вас:

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

Ответ 4

Когда вы определяете макет и представление по 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 docs.

Ответ 5

Я считаю, что XML-подход Mayras может быть аккуратным. Однако можно сделать его более точным, с одним видом, только установив 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 (и центрирование) - это вес, который мне нравится использовать для кнопок.

Ответ 6

Попробуйте это

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

Ответ 7

Теперь вы можете использовать PercentRelativeLayout. Boom! Проблема решена.

Ответ 8

Роман, если вы хотите сделать свой макет в Java-коде (потомком ViewGroup), это возможно. Фокус в том, что вам нужно реализовать методы onMeasure и onLayout. Сначала запускается onMeasure, и вам нужно "измерить" подпункт (фактически его размер до нужного значения). Вам нужно изменить его снова в вызове onLayout. Если вы не выполните эту последовательность или не сможете вызвать setMeasuredDimension() в конце вашего кода onMeasure, вы не получите результаты. Почему это сконструировано таким сложным и хрупким способом, что это вне меня.

Ответ 9

Если другая сторона пуста. Я думаю, самым простым способом было бы добавить пустой вид (например, линейный макет), а затем установить ширину обоих представлений для fill_parent и оба их веса до 1.

Это работает в LinearLayout...

Ответ 10

Что-то вроде этого:

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

Ответ 11

У меня есть другое решение. Мы можем получить ширину и высоту родительского элемента, а затем просто использовать его для вычисления размера и назначения параметров макета.
Вот так:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Don't for get this
    int parentWidth = ((View) getParent()).getMeasuredWidth();
    int parentHeight = ((View) getParent()).getMeasuredHeight();
    if (parentWidth*parentHeight != 0) { // Check if both width and height in non-zero
         LayoutParams lp = getLayoutParams();
         lp.width = parentWidth / 2;
         lp.height = parentHeight;
    }
}