Sesuaikan gambar dengan ImageView, pertahankan rasio aspek lalu ubah ukuran ImageView ke dimensi gambar?

164

Bagaimana cara mencocokkan gambar dengan ukuran acak ImageView?
Kapan:

  • ImageViewDimensi awalnya adalah 250dp * 250dp
  • Dimensi gambar yang lebih besar harus ditingkatkan / turun ke 250dp
  • Gambar harus menjaga rasio aspeknya
  • The ImageViewdimensi harus sesuai dimensi gambar berskala setelah skala

Misalnya untuk gambar 100 * 150, gambar dan ImageViewharus 166 * 250.
Misalnya untuk gambar 150 * 100, gambar dan ImageViewharus 250 * 166.

Jika saya menetapkan batas sebagai

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

gambar pas di ImageView, tetapi ImageViewselalu 250dp * 250dp.

jul
sumber
Eh, maksud Anda mengubah ukuran menjadi ukuran ImageViewgambar? Misalnya gambar 100dp x 150dp akan skala ImageViewke langkah yang sama? Atau maksud Anda bagaimana skala gambar ke ImageViewbatas. Misalnya gambar 1000dp x 875dp akan diskalakan menjadi 250dp x 250dp. Apakah Anda perlu mempertahankan rasio aspek?
Jarno Argillander
Saya ingin ImageView memiliki dimensi gambar, dan gambar memiliki dimensi terbesarnya sama dengan 250dp dan menjaga rasio aspeknya. Misalnya untuk gambar 100 * 150, saya ingin gambar dan ImageView menjadi 166 * 250. Saya akan memperbarui pertanyaan saya.
Juli
Apakah Anda ingin melakukan penskalaan / penyesuaian hanya saat menampilkan suatu aktivitas (lakukan sekali) atau ketika melakukan sesuatu pada aktivitas tersebut seperti memilih gambar dari galeri / web (lakukan berkali-kali tetapi tidak saat memuat) atau keduanya?
Jarno Argillander
Lihat jawaban saya yang dimodifikasi, yang seharusnya melakukan persis seperti yang Anda inginkan :)
Jarno Argillander

Jawaban:

136

(Jawabannya sangat dimodifikasi setelah klarifikasi ke pertanyaan awal)

Setelah klarifikasi:
Ini tidak dapat dilakukan dalam xml saja . Tidak mungkin untuk skala gambar dan ImageViewsehingga satu dimensi gambar akan selalu 250dp dan ImageViewakan memiliki dimensi yang sama dengan gambar.

Kode ini menskala Drawablesuatu ImageViewuntuk tetap dalam kotak seperti 250dp x 250dp dengan satu dimensi persis 250dp dan menjaga rasio aspek. Kemudian ImageViewdiubah ukurannya agar sesuai dengan dimensi gambar yang diskalakan. Kode tersebut digunakan dalam suatu kegiatan. Saya mengujinya melalui tombol klik penangan.

Nikmati. :)

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

Kode xml untuk 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"/>


Berkat diskusi ini untuk kode penskalaan:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


UPDATE 7th, November 2012:
Menambahkan null pointer check seperti yang disarankan dalam komentar

Jarno Argillander
sumber
1
ImageView akan selalu berukuran 250 * 250.
Juli
2
Baik. Itu tidak bisa dilakukan dalam xml saja. Diperlukan kode Java. Dengan xml Anda dapat mengatur skala gambar atau ImageView, bukan keduanya.
Jarno Argillander
92
tidak sadar Anda bisa mengganti android: dengan:
StackOverflowed
2
Ion adalah kerangka kerja untuk jaringan asinkron dan pemuatan gambar: github.com/koush/ion
Thomas
1
Java adalah bahasa yang sangat jelek karena harus menulis begitu banyak kode untuk tugas-tugas sederhana seperti itu.
Dmitry
245

Mungkin bukan jawaban untuk pertanyaan khusus ini, tetapi jika seseorang, seperti saya, mencari jawaban bagaimana mencocokkan gambar di ImageView dengan ukuran terikat (misalnya, maxWidth) sambil mempertahankan Aspect Ratio dan kemudian menyingkirkan ruang berlebihan yang ditempati oleh ImageView, maka solusi paling sederhana adalah dengan menggunakan properti berikut di XML:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"
Nama tampilan
sumber
13
Ini berfungsi jika Anda tidak ingin gambar diperbesar jika terlalu kecil.
Janusz
bagaimana saya meningkatkannya jika terlalu kecil dan juga mempertahankan aspek rasio?
Kaustubh Bhagwat
jika seseorang membutuhkan, "fitCenter" adalah atribut lain untuk scaleType, dan itu tidak akan memperbesar gambar, tetapi untuk gambar besar apa pun, itu akan sesuai dengan ukuran maksimum gambar di dalam kotak tampilan mempertahankan rasio aspek
yogesh prajapati
untuk memperbesar gambar kecil gunakan scaleType = "centerCrop" sebagai gantinya.
Eaweb
satu hal lagi bagi saya untuk bekerja dengan solusi ini adalah menggunakan "android: src" bukan "android: background" untuk memperbaiki gambar saya.
Codingpan
45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>
diesel
sumber
23

Kode di bawah ini membuat bitmap sempurna dengan ukuran imageview yang sama. Dapatkan tinggi dan lebar gambar bitmap lalu hitung tinggi dan lebar baru dengan bantuan parameter imageview. Itu memberi Anda gambar yang diperlukan dengan rasio aspek terbaik.

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)

