Görüntüyü ImageView'e sığdırın, en boy oranını koruyun ve ImageView'ı görüntü boyutlarına göre yeniden boyutlandırın mı?


164

Rastgele boyuttaki bir görüntüye nasıl sığdırılır ImageView?
Ne zaman:

  • Başlangıçta ImageViewboyutlar 250dp * 250dp'dir
  • Görüntünün daha büyük boyutu 250 dp'ye kadar yukarı / aşağı ölçeklendirilmelidir
  • Görüntü en boy oranını korumalıdır
  • ImageViewBoyutlar ölçekleme sonra ölçekli resmin boyutlarıyla

Örneğin, 100 * 150'lik bir resim için resim ve ImageViewolması gereken 166 * 250 olmalıdır.
Örneğin 150 * 100 görüntü için görüntü ve ImageView250 * 166 olmalıdır.

Sınırları şu şekilde ayarlarsam

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

görüntüler düzgün sığar ImageView, ancak ImageViewher zaman 250dp * 250dp'dir.


Uh, boyutunu boyutunu ImageViewgörüntü boyutuyla mı değiştirmek istiyorsun ? Örneğin 100dp x 150dp görüntüsü ImageViewaynı ölçülere göre ölçeklendirilir mi? Yoksa görüntüyü ImageViewsınırlara nasıl ölçeklendireceğinizi mi kastediyorsunuz ? Örneğin 1000dp x 875dp görüntüsü 250dp x 250dp olarak ölçeklendirilir. En boy oranını korumanız mı gerekiyor?
Jarno Argillander

ImageView görüntü boyutlarına sahip ve görüntü en büyük boyutu 250dp eşit ve en boy oranını korumak istiyorum. 100 * 150 görüntü için, görüntü ve ImageView 166 * 250 olmasını istiyorum. Sorumu güncelleyeceğim.
Temmuz

Ölçekleme / ayarlama işlemini yalnızca bir etkinlik görüntülerken (bir kez yapın) veya etkinlik üzerinde galeri / web'den (birçok kez yüklerken değil) resim veya her ikisi gibi bir şey yaparken mi yapmak istiyorsunuz?
Jarno Argillander

Tam olarak istediğiniz gibi yapması gereken değiştirilmiş cevabımı görün :)
Jarno Argillander

Yanıtlar:


137

(Orijinal soruya açıklandıktan sonra cevap büyük ölçüde değiştirildi)

Açıklamalardan sonra:
Bu yalnızca xml ile yapılamaz . Hem görüntüyü hem de görüntüyü ölçeklemek mümkün değildir, ImageViewböylece görüntünün bir boyutu her zaman 250dp olur ve ImageViewgörüntüyle aynı boyutlara sahip olur.

Bu kod ölçekler Drawable bir bir ImageViewtek boyutta tam 250dp ve boy oranını koruyarak ile 250dp x 250dp gibi bir meydanda kalmak. Ardından ImageViewölçeklendirilen görüntünün boyutlarına uyacak şekilde yeniden boyutlandırılır. Kod bir aktivitede kullanılır. Düğme tıklama işleyicisi ile test ettim.

Zevk almak. :)

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

Şunun için xml kodu 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"/>


Ölçekleme kodu için bu tartışma sayesinde:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


GÜNCELLE 7 Kasım 2012:
Yorumlarda önerildiği gibi boş işaretçi kontrolü eklendi


1
ImageView her zaman 250 * 250 olacaktır.
Temmuz

2
Tamam. Bu yalnızca xml ile yapılamaz. Java kodu gerekli. Xml ile görüntüyü ölçekleyebilir veya ImageViewher ikisini birden değil.
Jarno Argillander

94
android'in yerine geçebileceğini fark etmedim:
StackOverflowed

2
Ion, eşzamansız ağ oluşturma ve görüntü yükleme için bir çerçevedir: github.com/koush/ion
Thomas

1
Java son derece çirkin bir dildir, çünkü bu tür basit görevler için çok fazla kod yazmayı gerektirir.
Dmitry

245

Bu özel sorunun cevabı olmayabilir, ancak biri benim gibi, maxWidthGörüntü Oranı korunurken ImageView'de görüntüyü sınırlı boyutlu (örneğin ) nasıl sığdıracağına ve ardından ImageView tarafından kullanılan aşırı alandan nasıl kurtulacağına cevap arıyorsa, en basit çözüm XML'de aşağıdaki özellikleri kullanmaktır:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"

13
Bu, görüntünün çok küçük olması durumunda büyütülmesini istemiyorsanız çalışır.
Janusz

çok küçükse nasıl büyütebilirim ve en boy oranını nasıl koruyabilirim?
Kaustubh Bhagwat

Birisi ihtiyaçları varsa, "fitCenter" scaleType için başka özellik olduğunu ve görüntüyü büyütmek değil, ancak herhangi bir büyük görüntü için, bu boy oranını koruyarak görünümü kutusunun içindeki görüntünün maksimum boyutunu uyacak
yogesh prajapati

küçük resimleri büyütmek için bunun yerine scaleType = "centerCrop" kullanın.
Eaweb

benim bu çözüm ile çalışmak için bir şey daha benim görüntü ref için "android: src" değil "android: arka plan" kullanmaktır.
Codingpan

45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>

23

Aşağıdaki kod, bitmap'i aynı görüntü boyutuyla mükemmel hale getirir. Bitmap görüntü yüksekliğini ve genişliğini alın ve sonra yeni görüntüleme yüksekliğini ve genişliğini imageview parametrelerini kullanarak hesaplayın. Bu, size en iyi en boy oranına sahip gerekli görüntüyü sağlar.

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)

