ImageView - la hauteur correspond-elle à la largeur?

166

J'ai une vue d'image. Je veux que sa largeur soit fill_parent. Je veux que sa hauteur soit quelle que soit la largeur finie par être. Par exemple:

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

Est-ce que quelque chose comme ça est possible dans un fichier de mise en page sans avoir à créer ma propre classe de vue?

Merci

user291701
la source
Avez-vous trouvé comment faire cela? Je suppose que vous voulez que le rapport hauteur / largeur reste le même. La plupart de ces réponses supposent que vous voulez que l'image soit carrée.
Adam
@Joe Blow c'est une TRÈS mauvaise façon de le faire
Agressor

Réponses:

170

Mise à jour: 14 septembre 2017

Selon un commentaire ci-dessous, la bibliothèque de support pour cent est obsolète à partir de la bibliothèque de support Android 26.0.0. Voici la nouvelle façon de procéder:

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

Voir ici

Obsolète:

Selon cet article de développeurs Android, tout ce que vous avez à faire maintenant est d'envelopper ce que vous voulez dans un PercentRelativeLayout ou un PercentFrameLayout, puis spécifiez ses ratios, comme ceci

<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
la source
8
Le lien de cette réponse a la solution la plus élégante fournie à Google. Dans mon cas, je voulais que l'image soit affichée au format 16: 9, quel que soit le rapport hauteur / largeur de l'image d'origine. Fonctionne très bien. Merci!
LETs le
Im mon cas, des solutions comme celle-ci n'ont pas fonctionné, celle-ci a fonctionné!
Gooey
5
n'oubliez pas d'ajouter 'compile com.android.support:percent:23.3.0' dans vos dépendances
Milad Faridnia
Cela ressemble à cette approche a des problèmes avec WrappedViewPager qui calcule la hauteur en fonction de son contenu enfants. Source pour WrappedViewPager similaire à gist.github.com/egslava/589b82a6add9c816a007
sha
1
Le module Percent Support est obsolète et est obsolète depuis la bibliothèque de support Android 26.0.0. Source: developer.android.com/topic/libraries/support-library/…
MHogge
97

Peut-être que cela répondra à votre question:

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

Vous pouvez ignorer l' scaleTypeattribut pour cette situation particulière.

Vlad Stefanescu
la source
12
Ouais, c'est inutile
Fattie
4
Ce n'est pas forcément inutile. Cela fonctionne bien pour mon utilisation, j'ai une icône sur une barre de titre que je veux mettre à l'échelle pour remplir la hauteur tout en restant carrée.
Anubian Noob
3
J'ai aussi résolu mon problème.
Dielson Sales
Le moyen le plus simple! Cela devrait être marqué comme la meilleure réponse.
H.Farid
30

Cela peut être fait en utilisant LayoutParams pour définir dynamiquement la hauteur des vues une fois que vous connaissez la largeur des vues au moment de l'exécution. Vous devez utiliser un thread exécutable pour obtenir la largeur des vues au moment de l'exécution, sinon vous allez essayer de définir la hauteur avant de connaître la largeur de la vue, car la mise en page n'a pas encore été dessinée.

Exemple de résolution de mon problème:

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

Les LayoutParams doivent être du type de la vue parent dans laquelle se trouve votre vue. Mon FrameLayout est à l'intérieur d'un RelativeLayout dans le fichier xml.

    mFrame.postInvalidate();

est appelée pour forcer la vue à se redessiner lorsqu'elle est sur un thread distinct du thread d'interface

drees
la source
4
réponse géniale, en particulier avec le Runnable, merci!
jesses.co.tt
1
Bien que cela fonctionne, ce n'est pas idéal. L'exécution sur la publication signifie que la vue est rendue une fois avant que la disposition ne change. Pourrait permettre un flash de contenu à la mauvaise hauteur, avant de dessiner correctement. Mieux vaut résoudre plus tôt. Le moment le plus tôt possible à résoudre est lors d'une coutume onMeasure, comme le montre la réponse de Régis . Une alternative, mais uniquement pour les vues rendues via un adaptateur, par exemple à l'intérieur GridView, est la réponse de Matt .
ToolmakerSteve
1
bien cela a fonctionné pour moi seulement après avoir appelé requestLayout()après avoir réglé les paramètres. pourquoi cela serait-il?
Divins Mathew
mFrame.postInvalidate (); C'est ce qui l'a fait, sans cela, je devenais la vue hors de position.
Jacolack
17

