Ajustar imagem ao ImageView, manter a proporção e redimensionar o ImageView para as dimensões da imagem?

164

Como ajustar uma imagem de tamanho aleatório a uma ImageView?
Quando:

  • Inicialmente as ImageViewdimensões são 250dp * 250dp
  • A dimensão maior da imagem deve ser aumentada / reduzida para 250dp
  • A imagem deve manter sua proporção
  • As ImageViewdimensões devem corresponder às dimensões da imagem em escala após o dimensionamento

Por exemplo, para uma imagem de 100 * 150, a imagem e a ImageViewdevem ser 166 * 250.
Por exemplo, para uma imagem de 150 * 100, a imagem e a ImageViewdevem ser 250 * 166.

Se eu definir os limites como

<ImageView
    android:id="@+id/picture"
    android:layout_width="250dp"
    android:layout_height="250dp"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="20dp"
    android:adjustViewBounds="true" />

as imagens se encaixam corretamente no ImageView, mas ImageViewsempre são 250dp * 250dp.

jul
fonte
Você quer mudar o tamanho do tamanho da ImageViewimagem? Por exemplo, a imagem de 100dp x 150dp seria dimensionada ImageViewpara as mesmas medidas? Ou você quer dizer como dimensionar a imagem até os ImageViewlimites. Por exemplo, a imagem de 1000dp x 875dp seria dimensionada para 250dp x 250dp. Você precisa manter a proporção?
Jarno Argillander
Quero que o ImageView tenha as dimensões da imagem, e a imagem tenha sua maior dimensão igual a 250dp e mantenha sua proporção. Por exemplo, para uma imagem de 100 * 150, quero que a imagem e o ImageView sejam 166 * 250. Vou atualizar minha pergunta.
julho
Deseja fazer redimensionamento / ajuste apenas ao exibir uma atividade (faça uma vez) ou ao executar algo na atividade, como selecionar uma imagem da galeria / web (faça várias vezes, mas não carregue) ou ambas?
Jarno Argillander
Veja a minha resposta modificada, o que deve fazer exatamente como você desejava que :)
Jarno Argillander

Respostas:

136

(A resposta foi fortemente modificada após esclarecimentos à pergunta original)

Após esclarecimentos:
Isso não pode ser feito apenas em xml . Não é possível dimensionar a imagem e a imagem ImageViewpara que a única dimensão da imagem seja sempre de 250 pd e ImageViewtenha as mesmas dimensões da imagem.

Este escalas de código Drawable de um ImageViewpara ficar em um quadrado como 250DP x 250DP com uma dimensão exatamente 250DP e mantendo a relação de aspecto. Em seguida, o ImageViewé redimensionado para corresponder às dimensões da imagem em escala. O código é usado em uma atividade. Testei-o através do manipulador de cliques de botão.

Aproveitar. :)

private void scaleImage(ImageView view) throws NoSuchElementException  {
    // Get bitmap from the the ImageView.
    Bitmap bitmap = null;

    try {
        Drawable drawing = view.getDrawable();
        bitmap = ((BitmapDrawable) drawing).getBitmap();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("No drawable on given view");
    } catch (ClassCastException e) {
        // Check bitmap is Ion drawable
        bitmap = Ion.with(view).getBitmap();
    }

    // Get current dimensions AND the desired bounding box
    int width = 0;

    try {
        width = bitmap.getWidth();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("Can't find bitmap on given view/drawable");
    }

    int height = bitmap.getHeight();
    int bounding = dpToPx(250);
    Log.i("Test", "original width = " + Integer.toString(width));
    Log.i("Test", "original height = " + Integer.toString(height));
    Log.i("Test", "bounding = " + Integer.toString(bounding));

    // Determine how much to scale: the dimension requiring less scaling is
    // closer to the its side. This way the image always stays inside your
    // bounding box AND either x/y axis touches it.  
    float xScale = ((float) bounding) / width;
    float yScale = ((float) bounding) / height;
    float scale = (xScale <= yScale) ? xScale : yScale;
    Log.i("Test", "xScale = " + Float.toString(xScale));
    Log.i("Test", "yScale = " + Float.toString(yScale));
    Log.i("Test", "scale = " + Float.toString(scale));

    // Create a matrix for the scaling and add the scaling data
    Matrix matrix = new Matrix();
    matrix.postScale(scale, scale);

    // Create a new bitmap and convert it to a format understood by the ImageView 
    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth(); // re-use
    height = scaledBitmap.getHeight(); // re-use
    BitmapDrawable result = new BitmapDrawable(scaledBitmap);
    Log.i("Test", "scaled width = " + Integer.toString(width));
    Log.i("Test", "scaled height = " + Integer.toString(height));

    // Apply the scaled bitmap
    view.setImageDrawable(result);

    // Now change ImageView's dimensions to match the scaled image
    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);

    Log.i("Test", "done");
}

