ImageView: ¿la altura coincide con el ancho?

166

Tengo una vista de imagen. Quiero que su ancho sea fill_parent. Quiero que su altura sea cualquiera que sea el ancho. Por ejemplo:

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

¿Es posible algo así en un archivo de diseño sin tener que crear mi propia clase de vista?

Gracias

usuario291701
fuente
¿Has descubierto cómo hacer esto? Supongo que desea que la relación de aspecto permanezca igual. La mayoría de estas respuestas asumen que quieres que la imagen sea cuadrada.
Adam
@ Joe Blow que es una MUY mala manera de hacerlo
Agresor

Respuestas:

170

Actualización: 14 de septiembre de 2017

Según un comentario a continuación, el porcentaje de biblioteca de soporte está en desuso a partir de Android Support Library 26.0.0. Esta es la nueva forma de hacerlo:

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

Ver aquí

Obsoleto:

De acuerdo con esta publicación de Desarrolladores de Android, todo lo que necesita hacer ahora es ajustar lo que quiera dentro de un PercentRelativeLayout o un PercentFrameLayout, y luego especificar sus proporciones, de esta manera

<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
fuente
8
El enlace de esta respuesta tiene la solución más elegante proporcionada por Google. En mi caso, quería que la imagen se mostrara en una relación de 16: 9 sin importar la relación de aspecto de la imagen original. Funciona genial. ¡Gracias!
Deja
En mi caso, soluciones como esta no funcionaron, ¡esta sí!
Gooey
55
no olvide agregar 'compilar com.android.support:percent:23.3.0' en sus dependencias
Milad Faridnia
Parece que este enfoque tiene problemas con WrappedViewPager, que calcula la altura en función de su contenido secundario. Fuente para WrappedViewPager similar a gist.github.com/egslava/589b82a6add9c816a007
sha
1
El módulo de porcentaje de soporte ha quedado en desuso desde la biblioteca de soporte de Android 26.0.0. Fuente: developer.android.com/topic/libraries/support-library/…
MHogge
97

Tal vez esto responderá tu pregunta:

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

Puede ignorar el scaleTypeatributo para esta situación particular.

Vlad Stefanescu
fuente
12
Sí, eso es inútil
Fattie
44
No es necesariamente inútil. Esto funciona bien para mi uso, tengo un icono en una barra de título que quiero escalar para llenar la altura sin dejar de ser cuadrado.
Anubian Noob
3
También resolvió mi problema.
Ventas de Dielson el
¡La forma más fácil! Esto debe marcarse como la mejor respuesta.
H. Farid
30

Esto se puede hacer usando LayoutParams para establecer dinámicamente la altura de las Vistas una vez que conozca el ancho de las Vistas en tiempo de ejecución. Debe usar un subproceso ejecutable para obtener el ancho de Vistas en tiempo de ejecución o de lo contrario intentará establecer la Altura antes de conocer el ancho de la Vista porque el diseño aún no se ha dibujado.

Ejemplo de cómo resolví mi 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();
        }
    });

Los LayoutParams deben ser del tipo de la Vista principal en la que se encuentra su vista. Mi FrameLayout está dentro de un RelativeLayout en el archivo xml.

    mFrame.postInvalidate();

se llama para forzar que la vista se vuelva a dibujar mientras está en un hilo separado del hilo de la interfaz de usuario

drees
fuente
44
respuesta increíble, especialmente con Runnable, ¡gracias!
jesses.co.tt
1
Si bien esto funciona, no es lo ideal. Ejecutar en publicación significa que la vista se representa una vez antes de que cambie el diseño. Podría permitir un destello de contenido a la altura incorrecta, antes de dibujar correctamente. Es mejor resolverlo antes. El momento más temprano posible para resolver es durante una costumbre onMeasure, como se muestra en la respuesta de Regis . Una alternativa, pero solo para vistas representadas a través de un adaptador, por ejemplo GridView, dentro , es la respuesta de Matt .
ToolmakerSteve
1
bueno, funcionó para mí solo después de llamar requestLayout()después de configurar los parámetros. ¿Por qué sería eso?
Divins Mathew
mFrame.postInvalidate (); es lo que lo hizo, sin él estaba sacando la vista de posición.
Jacolack
17

