ImageView genişliğini doldurmak ve en boy oranını korumak için Görüntüyü ölçeklendirme


200

Benim bir GridView. Verileri GridViewbir sunucudan istenir.

İşte öğe düzeni GridView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/analysis_micon_bg"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="@dimen/half_activity_vertical_margin"
    android:paddingLeft="@dimen/half_activity_horizontal_margin"
    android:paddingRight="@dimen/half_activity_horizontal_margin"
    android:paddingTop="@dimen/half_activity_vertical_margin" >

    <ImageView
        android:id="@+id/ranking_prod_pic"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:contentDescription="@string/app_name"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/ranking_rank_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/ranking_prod_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/ranking_prod_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Sunucudan veri istiyorum, resim URL'si alıyorum ve resim yüklüyorum Bitmap

public static Bitmap loadBitmapFromInputStream(InputStream is) {
    return BitmapFactory.decodeStream(is);
}

public static Bitmap loadBitmapFromHttpUrl(String url) {
    try {
        return loadBitmapFromInputStream((InputStream) (new URL(url).getContent()));
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
        return null;
    }
}

ve getView(int position, View convertView, ViewGroup parent)bağdaştırıcıda yöntem kodu var

Bitmap bitmap = BitmapUtil.loadBitmapFromHttpUrl(product.getHttpUrl());
prodImg.setImageBitmap(bitmap);

Görüntü boyutu 210*210. Uygulamamı Nexus 4'ümde çalıştırıyorum. Görüntü dolgu ImageViewgenişliği dolduruyor , ancak ImageViewyükseklik ölçeklenmiyor. ImageViewtüm görüntüyü göstermez.

Bu sorunu nasıl çözerim?

Yanıtlar:


548

Herhangi bir özel sınıf veya kitaplık kullanmadan:

<ImageView
    android:id="@id/img"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter" />

scaleType="fitCenter" (atlandığında varsayılan)

  • ebeveynin izin verdiği kadar geniş ve en boy oranını koruyarak gerektiğinde yukarı / aşağı ölçeklendirir.

scaleType="centerInside"

  • iç genişliği srcüst genişlikten küçükse
    görüntüyü yatay olarak ortalar
  • iç genişliği srcana genişlikten daha büyükse
    , üst öğe izin verdiği kadar geniş ve aşağı ölçek tutma en boy oranını sağlayacaktır.

android:srcVeya ImageView.setImage*yöntemleri kullanmak önemli değildir ve anahtar muhtemelen adjustViewBounds.


5
android: layout_height = "wrap_content" android: adjustViewBounds = "true" android: scaleType = "fitCenter" hile yapıyor
James Tan

@JamesTan fill_parentgenişlik için sadece iyi bir uygulamadır, sabit bir boyut da işe yarar.
TWiStErRob

@TWiStErRob i android ihtiyacı gerektiğini fark: adjustViewBounds = "onunla" true, aksi takdirde yükseklik için uygun değildir. ve evet, ebeveyn sığacak genişlik tam sürüm
James Tan

9
API 19 + 'da cazibe gibi çalışır, ancak API 16'da (test edilmiş) çalışmaz. Alex Semeniuk'un özel görünümü API 16 üzerinde de çalışıyor.
Ashkan Sarlak

1
@ F.Mysir whops yes, evet, hangisi sorun için önemli değil, ama iyi uygulamayı yaymak için tamamen katılıyorum.
TWiStErRob

42

Ben arnefm cevabı gibi ama düzeltmeye çalışacağım küçük bir hata yaptı (yorumlara bakın):

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * ImageView that keeps aspect ratio when scaled
 */
public class ScaleImageView extends ImageView {

  public ScaleImageView(Context context) {
    super(context);
  }

  public ScaleImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public ScaleImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    try {
      Drawable drawable = getDrawable();
      if (drawable == null) {
        setMeasuredDimension(0, 0);
      } else {
        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (measuredHeight == 0 && measuredWidth == 0) { //Height and width set to wrap_content
          setMeasuredDimension(measuredWidth, measuredHeight);
        } else if (measuredHeight == 0) { //Height set to wrap_content
          int width = measuredWidth;
          int height = width *  drawable.getIntrinsicHeight() / drawable.getIntrinsicWidth();
          setMeasuredDimension(width, height);
        } else if (measuredWidth == 0){ //Width set to wrap_content
          int height = measuredHeight;
          int width = height * drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
          setMeasuredDimension(width, height);
        } else { //Width and height are explicitly set (either to match_parent or to exact value)
          setMeasuredDimension(measuredWidth, measuredHeight);
        }
      }
    } catch (Exception e) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
  }

}

Böylece, ImageViewdüzgün bir şekilde ölçeklendirilecek ve (örneğin)ScrollView


thx, çözüm buldum, arnefm cevabının hemen altında, eklediğim ilk yorum. bu therebir bağlantıdır
Joe

36