private int dpToPx(int dp) {
    float density = getApplicationContext().getResources().getDisplayMetrics().density;
    return Math.round((float)dp * density);
}

O código xml para o ImageView:

<ImageView a:id="@+id/image_box"
    a:background="#ff0000"
    a:src="@drawable/star"
    a:layout_width="wrap_content"
    a:layout_height="wrap_content"
    a:layout_marginTop="20dp"
    a:layout_gravity="center_horizontal"/>


Obrigado a esta discussão pelo código de dimensionamento:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


ATUALIZAÇÃO 7 de novembro de 2012:
verificação de ponteiro nulo adicionada, conforme sugerido nos comentários

Jarno Argillander
fonte
1
O ImageView sempre será 250 * 250.
julho
2
Está bem. Isso não pode ser feito apenas em xml. Código Java é necessário. Com o xml, você pode dimensionar a imagem ou o ImageView, não os dois.
Jarno Argillander
92
não sabia que você poderia substituir o android: por um:
StackOverflowed
2
Ion é uma estrutura para redes assíncronas e carregamento da imagem: github.com/koush/ion
Thomas
1
Java é uma linguagem extremamente feia, porque exige escrever muito código para tarefas simples.
Dmitry
245

Pode não ser a resposta para esta pergunta específica, mas se alguém, como eu, estiver procurando uma resposta para ajustar a imagem no ImageView com tamanho limitado (por exemplo maxWidth), preservando a Proporção da imagem e depois se livrar do espaço excessivo ocupado pelo ImageView, a solução mais simples é usar as seguintes propriedades em XML:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"
Nome em Exibição
fonte
13
Isso funciona se você não quiser que a imagem seja ampliada se ela for muito pequena.
Janusz
como escaloná-lo se for muito pequeno e também manter a proporção?
Kaustubh Bhagwat
se alguém precisar, "fitCenter" é outro atributo para scaleType e não aumentará a escala da imagem, mas para qualquer imagem grande, caberá no tamanho máximo da imagem dentro da caixa de exibição, mantendo a proporção
yogesh prajapati
para aumentar a escala de imagens pequenas, use scaleType = "centerCrop".
Eaweb
mais uma coisa para eu trabalhar com esta solução é usar "android: src" e não o "android: background" para refazer minha imagem.
Codingpan
45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>
diesel
fonte
23

O código Abaixo cria o bitmap perfeitamente com o mesmo tamanho da visualização de imagem. Obtenha a altura e a largura da imagem de bitmap e calcule a nova altura e largura com a ajuda dos parâmetros do imageview. Isso fornece a imagem necessária com a melhor proporção.

int currentBitmapWidth = bitMap.getWidth();
int currentBitmapHeight = bitMap.getHeight();

int ivWidth = imageView.getWidth();
int ivHeight = imageView.getHeight();
int newWidth = ivWidth;

newHeight = (int) Math.floor((double) currentBitmapHeight *( (double) new_width / (double) currentBitmapWidth));

Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap, newWidth, newHeight, true);

imageView.setImageBitmap(newbitMap)

desfrutar.

Naresh Sharma
fonte
3
Isso apenas reduzirá a altura original pelo mesmo fator pelo qual a largura foi reduzida. Isso não garante que newHeight <ivHeight. Idealmente, você deve verificar qual proporção é maior (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) e, com base nisso, tomar outras decisões.
Sumit Trehan
1
Isso realmente funciona perfeitamente, embora você não precise de ivHeight ou newWidth, basta colocar ivWidth no cálculo.
Stuart
14

