ImageView - a altura corresponde à largura?

166

Eu tenho uma visualização de imagem. Eu quero que sua largura seja fill_parent. Eu quero que a altura seja a largura que for. Por exemplo:

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

É possível algo assim em um arquivo de layout sem precisar criar minha própria classe de exibição?

obrigado

user291701
fonte
Você descobriu como fazer isso? Suponho que você deseja que a proporção permaneça a mesma. A maioria dessas respostas pressupõe que você deseja que a imagem seja quadrada.
8113 Adam
@ Joe Blow, que é uma péssima maneira de fazer isso #
Aggressor

Respostas:

170

Atualização: 14 de setembro de 2017

De acordo com um comentário abaixo, a porcentagem de biblioteca de suporte está obsoleta a partir da Android Support Library 26.0.0. Esta é a nova maneira de fazer isso:

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

Veja aqui

Descontinuada:

De acordo com esta postagem dos desenvolvedores do Android, tudo o que você precisa fazer agora é agrupar o que quiser dentro de um PercentRelativeLayout ou um PercentFrameLayout e especificar suas proporções, assim

<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
fonte
8
O link para esta resposta tem a solução mais elegante fornecida ao Google. No meu caso, queria que a imagem fosse exibida na proporção 16: 9, independentemente da proporção original da imagem. Funciona bem. Obrigado!
Deixou
No meu caso, soluções como esta não funcionaram, esta funcionou!
Gooey
5
Não se esqueça de adicionar 'com.android.support:percent:23.3.0 compilação' em suas dependências
Milad Faridnia
Parece que essa abordagem está tendo problemas com o WrappedViewPager, que calcula a altura com base no conteúdo filho. Fonte para WrappedViewPager semelhante a gist.github.com/egslava/589b82a6add9c816a007
sha
1
O módulo Porcentagem de suporte foi descontinuado desde a biblioteca de suporte do Android 26.0.0. Fonte: developer.android.com/topic/libraries/support-library/…
MHogge
97

Talvez isso responda sua pergunta:

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

Você pode ignorar o scaleTypeatributo para esta situação específica.

Vlad Stefanescu
fonte
12
Sim, isso é inútil
Fattie
4
Não é necessariamente inútil. Isso funciona bem para o meu uso. Eu tenho um ícone na barra de título que eu quero dimensionar para preencher a altura enquanto permanece quadrado.
Anubian Noob
3
Também resolveu o meu problema.
Dielson Sales
A maneira mais fácil! Isso deve ser marcado como a melhor resposta.
H. Farid
30

Isso pode ser feito usando o LayoutParams para definir dinamicamente a altura das Views assim que você souber a largura das Views em tempo de execução. Você precisa usar um thread Runnable para obter a largura da Views em tempo de execução, ou então você estará tentando definir a Altura antes de saber a largura da View porque o layout ainda não foi desenhado.

Exemplo de como eu resolvi meu problema:

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

Os LayoutParams devem ser do tipo da Visualização pai em que sua visualização está. Meu FrameLayout está dentro de um RelativeLayout no arquivo xml.

    mFrame.postInvalidate();

é chamado para forçar a exibição a redesenhar enquanto estiver em um thread separado do que o thread da interface do usuário

drees
fonte
4
resposta incrível, especialmente com o Runnable, obrigado!
precisa saber é o seguinte
1
Enquanto isso funciona, não é o ideal. A execução na postagem significa que a exibição é renderizada uma vez antes da alteração do layout. Pode permitir um flash de conteúdo na altura errada, antes de desenhar corretamente. Melhor resolver mais cedo. O primeiro momento possível para resolver é durante um costume onMeasure, como mostra a resposta da Regis . Uma alternativa, mas apenas para visualizações renderizadas através de um adaptador, por exemplo GridView, dentro , é a resposta de Matt .
ToolmakerSteve
1
bem, funcionou para mim apenas depois de ligar requestLayout()depois de definir os parâmetros. por que isso seria?
precisa
mFrame.postInvalidate (); foi o que fez, sem ele eu estava tirando a vista da posição.
Jacolack
17