Bir zamanlar benzer bir sorun yaşadım. Özel bir ImageView yaparak çözdüm.

public class CustomImageView extends ImageView

Ardından, görüntüleme görünümünün onMeasure yöntemini geçersiz kılın. Ben böyle bir şey yaptım inanıyorum:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    try {
        Drawable drawable = getDrawable();

        if (drawable == null) {
            setMeasuredDimension(0, 0);
        } else {
            float imageSideRatio = (float)drawable.getIntrinsicWidth() / (float)drawable.getIntrinsicHeight();
            float viewSideRatio = (float)MeasureSpec.getSize(widthMeasureSpec) / (float)MeasureSpec.getSize(heightMeasureSpec);
            if (imageSideRatio >= viewSideRatio) {
                // Image is wider than the display (ratio)
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = (int)(width / imageSideRatio);
                setMeasuredDimension(width, height);
            } else {
                // Image is taller than the display (ratio)
                int height = MeasureSpec.getSize(heightMeasureSpec);
                int width = (int)(height * imageSideRatio);
                setMeasuredDimension(width, height);
            }
        }
    } catch (Exception e) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

Bu, en boy oranını korurken görüntüyü ekrana sığacak şekilde uzatır.


1
oraya bakın . ilk cevap
Joe

Bu cevap doğru değil. Ayarladığınız durumu düşünün android:layout_height="wrap_content". Bu durumda MeasureSpec.getSize(heightMeasureSpec)olacak 0ve viewSideRatiosonuçlanacaktır Infinity(merak etmeye gerek yok, Java float bu değerlere izin verir.) Bu durumda hem sizin heighthem widthde olacaktır 0.
Alex Semeniuk

1
Benim için dolgu işi yapmak için (imageSideRatio> = viewSideRatio) (imageSideRatio <viewSideRatio) takas gerekiyordu .. aksi takdirde iyi bir cevap
Marek Halmo

23

Kullanın android:scaleType="centerCrop".


Sorunun tam olarak ne istediğini değil, tam olarak neye ihtiyacım olduğunu!
nickjm

@ Jameson'u detaylandırabilir misin? Android sürümlerini mi kastediyorsunuz?
Mick

CenterCrop kullanırsam görüntü üstte ve altta biraz kesilir.
Sreekanth Karumanaghat

9

Yukarıdakine benzer bir şey yaptım ve sonra başımı birkaç saat boyunca duvara çarptım çünkü içinde çalışmadı RelativeLayout. Aşağıdaki kod ile sona erdi:

package com.example;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class ScaledImageView extends ImageView {
    public ScaledImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final Drawable d = getDrawable();

        if (d != null) {
            int width;
            int height;
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
                height = MeasureSpec.getSize(heightMeasureSpec);
                width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
            } else {
                width = MeasureSpec.getSize(widthMeasureSpec);
                height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
            }
            setMeasuredDimension(width, height);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

Ve sonra RelativeLayoutölçülen boyutu görmezden gelmemek için bunu yaptım:

    <FrameLayout
        android:id="@+id/image_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/something">

        <com.example.ScaledImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="150dp"/>
    </FrameLayout>

5

En boy oranını korumak için ImageView'da şu özellikleri kullanın:

android:adjustViewBounds="true"
android:scaleType="fitXY"

9
fitXY en boy oranını korumaz. Görüntüyü mizanpajın genişliğine ve yüksekliğine tam olarak uyacak şekilde uzatır.
Terk Edilmiş Araba

5

Resmi ImageView'de arka plan olarak ayarlarsanız, src (android: src) olarak ayarlamanız gerekiyorsa bu geçerli olmayacaktır.

Teşekkürler.


5

Genişliğe sahip bir görüntü ekran genişliğine eşittir ve en boy oranına göre orantılı olarak ayarlanmış bir yükseklik oluşturmak için aşağıdakileri yapın.

Glide.with(context).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {

                        // creating the image that maintain aspect ratio with width of image is set to screenwidth.
                        int width = imageView.getMeasuredWidth();
                        int diw = resource.getWidth();
                        if (diw > 0) {
                            int height = 0;
                            height = width * resource.getHeight() / diw;
                            resource = Bitmap.createScaledBitmap(resource, width, height, false);
                        }
                                              imageView.setImageBitmap(resource);
                    }
                });

Bu yardımcı olur umarım.


bu bulduğum en iyi cevap, ben 2 gün arama, teşekkürler fathima
Karthick Ramanathan

4

Şunu deneyin: benim için problemi çözdü

   android:adjustViewBounds="true"
    android:scaleType="fitXY"

4

Herhangi bir java koduna ihtiyacınız yok. Tek yapmanız gereken:

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

Anahtar, genişlik ve yükseklik için eşleştirme üstündedir


centerCrop aslında görüntünün bir kısmını keser.
Sreekanth Karumanaghat

2

