Chia tỷ lệ hình ảnh để lấp đầy chiều rộng ImageView và giữ tỷ lệ khung hình


198

Tôi có một GridView. Dữ liệu củaGridView là yêu cầu từ một máy chủ.

Đây là cách bố trí mục trong 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>

Tôi yêu cầu dữ liệu từ máy chủ, nhận url hình ảnh và tải hình ảnh vào 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;
    }
}

và có mã getView(int position, View convertView, ViewGroup parent)phương thức trong bộ chuyển đổi

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

Kích thước hình ảnh là 210*210. Tôi chạy ứng dụng của mình trên Nexus 4. Hình ảnh không lấp đầy ImageViewchiều rộng, nhưng ImageViewchiều cao không mở rộng.ImageViewkhông hiển thị toàn bộ hình ảnh.

Làm thế nào để tôi giải quyết vấn đề này?

Câu trả lời:


544

Không sử dụng bất kỳ lớp hoặc thư viện tùy chỉnh:

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

scaleType="fitCenter" (mặc định khi bỏ qua)

  • sẽ làm cho nó rộng như cha mẹ cho phép và tăng / giảm tỷ lệ khi cần giữ tỷ lệ khung hình.

scaleType="centerInside"

  • nếu chiều rộng nội tại srcnhỏ hơn chiều rộng cha mẹ
    sẽ căn giữa hình ảnh theo chiều ngang
  • nếu chiều rộng nội tại srclớn hơn chiều rộng cha mẹ
    sẽ làm cho nó rộng bằng tỷ lệ khung hình cho phép và tỷ lệ giữ nguyên tỷ lệ.

Nó không quan trọng nếu bạn sử dụng android:srchoặc ImageView.setImage*phương pháp và chìa khóa có lẽ là adjustViewBounds.


5
android: layout_height = "quấn_content" android: điều chỉnhViewBound = "true" android: scaleType = "fitCenter" thực hiện thủ thuật
James Tan

@JamesTan fill_parentcho chiều rộng chỉ là một thực hành tốt, một kích thước cố định là tốt.
TWiStErRob

@TWiStErRob tôi nhận ra rằng nó cần android: điều chỉnhViewBound = "true" với nó, nếu không nó không phù hợp với chiều cao. và vâng, chiều rộng để vừa với phụ huynh là phiên bản hoàn chỉnh
James Tan

9
Hoạt động như bùa mê trên API 19+, nhưng không hoạt động trên API 16 (đã thử nghiệm). Chế độ xem tùy chỉnh của Alex Semeniuk cũng hoạt động trên API 16.
Ashkan Sarlak

1
@ F.Mysir whops 😅, vâng, không vấn đề nào là vấn đề, nhưng để truyền bá thông lệ tốt, tôi hoàn toàn đồng ý.
TWiStErRob

42

Tôi thích câu trả lời của arnefm nhưng anh ấy đã mắc một lỗi nhỏ (xem bình luận) mà tôi sẽ cố gắng sửa:

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

}

Do đó, ý chí của bạn ImageViewsẽ được thu nhỏ đúng cách và sẽ không có vấn đề về kích thước nếu (ví dụ) đặt bên trongScrollView


Thx, tôi đã tìm thấy giải pháp, ngay bên dưới câu trả lời của arnefm, bình luận đầu tiên mà tôi đã thêm. đó therelà một liên kết
Joe

36

Tôi đã có một vấn đề tương tự một lần. Tôi đã giải quyết nó bằng cách tạo một ImageView tùy chỉnh.

public class CustomImageView extends ImageView

Sau đó ghi đè phương thức onMeasure của chế độ xem hình ảnh. Tôi đã làm một cái gì đó như thế này tôi tin rằng:

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

Điều này sẽ kéo dài hình ảnh để vừa với màn hình trong khi vẫn duy trì tỷ lệ khung hình.


1
thấy . câu trả lời đầu tiên
Joe

Vâng, câu trả lời này là không chính xác. Xem xét tình huống nơi bạn đặt android:layout_height="wrap_content". Trong trường hợp MeasureSpec.getSize(heightMeasureSpec)này sẽ là 0viewSideRatiokết quả của bạn sẽ Infinity(không cần phải thắc mắc, Java float cho phép các giá trị như vậy.) Trong trường hợp này cả bạn heightwidthsẽ 0.
Alex Semeniuk

1
Đối với tôi để thực hiện công việc điền tôi cần để hoán đổi (imageSideRatio> = viewSideRatio) thành (imageSideRatio <viewSideRatio) .. nếu không thì một câu trả lời hay
Marek Halmo