Nikmati.

Naresh Sharma
sumber
3
Ini hanya akan mengurangi ketinggian asli dengan faktor yang sama dengan mana lebar dikurangi. Ini tidak akan menjamin ketinggian baru <iv Tinggi. Idealnya Anda harus memeriksa rasio mana yang lebih besar (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) dan kemudian atas dasar ini mengambil keputusan lebih lanjut.
Sumit Trehan
1
Ini sebenarnya berfungsi dengan baik, meskipun Anda tidak perlu ivHeight atau newWidth, cukup masukkan ivWidth ke dalam perhitungan.
Stuart
14

coba tambahkan android:scaleType="fitXY"ke ImageView.

DeeFour
sumber
5
Ini akan mengubah rasio aspek jika gambar asli tidak dikuadratkan.
juli
1
fitXYakan hampir selalu mengubah aspek rasio gambar. OP dengan jelas menyebutkan bahwa aspek rasio HARUS dipertahankan.
IcyFlame
7

Setelah mencari sehari, saya pikir ini adalah solusi termudah:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);
MikeyB
sumber
2
Terima kasih atas jawaban Anda yang baik, Tapi saya pikir lebih baik menambahkannya adjustViewBoundske XML
7

Solusi terbaik yang berfungsi dalam banyak kasus adalah

Berikut ini sebuah contoh:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>
Nikita Vishwakarma
sumber
1
Jangan mengandalkan API usang (fill_parent)
fdermishin
bagaimana ini menjawab pertanyaan OP. Ini tidak akan mempertahankan rasio aspet
Alex
6

ini semua bisa dilakukan dengan menggunakan XML ... metode lain tampaknya cukup rumit. Pokoknya, Anda tinggal mengatur ketinggian ke apa yang Anda inginkan dalam dp, lalu atur lebar untuk membungkus konten atau sebaliknya. Gunakan scaleType fitCenter untuk menyesuaikan ukuran gambar.

<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">
Petir
sumber
4

Gunakan kode ini:

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

Diedit Jarno Argillanders menjawab:

Cara menyesuaikan Gambar dengan Lebar dan Tinggi Anda:

1) Inisialisasi ImageView dan atur Gambar:

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

2) Sekarang mengubah ukuran:

scaleImage(iv);

scaleImageMetode yang diedit : ( Anda dapat mengganti nilai pembatas yang DIHARAPKAN )

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

Dan .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />
Volodymyr Kulyk
sumber
Saya pikir ini pemain: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams (); harus sebaliknya, karena MarginLayoutParams mewarisi dari ViewGroup.LayoutParams.
Jay Jacobs
3

Ini berhasil untuk kasus saya.

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

jika itu tidak berhasil untuk Anda maka ganti android: background dengan android: src

android: src akan memainkan trik utama

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

itu bekerja dengan baik seperti pesona

masukkan deskripsi gambar di sini

Harvinder Singh
sumber
1

Saya perlu memiliki ImageView dan Bitmap, sehingga Bitmap diskalakan ke ukuran ImageView, dan ukuran ImageView sama dengan Bitmap yang diskalakan :).

Saya sedang mencari-cari cara untuk melakukannya, dan akhirnya melakukan apa yang saya inginkan, bukan cara yang dijelaskan di sini.

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

dan kemudian dalam metode 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;
}

dan kemudian kode 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);

}

Dan hasilnya adalah gambar yang pas di dalam, menjaga rasio aspek, dan tidak memiliki piksel sisa tambahan dari ImageView ketika Bitmap ada di dalam.

Hasil

ImageView penting untuk memiliki wrap_content dan sesuaikanViewBounds menjadi true, lalu setMaxWidth dan setMaxHeight akan berfungsi, ini ditulis dalam kode sumber 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
sumber
0

Saya perlu menyelesaikan ini dalam tata letak kendala dengan Picasso, jadi saya mengumpulkan beberapa jawaban di atas dan menghasilkan solusi ini (saya sudah tahu rasio aspek gambar yang saya muat, sehingga membantu):

Disebut dalam kode aktivitas saya di suatu tempat setelah 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...
    }
}

Dalam XML saya

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

Perhatikan kurangnya atribut constraintBottom_toBottomOf. ImageLoader adalah kelas statis saya sendiri untuk metode utilisasi pemuatan gambar dan konstanta.

the_dude_abides
sumber
0

Saya menggunakan solusi yang sangat sederhana. Ini kode saya:

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

Foto-foto saya ditambahkan secara dinamis dalam tampilan kotak. Ketika Anda membuat pengaturan ini ke tampilan gambar, gambar dapat secara otomatis ditampilkan dalam rasio 1: 1.

Bilal Demir
sumber
0

Gunakan matematika sederhana untuk mengubah ukuran gambar. baik Anda dapat mengubah ukuran ImageViewatau Anda dapat mengubah ukuran gambar yang dapat ditarik daripada diatur ImageView. temukan lebar dan tinggi bitmap Anda yang ingin Anda setel ImageViewdan panggil metode yang diinginkan. misalkan lebar 500 Anda lebih besar dari tinggi daripada metode panggilan

//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);

Anda menggunakan kelas ini untuk mengubah ukuran 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);
   }
 }

kode xml adalah

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

Jawaban cepat:

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