tente adicionar android:scaleType="fitXY"ao seu ImageView.

DeeFour
fonte
5
Isso modificará a proporção se a imagem original não estiver ao quadrado.
julho
1
fitXYquase sempre altera a proporção da imagem. O OP menciona claramente que a proporção deve ser mantida.
IcyFlame
7

Depois de procurar um dia, acho que essa é a solução mais fácil:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);
MikeyB
fonte
2
Obrigado pela sua boa resposta, mas acho que é melhor adicionar adjustViewBoundsao XML
7

A melhor solução que funciona na maioria dos casos é

Aqui está um exemplo:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>
Nikita Vishwakarma
fonte
1
Não confie na API obsoleto (fill_parent)
fdermishin
como isso responde à pergunta do OP. Isso não vai manter a relação aspet
Alex
6

tudo isso pode ser feito usando XML ... os outros métodos parecem bastante complicados. De qualquer forma, basta definir a altura para o que quiser no dp e depois definir a largura para agrupar o conteúdo ou vice-versa. Use scaleType fitCenter para ajustar o tamanho da imagem.

<ImageView
    android:layout_height="200dp"
    android:layout_width="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true"
    android:src="@mipmap/ic_launcher"
    android:layout_below="@+id/title"
    android:layout_margin="5dip"
    android:id="@+id/imageView1">
Thunderstick
fonte
4

Use este código:

<ImageView android:id="@+id/avatar"
           android:layout_width="fill_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY" />
Abhay Anand
fonte
4

Editado Jarno Argillanders resposta:

Como encaixar Imagem com a sua largura e altura:

1) Inicializar ImageView e conjunto Image:

iv = (ImageView) findViewById(R.id.iv_image);
iv.setImageBitmap(image);

2) Agora redimensione:

scaleImage(iv);

scaleImageMétodo editado : ( você pode substituir valores limitados EXPECTIVOS )

private void scaleImage(ImageView view) {
    Drawable drawing = view.getDrawable();
    if (drawing == null) {
        return;
    }
    Bitmap bitmap = ((BitmapDrawable) drawing).getBitmap();

    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int xBounding = ((View) view.getParent()).getWidth();//EXPECTED WIDTH
    int yBounding = ((View) view.getParent()).getHeight();//EXPECTED HEIGHT

    float xScale = ((float) xBounding) / width;
    float yScale = ((float) yBounding) / height;

    Matrix matrix = new Matrix();
    matrix.postScale(xScale, yScale);

    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth();
    height = scaledBitmap.getHeight();
    BitmapDrawable result = new BitmapDrawable(context.getResources(), scaledBitmap);

    view.setImageDrawable(result);

    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);
}

E .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />
Volodymyr Kulyk
fonte
Eu acho que este elenco: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams (); deve seguir o outro caminho, já que MarginLayoutParams herda de ViewGroup.LayoutParams.
Jay Jacobs
3

Isso foi feito no meu caso.

             <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:scaleType="centerCrop"
                android:adjustViewBounds="true"
                />
Ronny Kibet
fonte
2

se não estiver funcionando, substitua android: background por android: src

android: src fará o maior truque

    <ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:src="@drawable/bg_hc" />

está funcionando bem como um encanto

insira a descrição da imagem aqui

Harvinder Singh
fonte
1

Eu precisava ter um ImageView e um Bitmap, para que o Bitmap seja dimensionado para o tamanho do ImageView, e o tamanho do ImageView seja o mesmo do Bitmap :).

Eu estava olhando este post para saber como fazê-lo e, finalmente, fiz o que queria, mas não da maneira descrita aqui.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/acpt_frag_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/imageBackground"
android:orientation="vertical">

<ImageView
    android:id="@+id/acpt_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    android:layout_margin="@dimen/document_editor_image_margin"
    android:background="@color/imageBackground"
    android:elevation="@dimen/document_image_elevation" />

e depois no método onCreateView

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_scanner_acpt, null);

    progress = view.findViewById(R.id.progress);

    imageView = view.findViewById(R.id.acpt_image);
    imageView.setImageBitmap( bitmap );

    imageView.getViewTreeObserver().addOnGlobalLayoutListener(()->
        layoutImageView()
    );

    return view;
}

