ImageView - высота соответствует ширине?

166

У меня есть изображение. Я хочу, чтобы его ширина была fill_parent. Я хочу, чтобы его высота равнялась ширине. Например:

<ImageView
  android:layout_width="fill_parent"
  android:layout_height="whatever the width ends up being" />

Возможно ли что-то подобное в файле макета без необходимости создавать собственный класс представления?

Спасибо

user291701
источник
Вы выяснили, как это сделать? Я предполагаю, что вы хотите, чтобы соотношение сторон оставалось прежним. Большинство из этих ответов предполагают, что вы хотите, чтобы изображение было квадратным.
Адам
@ Joe Удар, это ОЧЕНЬ плохой способ сделать это
Агрессор

Ответы:

170

Обновление: 14 сентября 2017

Согласно комментарию ниже, библиотека поддержки процентов устарела начиная с библиотеки поддержки Android 26.0.0. Это новый способ сделать это:

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

</android.support.constraint.ConstraintLayout>

Смотри здесь

Запрещены:

Согласно этому сообщению разработчиков Android, все, что вам нужно сделать сейчас, это обернуть все, что вы хотите, в PercentRelativeLayout или PercentFrameLayout, а затем указать его отношения, например, так

<android.support.percent.PercentRelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        app:layout_widthPercent="100%"
        app:layout_aspectRatio="100%"/>

</android.support.percent.PercentRelativeLayout>
davidchuyaya
источник
8
Ссылка на этот ответ имеет самое элегантное решение, предоставленное Google. В моем случае я хотел, чтобы изображение отображалось в соотношении 16: 9 независимо от того, каково исходное соотношение сторон изображения. Прекрасно работает. Спасибо!
LETS
В моем случае, решения, подобные этому , не сработали, это сработало!
Gooey
5
не забудьте добавить «compile com.android.support:percent:23.3.0» в ваши зависимости
Милад Фаридния
Похоже, что у этого подхода есть проблемы с WrappedViewPager, который вычисляет высоту на основе его дочернего содержимого. Источник для WrappedViewPager похож на gist.github.com/egslava/589b82a6add9c816a007
ша
1
Модуль поддержки Percent объявлен устаревшим, устарел с момента появления библиотеки поддержки Android 26.0.0. Источник: developer.android.com/topic/libraries/support-library/...
MHogge
97

Может быть, это ответит на ваш вопрос:

<ImageView
    android:id="@+id/cover_image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true" />

Вы можете игнорировать scaleTypeатрибут для этой конкретной ситуации.

Влад Стефанеску
источник
12
Да, это бесполезно
Толстяк
4
Это не обязательно бесполезно. Это отлично работает для моего использования, у меня есть значок на заголовке, который я хочу масштабировать, чтобы заполнить высоту, оставаясь при этом квадратным.
Анубиан Нуб
3
Решил и мою проблему тоже.
Продажи Dielson
Самый простой способ! Это должно быть помечено как лучший ответ.
Х. Фарид
30

Это можно сделать с помощью LayoutParams, чтобы динамически установить высоту представлений, когда вы знаете ширину представлений во время выполнения. Вам нужно использовать поток Runnable, чтобы получить ширину представлений во время выполнения, иначе вы будете пытаться установить высоту до того, как узнаете ширину представления, поскольку макет еще не нарисован.

Пример того, как я решил свою проблему:

final FrameLayout mFrame = (FrameLayout) findViewById(R.id.frame_id);

    mFrame.post(new Runnable() {

        @Override
        public void run() {
            RelativeLayout.LayoutParams mParams;
            mParams = (RelativeLayout.LayoutParams) mFrame.getLayoutParams();
            mParams.height = mFrame.getWidth();
            mFrame.setLayoutParams(mParams);
            mFrame.postInvalidate();
        }
    });

LayoutParams должен относиться к типу родительского представления, в котором находится ваше представление. Мой FrameLayout находится внутри RelativeLayout в xml-файле.

    mFrame.postInvalidate();

вызывается, чтобы заставить представление перерисовываться, находясь в отдельном потоке, чем поток пользовательского интерфейса

Дреес
источник
4
отличный ответ, особенно с Runnable, спасибо!
jesses.co.tt
1
Хотя это работает, это не идеально. Запуск по почте означает, что представление визуализируется один раз до изменения макета. Может позволить флэш-контент на неправильной высоте, прежде чем рисовать правильно. Лучше решить раньше. Самый ранний возможный момент для решения - это обычай onMeasure, как показано в ответе Региса . Ответом , но только для представлений, представленных через адаптер, например, изнутри GridView, является ответ Мэтта .
ToolmakerSteve
1
ну у меня это сработало только после звонка requestLayout()после установки параметров. с чего бы это?
Divins Mathew
mFrame.postInvalidate (); это то, что сделал, без этого я получал вид из позиции.
Жаколак
17

Я не смог получить ответ Дэвида Чу для работы с элементом RecyclerView и понял, что мне нужно ограничить ImageView для родителя. Установите ширину ImageView 0dpи ограничьте его начало и конец родительским. Я не уверен, что установка ширины wrap_contentили match_parentработает в некоторых случаях, но я думаю, что это лучший способ получить дочерний элемент ConstraintLayout для заполнения его родителя.

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="1:1"/>

</android.support.constraint.ConstraintLayout>
Шон Атен
источник
13

Вот что я сделал, чтобы ImageButton всегда имел ширину, равную его высоте (и избегал глупых пустых полей в одном направлении ... что я считаю ошибкой SDK ...):