zevk almak.


3
Bu sadece orijinal yüksekliği genişliğin azaltıldığı faktörle azaltacaktır. Bu newHeight <ivHeight değerini garanti etmez. İdeal olarak hangi oranın daha büyük olduğunu kontrol etmelisiniz (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) ve ardından buna dayanarak daha fazla karar almalısınız.
Sumit Trehan

1
Bu gerçekten mükemmel çalışır, ancak ivHeight veya newWidth'e ihtiyacınız olmasa da, ivWidth değerini hesaplamaya koymanız yeterlidir.
Stuart

14

eklemeyi deneyin android:scaleType="fitXY"adresinden Müşteri ImageView.


5
Bu, orijinal görüntü kareye alınmazsa en boy oranını değiştirir.
Temmuz

1
fitXYneredeyse her zaman görüntünün en boy oranını değiştirir. OP, en-boy oranının korunması ZORUNLU olduğunu açıkça belirtir.
IcyFlame

7

Bir gün aradıktan sonra, bunun en kolay çözüm olduğunu düşünüyorum:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);

2
Güzel cevabınız için teşekkürler, ancak adjustViewBoundsXML'ye eklemenin daha iyi olduğunu düşünüyorum

7

Çoğu durumda çalışan en iyi çözüm

İşte bir örnek:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>

1
Kullanımdan kaldırılmış API'ya güvenmeyin (
doldurma_eklemi

Bu OP'nin sorusunu nasıl cevaplıyor? Bu aspet oranını koruyamayacak
Alex

6

tüm bunlar XML kullanılarak yapılabilir ... diğer yöntemler oldukça karmaşık görünüyor. Her neyse, yüksekliği dp'de istediğiniz değere ayarlayın, ardından içeriği sarmak için genişliği ayarlayın veya tam tersi. Görüntünün boyutunu ayarlamak için scaleType fitCenter'ı kullanın.

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

4

Bu kodu kullanın:

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

4

Düzenlenmiş Jarno Argillanders cevap:

Görüntüyü Genişlik ve Yüksekliğinize nasıl sığdırırsınız:

1) ImageView'i başlatın ve ayarlayın Image:

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

2) Şimdi yeniden boyutlandırın:

scaleImage(iv);

Düzenlenen scaleImageyöntem: ( EXPECTED sınırlama değerlerini değiştirebilirsiniz )

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

Ve .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />

Bence bu oyuncu: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams (); MarginLayoutParams öğesinin ViewGroup.LayoutParams öğesinden devralınması nedeniyle diğer yöne gitmelidir.
Jay Jacobs

3

Bu benim durumum için yaptı.

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

2

eğer sizin için çalışmıyorsa android'i kullanın: android ile arka plan: src

android: src büyük numara oynayacak

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

bir cazibe gibi iyi çalışıyor

resim açıklamasını buraya girin


1

Bir ImageView ve bir Bitmap olması gerekiyordu, bu yüzden Bitmap ImageView boyutuna ölçeklendirilmiş ve ImageView boyutu ölçekli Bitmap aynıdır :).

Nasıl yapılacağı için bu yazıya bakıyordum ve sonunda istediğim şeyi yaptım, burada açıklanan şekilde değil.

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

ve sonra onCreateView yönteminde

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

ve daha sonra layoutImageView () kodu

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

}

Sonuç olarak, görüntü en / boy oranını koruyarak mükemmel bir şekilde sığar ve Bitmap içerideyken ImageView'den fazladan kalan piksel içermez.

Sonuç

Wrap_content'a sahip olmak ve ViewBounds'u true olarak ayarlamak önemlidir ImageView, sonra setMaxWidth ve setMaxHeight çalışır, bu ImageView kaynak kodunda yazılır,

/*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. */

0

Bu Picasso ile bir kısıtlama düzeninde yapılması gerekiyordu, bu yüzden yukarıdaki cevapların bazılarını birlikte munged ve bu çözüm ile geldi (zaten yüklediğiniz görüntünün en boy oranını biliyorum, bu yüzden yardımcı olur):

SetContentView (...) sonra bir yerde benim etkinlik kodu çağırdı

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

XML'imde

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

Bir constraintBottom_toBottomOf özniteliğinin eksikliğine dikkat edin. ImageLoader , görüntü yükleme util yöntemleri ve sabitleri için kendi statik sınıfımdır.


0

Çok basit bir çözüm kullanıyorum. İşte benim kod:

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

Resimlerim bir ızgara görünümüne dinamik olarak eklenir. Bu ayarları görüntü görüntüsüne yaptığınızda, resim otomatik olarak 1: 1 oranında görüntülenebilir.


0

Görüntüyü yeniden boyutlandırmak için Basit matematik kullanın. Ya boyutlandırabilirsiniz ImageViewveya üzerinde kümeden daha çekilebilir görüntüyü yeniden boyutlandırabilirsiniz ImageView. ayarlamak istediğiniz bitmap'in genişliğini ve yüksekliğini bulun ve ImageViewistediğiniz yöntemi çağırın. genişlik 500'ün çağrı yönteminden yükseklikten daha büyük olduğunu varsayalım

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

Bu sınıfı yeniden boyutlandırma bitmap'i için kullanırsınız.

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

xml kodu

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

0

Hızlı cevap:

<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" />
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.