Bu basit çizgi ile deneyin ... herhangi bir bağımlılık ekleyerek xml koduna resim satırı etiketi içinde bu satırı ekleyin android: scaleType = "fitXY"


fitXY en boy oranını korumaz, böylece görüntü muhtemelen uzatılır
ProjectDelta

2

android kullan: ScaleType = "fitXY" im ImageView xml


fitXY en boy oranını korumaz, böylece görüntü muhtemelen uzatılır
ProjectDelta

1

Görüntüleri manuel olarak yükleyerek yaptıklarınızı yapmaya çalışabilirsiniz, ancak Universal Image Loader'a göz atmanızı şiddetle tavsiye ederim .

Son zamanlarda projeme entegre ettim ve harika olduğunu söylemeliyim. İşleri eşzamansız hale getirme, yeniden boyutlandırma, görüntüleri önbelleğe alma ile ilgili tüm endişeleri yapıyor mu? Entegre etmek ve kurmak gerçekten çok kolay. 5 dakika içinde muhtemelen istediğinizi yapabilirsiniz.

Örnek kod:

//ImageLoader config
DisplayImageOptions displayimageOptions = new DisplayImageOptions.Builder().showStubImage(R.drawable.downloadplaceholder).cacheInMemory().cacheOnDisc().showImageOnFail(R.drawable.loading).build();

    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).
            defaultDisplayImageOptions(displayimageOptions).memoryCache(new WeakMemoryCache()).discCache(new UnlimitedDiscCache(cacheDir)).build();

    if (ImageLoader.getInstance().isInited()) {
        ImageLoader.getInstance().destroy();
    }
    ImageLoader.getInstance().init(config);

    imageLoadingListener = new ImageLoadingListener() {
        @Override
        public void onLoadingStarted(String s, View view) {

        }

        @Override
        public void onLoadingFailed(String s, View view, FailReason failReason) {
            ImageView imageView = (ImageView) view;
            imageView.setImageResource(R.drawable.android);
            Log.i("Failed to Load " + s, failReason.toString());
        }

        @Override
        public void onLoadingComplete(String s, View view, Bitmap bitmap) {

        }

        @Override
        public void onLoadingCancelled(String s, View view) {

        }
    };

//Imageloader usage
ImageView imageView = new ImageView(getApplicationContext());
    if (orientation == 1) {
        imageView.setLayoutParams(new LinearLayout.LayoutParams(width / 6, width / 6));
    } else {
        imageView.setLayoutParams(new LinearLayout.LayoutParams(height / 6, height / 6));
    }
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageLoader.displayImage(SERVER_HOSTNAME + "demos" + demo.getPathRoot() + demo.getRootName() + ".png", imageView, imageLoadingListener);

Bu, görüntüleri tembel olarak yükleyebilir, görüntüleri doğru şekilde sığdırabilir Yüklenirken bir yer tutucu görüntüyü gösteren ve yükleme başarısız olursa ve kaynakları önbelleğe alırsa varsayılan bir simge gösterebilir.

- Ayrıca, bu geçerli yapılandırmanın görüntü en boy oranını koruduğunu eklemeliyim, dolayısıyla orijinal sorunuz için geçerlidir


0

UniversalImageLoader kullanın ve ayarlayın

DisplayImageOptions.Builder()
    .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
    .build();

ve ImageView'da ölçek ayarı yok


0

Benzer bir sorunum vardı, bunun nedenini buldum çünkü hesaplamanız gerekiyor dp. Android stüdyo hesaplıyor ImageViewsen onu yüklediğinizde drawable, ancak başka bir yöntemi kullanırken, gelen yükleme gibi bitmapdp otomatik hesaba değil,

İşte benim xml

<ImageView
  android:id="@+id/imageViewer"
  android:layout_width="match_parent"
  android:layout_height="match_parent"//dp is not automaticly updated, when loading from a other source
  android:scaleType="fitCenter"
  tools:srcCompat="@drawable/a8" />

Kotlin kullanıyorum ve bir varlık dosyasından çekilebilir yüklüyorum, bunu nasıl hesaplıyorum

val d = Drawable.createFromStream(assets.open("imageData/${imageName}.png"), null)
bitHeight = d.minimumHeight//get the image height
imageViewer.layoutParams.height = (bitHeight * resources.displayMetrics.density).toInt()//set the height
imageViewer.setImageDrawable(d)//set the image from the drawable
imageViewer.requestLayout()//here I apply it to the layout

-1

Kullanımı kolay picasso kullanın ..

Adaptörünüzde ..

@Override
public void getView(int position, View convertView, ViewGroup parent) {

 ImageView view = (ImageView) convertView.findViewById(R.id.ranking_prod_pic);

 Picasso.with(context).load(url).into(view); //url is image url

 //you can resize image if you want

 /* Picasso.with(context) .load(url) .resize(50, 50) .centerCrop() .into(view) */

}

http://square.github.io/picasso/ resim açıklamasını buraya girin

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.