Je n'ai pas pu faire fonctionner la réponse de David Chu pour un élément RecyclerView et j'ai compris que je devais contraindre ImageView au parent. Définissez la largeur ImageView sur 0dpet contraignez son début et sa fin au parent. Je ne sais pas si la définition de la largeur sur wrap_contentou match_parentfonctionne dans certains cas, mais je pense que c'est un meilleur moyen de faire en sorte que l'enfant d'un ConstraintLayout remplisse son parent.

<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
la source
13

Voilà ce que j'ai fait pour avoir un ImageButton qui a toujours une largeur égale à sa hauteur (et éviter les marges vides stupides dans un sens ... ce que je considère comme un bug du SDK ...):

J'ai défini une classe SquareImageButton qui s'étend de 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);

    }

}

Voici mon 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"
           />

Fonctionne comme un charme!

Regis_AG
la source
Ouais, c'est la meilleure réponse. (et le seul qui correspond vraiment à la question des OP)
Twometer
7

Si votre vue d'image se trouve dans une mise en page de contraintes, vous pouvez utiliser les contraintes suivantes pour créer une vue d'image carrée

<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
la source
6

Dans Android 26.0.0, PercentRelativeLayout est obsolète .

La meilleure façon de le résoudre est maintenant avec ConstraintLayoutcomme ceci:

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


Voici un tutoriel sur la façon d'ajouter ConstraintLayoutà votre projet.

Sebastian Schneider
la source
5

Vous ne pouvez pas le faire avec la mise en page seule, j'ai essayé. J'ai fini par écrire une classe très simple pour la gérer, vous pouvez la vérifier sur github. SquareImage.java Il fait partie d'un projet plus vaste mais rien qu'un petit copier-coller ne peut corriger (sous licence Apache 2.0)

Il vous suffit essentiellement de définir la hauteur / largeur égale à l'autre dimension (en fonction de la manière dont vous souhaitez la mettre à l'échelle)

Remarque: vous pouvez le rendre carré sans classe personnalisée à l'aide de l' scaleTypeattribut, mais les limites de la vue s'étendent au-delà de l'image visible, ce qui pose un problème si vous placez d'autres vues à proximité.

Smith324
la source
3

Pour définir votre ImageView égale à la moitié de l'écran, vous devez ajouter ce qui suit à votre XML pour ImageView:

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

Pour définir ensuite la hauteur égale à cette largeur, vous devez le faire dans le code. Dans la getViewméthode de votre GridViewadaptateur, définissez la ImageViewhauteur égale à sa largeur mesurée:

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

Pour les gens de passage maintenant, en 2017, la nouvelle meilleure façon d'obtenir ce que vous voulez est d'utiliser ConstraintLayout comme ceci:

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

Et n'oubliez pas d'ajouter des contraintes aux quatre directions selon les besoins de votre mise en page.

Créer une interface utilisateur réactive avec ConstraintLayout

De plus, à présent, PercentRelativeLayout est obsolète (voir la documentation Android ).

Cristina De Rito
la source
1

Voici comment j'ai résolu ce problème:

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

aperçu - imageView avec une largeur définie sur "match_parent" et scaleType sur "cropCenter"

picture - Objet bitmap à définir dans imageView src.

Cela fonctionne plutôt bien pour moi.

udenfox
la source
Vous n'avez pas expliqué ce code doit être placé. Vous n'avez pas non plus expliqué pourquoi vous le faites = vw*ph/pwau lieu du plus simple = vw. (Je pense que vous faites cela pour préserver le rapport hauteur / largeur de l'image source, plutôt que de forcer un aperçu carré.)
ToolmakerSteve
0

Je ne pense pas que vous puissiez le faire dans un fichier de mise en page XML, et je ne pense pas que l' android:scaleTypeattribut fonctionnera comme vous le souhaitez.
Le seul moyen serait de le faire par programme. Vous pouvez définir la largeur sur fill_parent et prendre la largeur de l'écran comme hauteur de la méthode Viewou utiliser la View.getWidth()méthode.

Noob
la source
0

La fonction ImageView "scaleType" peut vous aider ici.

Ce code conservera le rapport hauteur / largeur et positionnera l'image en haut:

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

Voici un excellent article montrant les possibilités et les apparences de l'utilisation de scaleType.

Exemples d'ImageView scaleType

ac_banks
la source
"scaleType" n'aide pas ici. Le but est que ImageView soit toujours carrée, pas seulement l'image à l'intérieur. Avec scaleType, ImageView peut être plus grande que l'image.
ToolmakerSteve
0

j'ai aimé ça -

layout.setMinimumHeight(layout.getWidth());
HarshitG
la source