Я определил класс SquareImageButton, который выходит из ImageButton:

package com.myproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;

    public class SquareImageButton extends ImageButton {

        public SquareImageButton(Context context) {
        super(context);


        // TODO Auto-generated constructor stub
    }

    public SquareImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

    }

    public SquareImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    int squareDim = 1000000000;

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


        int h = this.getMeasuredHeight();
        int w = this.getMeasuredWidth();
        int curSquareDim = Math.min(w, h);
        // Inside a viewholder or other grid element,
        // with dynamically added content that is not in the XML,
        // height may be 0.
        // In that case, use the other dimension.
        if (curSquareDim == 0)
            curSquareDim = Math.max(w, h);

        if(curSquareDim < squareDim)
        {
            squareDim = curSquareDim;
        }

        Log.d("MyApp", "h "+h+"w "+w+"squareDim "+squareDim);


        setMeasuredDimension(squareDim, squareDim);

    }

}

Вот мой XML:

<com.myproject.SquareImageButton
            android:id="@+id/speakButton"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerInside"
            android:src="@drawable/icon_rounded_no_shadow_144px"
            android:background="#00ff00"
            android:layout_alignTop="@+id/searchEditText"
            android:layout_alignBottom="@+id/searchEditText"
            android:layout_alignParentLeft="true"
           />

Работает как шарм!

Regis_AG
источник
Да, это лучший ответ. (и единственный, который действительно соответствует вопросу ОП)
Twometer
7

Если ваш вид изображения находится внутри макета ограничения, вы можете использовать следующие ограничения для создания квадратного вида изображения

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:id="@+id/ivImageView"
    app:layout_constraintDimensionRatio="W,1:1"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>
ChaturaM
источник
6

В Android 26.0.0 PercentRelativeLayout устарела .

Лучший способ решить эту проблему теперь ConstraintLayoutтак:

<android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

    <ImageView android:layout_width="match_parent"
               android:layout_height="0dp"
               android:scaleType="centerCrop"
               android:src="@drawable/you_image"                       
               app:layout_constraintDimensionRatio="1:1"/>


</android.support.constraint.ConstraintLayout>


Вот учебник о том, как добавить ConstraintLayoutв свой проект.

Себастьян Шнайдер
источник
5

Вы не можете сделать это только с макетом, я пытался. Я закончил тем, что написал очень простой класс для обработки, вы можете проверить это на github. SquareImage.java Это часть более крупного проекта, но ничего, что можно скопировать и вставить не удается (лицензировано под Apache 2.0)

По сути, вам просто нужно установить высоту / ширину, равную другому измерению (в зависимости от того, как вы хотите его масштабировать)

Примечание. Вы можете сделать его квадратным без пользовательского класса, используя scaleTypeатрибут, но границы представления выходят за пределы видимого изображения, что создает проблему, если вы размещаете рядом другие представления.

smith324
источник
3

Чтобы установить ImageView равным половине экрана, вам нужно добавить следующее в ваш XML для ImageView:

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:scaleType="fitXY"
    android:adjustViewBounds="true"/>

Чтобы затем установить высоту, равную этой ширине, вам нужно сделать это в коде. В getViewметоде вашего GridViewадаптера установите ImageViewвысоту, равную его измеренной ширине:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();
Мэтт Логан
источник
3

Для людей, проходящих мимо, в 2017 году, новый лучший способ добиться того, чего вы хотите, - это использовать ConstraintLayout, например:

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:layout_constraintDimensionRatio="1:1" />

И не забудьте добавить ограничения для всех четырех направлений в соответствии с вашими требованиями.

Создайте адаптивный интерфейс с ConstraintLayout

Кроме того, к настоящему времени PercentRelativeLayout устарел (см. Документацию Android ).

Кристина Де Рито
источник
1

Вот как я решил эту проблему:

int pHeight =  picture.getHeight();
int pWidth = picture.getWidth();
int vWidth = preview.getWidth();
preview.getLayoutParams().height = (int)(vWidth*((double)pHeight/pWidth));

Предварительный просмотр - imageView с шириной, установленной в «match_parent» и scaleType в «cropCenter»

picture - Растровый объект для установки в imageView src.

Это работает очень хорошо для меня.

udenfox
источник
Вы не объяснили, где этот код должен быть помещен. Вы также не объяснили, почему вы делаете, = vw*ph/pwа не проще = vw. (Я думаю , что вы делаете это , чтобы сохранить пропорции исходного изображения, а не силу квадратный предварительный просмотр.)
ToolmakerSteve
0

Я не думаю, что есть какой-то способ сделать это в файле макета XML, и я не думаю, что android:scaleTypeатрибут будет работать так, как вы этого хотите.
Единственным способом было бы сделать это программно. Вы можете установить ширину fill_parent и либо принять ширину экрана в качестве высоты, Viewлибо использовать View.getWidth()метод.

новичек
источник
0

Функция ImageView «scaleType» может помочь вам в этом.

Этот код сохранит соотношение сторон и разместит изображение сверху:

android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitStart"

Вот отличный пост, показывающий возможности и возможности использования scaleType.

Образцы ImageView scaleType

ac_banks
источник
«scaleType» здесь не помогает. Цель состоит в том, чтобы сам ImageView всегда был квадратным, а не только изображение внутри него. С scaleType ImageView может быть больше, чем изображение.
ToolmakerSteve
0

мне так понравилось -

layout.setMinimumHeight(layout.getWidth());
HarshitG
источник