No pude obtener la respuesta de David Chu para trabajar para un elemento RecyclerView y descubrí que necesitaba restringir el ImageView al padre. Establezca el ancho de ImageView en 0dpy restrinja su inicio y fin al padre. No estoy seguro de si establecer el ancho wrap_contento match_parentfunciona en algunos casos, pero creo que esta es una mejor manera de hacer que el hijo de un RestraintLayout llene a su padre.

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

Aquí lo que hice para tener un ImageButton que siempre tiene un ancho igual a su altura (y evitar márgenes vacíos estúpidos en una dirección ... lo que considero un error del SDK ...):

Definí una clase SquareImageButton que se extiende desde 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);

    }

}

Aquí está mi 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 de maravilla !

Regis_AG
fuente
Sí, esa es la mejor respuesta. (y el único que realmente coincide con la pregunta de los OP)
Twometer
6

En Android 26.0.0, PercentRelativeLayout ha quedado en desuso .

La mejor manera de resolverlo ahora es ConstraintLayoutasí:

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


Aquí hay un tutorial sobre cómo agregar ConstraintLayouta su proyecto.

Sebastian Schneider
fuente
6

Si su vista de imagen está dentro de un diseño de restricción, puede usar las siguientes restricciones para crear una vista de imagen cuadrada

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

No puedes hacerlo solo con el diseño, lo he intentado. Terminé escribiendo una clase muy simple para manejarlo, puedes verlo en github. SquareImage.java Es parte de un proyecto más grande pero nada que una pequeña copia y pegue no pueda arreglar (licenciado bajo Apache 2.0)

Esencialmente, solo necesita establecer la altura / ancho igual a la otra dimensión (dependiendo de la forma en que desee escalarlo)

Nota: Puede hacerlo cuadrado sin una clase personalizada utilizando el scaleTypeatributo, pero los límites de la vista se extienden más allá de la imagen visible, lo que hace que sea un problema si coloca otras vistas cerca de ella.

smith324
fuente
3

Para configurar su ImageView igual a la mitad de la pantalla, debe agregar lo siguiente a su XML para ImageView:

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

Para establecer la altura igual a este ancho, debe hacerlo en código. En el getViewmétodo de su GridViewadaptador, establezca la ImageViewaltura igual a su ancho medido:

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

Para las personas que pasan ahora, en 2017, la nueva mejor manera de lograr lo que quieres es usar ConstraintLayout de esta manera:

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

Y no olvide agregar restricciones a las cuatro direcciones según lo necesite su diseño.

Cree una interfaz de usuario receptiva con RestraintLayout

Además, por ahora, PercentRelativeLayout ha quedado en desuso (consulte la documentación de Android ).

Cristina De Rito
fuente
1

Así es como resolví ese problema:

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

preview - imageView con ancho configurado en "match_parent" y scaleType en "cropCenter"

picture: objeto de mapa de bits para establecer en imageView src.

Eso funciona bastante bien para mí.

udenfox
fuente
No ha explicado dónde debe colocarse este código. Tampoco ha explicado por qué lo hace en = vw*ph/pwlugar de lo más simple = vw. (Creo que lo hace para preservar la relación de aspecto de la imagen de la fuente, en lugar de la fuerza una vista previa cuadrado.)
ToolmakerSteve
0

No creo que pueda hacerlo en un archivo de diseño XML, y no creo que el android:scaleTypeatributo funcione como usted desea.
La única forma sería hacerlo mediante programación. Puede establecer el ancho en fill_parent y puede tomar el ancho de la pantalla como la altura del método Viewo puede usarlo View.getWidth().

novato
fuente
0

La función ImageView "scaleType" puede ayudarlo aquí.

Este código mantendrá la relación de aspecto y posicionará la imagen en la parte superior:

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

Aquí hay una gran publicación que muestra las posibilidades y apariencias del uso de scaleType.

ImageView scaleType samples

ac_banks
fuente
"scaleType" no ayuda aquí. El objetivo es que el ImageView en sí siempre sea cuadrado, no solo la imagen dentro de él. Con scaleType, ImageView puede ser más grande que la imagen.
ToolmakerSteve
0

me gustó esto

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