Não consegui que a resposta de David Chu funcionasse para um item do RecyclerView e concluí que precisava restringir o ImageView ao pai. Defina a largura do ImageView 0dpe restrinja seu início e fim ao pai. Não tenho certeza se definir a largura como wrap_contentou match_parentfunciona em alguns casos, mas acho que essa é a melhor maneira de fazer com que o filho de um ConstraintLayout preencha seu pai.

<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>
Shawn Aten
fonte
13

Aqui eu o que fiz para ter um ImageButton que sempre tem uma largura igual à sua altura (e evite margens vazias estúpidas em uma direção ... que considero um bug do SDK ...):

Eu defini uma classe SquareImageButton que se estende do 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);

    }

}

Aqui está o meu 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"
           />

Funciona como um encanto !

Regis_AG
fonte
Sim, essa é a melhor resposta. (e o único que realmente corresponde a questão PO)
Twometer
6

No Android 26.0.0, o PercentRelativeLayout foi descontinuado .

A melhor maneira de resolver isso agora é ConstraintLayoutassim:

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


Aqui está um tutorial sobre como adicionar ConstraintLayoutao seu projeto.

Sebastian Schneider
fonte
6

Se a visualização da imagem estiver dentro de um layout de restrição, você poderá usar as seguintes restrições para criar uma visualização quadrada da imagem

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

Você não pode fazer isso apenas com o layout, tentei. Acabei escrevendo uma aula muito simples para lidar com isso, você pode conferir no github. SquareImage.java Faz parte de um projeto maior, mas nada que uma pequena cópia e cola não pode consertar (licenciado no Apache 2.0)

Basicamente, você só precisa definir a altura / largura igual à outra dimensão (dependendo da maneira que você deseja dimensioná-la)

Nota: Você pode quadrá-lo sem uma classe personalizada usando o scaleTypeatributo, mas os limites da vista se estendem além da imagem visível, o que torna um problema se você estiver colocando outras vistas perto dele.

smith324
fonte
3

Para definir seu ImageView igual à metade da tela, você precisa adicionar o seguinte ao XML para o ImageView:

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

Para definir a altura igual a essa largura, você precisa fazer isso no código. No getViewmétodo do seu GridViewadaptador, defina a ImageViewaltura igual à sua largura medida:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();
Matt Logan
fonte
3

Para as pessoas que passam agora, em 2017, a nova melhor maneira de alcançar o que você deseja é usando o ConstraintLayout assim:

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

E não se esqueça de adicionar restrições a todas as quatro direções, conforme necessário pelo seu layout.

Crie uma interface de usuário responsiva com ConstraintLayout

Além disso, agora, o PercentRelativeLayout foi descontinuado (consulte a documentação do Android ).

Cristina De Rito
fonte
1

Aqui está como eu resolvi esse problema:

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

preview - imageView com largura definida como "match_parent" e scaleType como "cropCenter"

picture - Objeto Bitmap para definir no imageView src.

Isso funciona muito bem para mim.

udenfox
fonte
Você não explicou onde esse código deve ser colocado. Você também não explicou por que o faz, em = vw*ph/pwvez do mais simples = vw. (Eu acho que você fazer isso para preservar a relação de aspecto de imagem de origem de, ao invés da força um preview quadrado.)
ToolmakerSteve
0

Acho que não há como você fazer isso no arquivo de layout XML, e não acho que o android:scaleTypeatributo funcione como você deseja.
A única maneira seria fazê-lo programaticamente. Você pode definir a largura como fill_parent e pode ter a largura da tela como a altura do método Viewou pode usar View.getWidth().

novato
fonte
0

A função ImageView "scaleType" pode ajudá-lo aqui.

Este código manterá a proporção e posicionará a imagem no topo:

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

Aqui está um ótimo post mostrando as possibilidades e aparências do uso de scaleType.

ImageView scaleType samples

ac_banks
fonte
"scaleType" não ajuda aqui. O objetivo é manter o ImageView sempre quadrado, não apenas a imagem dentro dele. Com scaleType, o ImageView pode ser maior que a imagem.
Página
0

eu fiz assim -

layout.setMinimumHeight(layout.getWidth());
HarshitG
fonte