e, em seguida, o código layoutImageView ()

private void layoutImageView(){

    float[] matrixv = new float[ 9 ];

    imageView.getImageMatrix().getValues(matrixv);

    int w = (int) ( matrixv[Matrix.MSCALE_X] * bitmap.getWidth() );
    int h = (int) ( matrixv[Matrix.MSCALE_Y] * bitmap.getHeight() );

    imageView.setMaxHeight(h);
    imageView.setMaxWidth(w);

}

E o resultado é que a imagem se encaixa perfeitamente, mantendo a taxa de proporção e não possui mais pixels restantes do ImageView quando o Bitmap está dentro.

Resultado

É importante que o ImageView tenha wrap_content e ajusteViewBounds como true; setMaxWidth e setMaxHeight funcionarão; isso está escrito no código-fonte do ImageView,

/*An optional argument to supply a maximum height for this view. Only valid if
 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
 * layout params to WRAP_CONTENT. */
alekshandru
fonte
0

Eu precisava fazer isso em um layout de restrição com o Picasso, então juntei algumas das respostas acima e criei esta solução (eu já conheço a proporção da imagem que estou carregando, o que ajuda):

Chamado no meu código de atividade em algum lugar após setContentView (...)

protected void setBoxshotBackgroundImage() {
    ImageView backgroundImageView = (ImageView) findViewById(R.id.background_image_view);

    if(backgroundImageView != null) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = (int) Math.round(width * ImageLoader.BOXART_HEIGHT_ASPECT_RATIO);

        // we adjust the height of this element, as the width is already pinned to the parent in xml
        backgroundImageView.getLayoutParams().height = height;

        // implement your Picasso loading code here
    } else {
        // fallback if no element in layout...
    }
}

No meu XML

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="0dp">

    <ImageView
        android:id="@+id/background_image_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="fitStart"
        app:srcCompat="@color/background"
        android:adjustViewBounds="true"
        tools:layout_editor_absoluteY="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginBottom="0dp"
        android:layout_marginRight="0dp"
        android:layout_marginLeft="0dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!-- other elements of this layout here... -->

</android.support.constraint.ConstraintLayout>

Observe a falta de um atributo constraintBottom_toBottomOf. ImageLoader é minha própria classe estática para carregamento de imagens, métodos e constantes utilitários .

the_dude_abides
fonte
0

Estou usando uma solução muito simples. Aqui meu código:

imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.getLayoutParams().height = imageView.getLayoutParams().width;
imageView.setMinimumHeight(imageView.getLayoutParams().width);

Minhas fotos são adicionadas dinamicamente em um gridview. Quando você faz essas configurações na visualização de imagem, a imagem pode ser exibida automaticamente na proporção de 1: 1.

Bilal Demir
fonte
0

Use Matemática simples para redimensionar a imagem. você pode redimensionar ImageViewou redimensionar a imagem desenhável do que ativada ImageView. encontre a largura e a altura do seu bitmap em que deseja definir ImageViewe chame o método desejado. suponha que sua largura 500 seja maior que a altura do que o método de chamada

//250 is the width you want after resize bitmap
Bitmat bmp = BitmapScaler.scaleToFitWidth(bitmap, 250) ;
ImageView image = (ImageView) findViewById(R.id.picture);
image.setImageBitmap(bmp);

Você usa essa classe para redimensionar o bitmap.

public class BitmapScaler{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
 public static Bitmap scaleToFitWidth(Bitmap b, int width)
  {
    float factor = width / (float) b.getWidth();
    return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
  }


  // Scale and maintain aspect ratio given a desired height
  // BitmapScaler.scaleToFitHeight(bitmap, 100);
  public static Bitmap scaleToFitHeight(Bitmap b, int height)
  {
    float factor = height / (float) b.getHeight();
    return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
   }
 }

código xml é

<ImageView
android:id="@+id/picture"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:adjustViewBounds="true"
android:scaleType="fitcenter" />
Ritesh Namdev
fonte
0

Resposta rápida:

<ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="center"
        android:src="@drawable/yourImage"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
myworldbox
fonte