23

Sử dụng android:scaleType="centerCrop".


Không chính xác những gì câu hỏi đã được yêu cầu, nhưng chính xác những gì tôi cần!
nickjm

Bạn có thể giải thích @Jameson không? Ý bạn là phiên bản Android?
Mick

Nếu tôi sử dụng centreCrop, hình ảnh sẽ bị cắt ở trên và dưới một chút.
Saletanth Karumanaghat

9

Tôi đã làm một cái gì đó tương tự như trên và sau đó đập đầu vào tường trong vài giờ vì nó không hoạt động bên trong a RelativeLayout. Tôi đã kết thúc với mã sau đây:

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

Và sau đó để tránh RelativeLayoutbỏ qua kích thước đo được, tôi đã làm điều này:

    <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

Sử dụng các thuộc tính này trong ImageView để giữ tỷ lệ khung hình:

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

9
fitXY KHÔNG giữ tỷ lệ khung hình. Nó kéo dài hình ảnh để phù hợp với chiều rộng và chiều cao của bố cục chính xác.
Giỏ hàng bị bỏ rơi

5

Điều này sẽ không được áp dụng nếu bạn đặt hình ảnh làm nền trong ImageView, cần phải đặt ở src (android: src).

Cảm ơn.


5

Để tạo một hình ảnh có chiều rộng bằng chiều rộng màn hình và chiều cao được đặt theo tỷ lệ theo tỷ lệ khung hình, hãy làm như sau.

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

Hi vọng điêu nay co ich.


đây là câu trả lời hay nhất tôi tìm được, tôi đã tìm kiếm trong 2 ngày, cảm ơn fathima
Karthick Ramanathan

4

Hãy thử điều này: nó đã giải quyết vấn đề cho tôi

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

4

Bạn không cần bất kỳ mã java. Bạn chỉ cần:

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

Khóa nằm trong phần khớp cha mẹ cho chiều rộng và chiều cao


centreCrop thực sự cắt một phần của hình ảnh.
Saletanth Karumanaghat

2

hãy thử với dòng đơn giản này ... thêm dòng này vào mã xml của bạn trong thẻ xem hình ảnh mà không cần thêm bất kỳ phụ thuộc nào vào android: scaleType = "fitXY"


fitXY không duy trì tỷ lệ khung hình nên hình ảnh có thể sẽ bị kéo dài
ProjectDelta

2

sử dụng android: ScaleType = "fitXY" im ImageView xml


fitXY không duy trì tỷ lệ khung hình nên hình ảnh có thể sẽ bị kéo dài
ProjectDelta

1

Bạn có thể thử làm những gì bạn đang làm bằng cách tải hình ảnh theo cách thủ công, nhưng tôi rất khuyến nghị bạn nên xem qua Trình tải ảnh phổ quát .

Gần đây tôi đã tích hợp nó vào dự án của mình và tôi phải nói rằng nó thật tuyệt vời. Có phải tất cả những lo lắng về việc làm cho mọi thứ không đồng bộ, thay đổi kích thước, lưu trữ hình ảnh cho bạn. Thật dễ dàng để tích hợp và thiết lập. Trong vòng 5 phút, bạn có thể có thể làm cho nó làm những gì bạn muốn.

Mã ví dụ:

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

Điều này có thể lười tải hình ảnh, khớp chính xác với kích thước của hình ảnh Xem hiển thị hình ảnh giữ chỗ trong khi tải và hiển thị biểu tượng mặc định nếu tải không thành công và lưu trữ tài nguyên.

- Tôi cũng nên thêm rằng cấu hình hiện tại này giữ tỷ lệ khung hình ảnh, do đó có thể áp dụng cho câu hỏi ban đầu của bạn


0

Chỉ cần sử dụng UniversalImageLoader và thiết lập

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

và không có cài đặt tỷ lệ trên ImageView


0

Tôi đã có một vấn đề tương tự, tôi tìm thấy lý do cho điều này là bởi vì bạn cần phải tính toán dp. Android studio được tính ImageViewkhi bạn tải nó từ drawable, nhưng khi bạn đang sử dụng một phương pháp khác, như tải từ bitmap sự dpkhông tự động chiếm,

Đây là xml của tôi

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

Tôi đang sử dụng Kotlin và tải có thể rút ra từ tệp tài sản, đây là cách tôi tính toán điều này

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

Sử dụng picasso dễ sử dụng ..

Trong bộ chuyển đổi của bạn ..

@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://sapes.github.io/picasso/ nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.