Điều chỉnh hình ảnh vào ImageView, giữ tỷ lệ khung hình và sau đó thay đổi kích thước ImageView thành kích thước hình ảnh?


164

Làm thế nào để phù hợp với một hình ảnh có kích thước ngẫu nhiên cho một ImageView?
Khi nào:

  • Ban đầu ImageViewKích thước là 250dp * 250dp
  • Kích thước lớn hơn của hình ảnh nên được tăng / giảm xuống 250dp
  • Hình ảnh phải giữ tỷ lệ khung hình của nó
  • Các ImageViewkích thước nên phù hợp với kích thước thu nhỏ hình ảnh sau khi mở rộng quy mô

Ví dụ: đối với hình ảnh 100 * 150, hình ảnh và ImageViewphải là 166 * 250.
Ví dụ: đối với hình ảnh 150 * 100, hình ảnh vàImageView phải là 250 * 166.

Nếu tôi đặt giới hạn là

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

hình ảnh phù hợp với đúng ImageView, nhưng ImageViewluôn luôn là 250dp * 250dp.


Uh, bạn có nghĩa là thay đổi kích thước của ImageViewkích thước hình ảnh? Ví dụ, hình ảnh của 100dp x 150dp sẽ có tỷ lệ ImageViewtương tự? Hay bạn có nghĩa là làm thế nào để chia tỷ lệ hình ảnh đến ImageViewgiới hạn. Ví dụ: hình ảnh 1000dp x 875dp sẽ được thu nhỏ thành 250dp x 250dp. Bạn có cần duy trì tỷ lệ khung hình?
Jarno Argillander

Tôi muốn ImageView có kích thước của hình ảnh và hình ảnh có kích thước lớn nhất bằng 250dp và giữ tỷ lệ khung hình của nó. Ví dụ: đối với hình ảnh 100 * 150, tôi muốn hình ảnh và ImageView là 166 * 250. Tôi sẽ cập nhật câu hỏi của tôi.
Tháng Bảy

Bạn có muốn chỉ điều chỉnh tỷ lệ / điều chỉnh khi hiển thị một hoạt động (thực hiện một lần) hoặc khi thực hiện một thao tác nào đó trên hoạt động như chọn ảnh từ thư viện / web (thực hiện nhiều lần nhưng không tải) hoặc cả hai?
Jarno Argillander

Xem câu trả lời đã được sửa đổi của tôi, sẽ thực hiện chính xác như bạn mong muốn :)
Jarno Argillander

Câu trả lời:


136

(Câu trả lời đã được sửa đổi rất nhiều sau khi làm rõ câu hỏi ban đầu)

Sau khi làm rõ:
Điều này không thể được thực hiện chỉ trong xml . Không thể chia tỷ lệ cho cả hình ảnh và ImageViewsao cho một chiều của hình ảnh sẽ luôn là 250dp và ImageViewsẽ có cùng kích thước với hình ảnh.

Mã này chia tỷ lệ Drawable của ImageViewmột hình vuông như 250dp x 250dp với một chiều chính xác 250dp và giữ tỷ lệ khung hình. Sau đó, ImageViewkích thước được thay đổi kích thước để phù hợp với kích thước của hình ảnh tỷ lệ. Mã được sử dụng trong một hoạt động. Tôi đã thử nó thông qua nút bấm xử lý.

Thưởng thức. :)

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

Mã xml cho 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"/>


Cảm ơn cuộc thảo luận này về mã chia tỷ lệ:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


CẬP NHẬT ngày 7 tháng 11 năm 2012:
Đã thêm kiểm tra con trỏ null như được đề xuất trong các nhận xét


1
ImageView sẽ luôn là 250 * 250.
Tháng Bảy

2
Đồng ý. Điều đó không thể được thực hiện chỉ trong xml. Mã Java là bắt buộc. Với xml, bạn có thể chia tỷ lệ hình ảnh hoặc ImageViewkhông phải cả hai.
Jarno Argillander

92
không nhận ra bạn có thể thay thế Android: bằng:
StackOverflow

2
Ion là một khuôn khổ cho việc tải hình ảnh và mạng không đồng bộ: github.com/koush/ion
Thomas

1
Java là ngôn ngữ cực kỳ xấu xí vì nó đòi hỏi phải viết rất nhiều mã cho các tác vụ đơn giản như vậy.
Dmitry

245

Có thể không trả lời được cho câu hỏi cụ thể này, nhưng nếu có ai đó, giống như tôi, đang tìm kiếm câu trả lời làm thế nào để phù hợp với hình ảnh trong ImageView với kích thước giới hạn (ví dụ maxWidth:) trong khi duy trì Tỷ lệ khung hình và sau đó thoát khỏi không gian bị chiếm dụng bởi ImageView, thì giải pháp đơn giản nhất là sử dụng các thuộc tính sau trong XML:

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

13
Điều này hoạt động nếu bạn không muốn hình ảnh được thu nhỏ nếu nó quá nhỏ.
Janusz

Làm thế nào để tôi tăng nó lên nếu nó quá nhỏ và cũng duy trì tỷ lệ khung hình?
Kaustubh Bhagwat

nếu ai đó cần, "fitCenter" là một thuộc tính khác cho scaleType và nó sẽ không mở rộng hình ảnh, nhưng đối với bất kỳ hình ảnh lớn nào, nó sẽ phù hợp với kích thước tối đa của hình ảnh bên trong hộp xem duy trì tỷ lệ khung hình
Yogesh Prajapati

để mở rộng hình ảnh nhỏ, sử dụng scaleType = "centreCrop" thay thế.
Eaweb

Một điều nữa để tôi làm việc với giải pháp này là sử dụng "android: src" chứ không phải "android: background" để chỉnh sửa hình ảnh của tôi.
Mã hóa

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

23

Mã dưới đây làm cho bitmap hoàn hảo với cùng kích thước của hình ảnh. Lấy chiều cao và chiều rộng của hình ảnh bitmap và sau đó tính toán chiều cao và chiều rộng mới với sự trợ giúp của các tham số của hình ảnh. Điều đó cung cấp cho bạn hình ảnh cần thiết với tỷ lệ khung hình tốt nhất.

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)

thưởng thức.


3
Điều này sẽ chỉ làm giảm chiều cao ban đầu theo cùng một yếu tố theo đó chiều rộng đã được giảm. Điều này sẽ không đảm bảo rằng newHeight <ivHeight. Tốt nhất bạn nên kiểm tra tỷ lệ nào lớn hơn (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) và sau đó trên cơ sở quyết định này.
Sumit Trehan

1
Điều này thực sự hoạt động hoàn hảo, mặc dù bạn không cần ivHeight hoặc newWidth, chỉ cần đưa ivWidth vào tính toán thay thế.
Stuart

14

hãy thử thêm android:scaleType="fitXY"vào của bạn ImageView.


5
Điều này sẽ sửa đổi tỷ lệ khung hình nếu hình ảnh gốc không bình phương.
Tháng Bảy

1
fitXYhầu như sẽ luôn thay đổi tỷ lệ khung hình của hình ảnh. OP đề cập rõ ràng rằng tỷ lệ khung hình PHẢI được duy trì.
IcyFlame

7

Sau khi tìm kiếm một ngày, tôi nghĩ đây là giải pháp đơn giản nhất:

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

2
Cảm ơn câu trả lời hay của bạn, nhưng tôi nghĩ tốt hơn là thêm adjustViewBoundsvào XML

7

Giải pháp tốt nhất hoạt động trong hầu hết các trường hợp là

Đây là một ví dụ:

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

1
Không dựa vào API không dùng nữa (fill_parent)
fdermishin

Làm thế nào để trả lời câu hỏi của OP. Điều này sẽ không duy trì tỷ lệ aspet
Alex

6

tất cả điều này có thể được thực hiện bằng cách sử dụng XML ... các phương thức khác có vẻ khá phức tạp. Dù sao, bạn chỉ cần đặt chiều cao cho những gì bạn muốn trong dp, sau đó đặt chiều rộng để bọc nội dung hoặc ngược lại. Sử dụng scaleType fitCenter để điều chỉnh kích thước của hình ảnh.

<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

Sử dụng mã này:

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

4

Đã chỉnh sửa Jarno Argillanders trả lời:

Cách điều chỉnh hình ảnh với chiều rộng và chiều cao của bạn:

1) Khởi tạo ImageView và đặt Image:

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

2) Bây giờ thay đổi kích thước:

scaleImage(iv);

scaleImagePhương pháp đã chỉnh sửa : ( bạn có thể thay thế các giá trị giới hạn EXPECTED )

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

Và .xml:

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

Tôi nghĩ rằng dàn diễn viên này: linearLayout.LayoutParams params = (linearLayout.LayoutParams) view.getLayoutParams (); nên đi theo một cách khác, vì MarginLayoutParams kế thừa từ Viewgroup.LayoutParams.
Jay Jacobs

3

Điều này đã làm nó cho trường hợp của tôi.

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

2

Nếu nó không hiệu quả với bạn thì hãy thay thế android: nền bằng android: src

android: src sẽ chơi trò lừa chính

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

nó hoạt động tốt như một bùa mê

nhập mô tả hình ảnh ở đây


1

Tôi cần phải có ImageView và Bitmap, vì vậy Bitmap được chia tỷ lệ thành kích thước ImageView và kích thước của ImageView giống với Bitmap được chia tỷ lệ :).

Tôi đã xem qua bài đăng này để biết cách thực hiện và cuối cùng đã làm những gì tôi muốn, không phải theo cách được mô tả ở đây.

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

và sau đó trong phương thức 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;
}

và sau đó là 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);

}

Và kết quả là hình ảnh phù hợp hoàn hảo bên trong, giữ tỷ lệ khung hình và không có thêm các pixel còn lại từ ImageView khi Bitmap ở bên trong.

Kết quả

Điều quan trọng là ImageView phải có quấn_content và điều chỉnhViewBound thành true, sau đó setMaxWidth và setMaxHeight sẽ hoạt động, điều này được viết trong mã nguồn của 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. */

0

Tôi cần phải thực hiện điều này trong bố cục ràng buộc với Picasso, vì vậy tôi đã tổng hợp một số câu trả lời ở trên và đưa ra giải pháp này (tôi đã biết tỷ lệ khung hình của hình ảnh tôi đang tải, vì vậy điều đó có ích):

Được gọi trong mã hoạt động của tôi ở đâu đó sau khi 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...
    }
}

Trong XML của tôi

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

Lưu ý việc thiếu thuộc tính ràng buộcBottom_toBottomOf. ImageLoader là lớp tĩnh của riêng tôi cho các phương thức và hằng số tải hình ảnh.


0

Tôi đang sử dụng một giải pháp rất đơn giản. Đây là mã của tôi:

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

Hình ảnh của tôi được thêm động trong một khung nhìn. Khi bạn thực hiện các cài đặt này cho chế độ xem hình ảnh, hình ảnh có thể được tự động hiển thị theo tỷ lệ 1: 1.


0

Sử dụng toán đơn giản để thay đổi kích thước hình ảnh. hoặc bạn có thể thay đổi kích thước ImageViewhoặc bạn có thể thay đổi kích thước hình ảnh có thể vẽ hơn là thiết lập ImageView. tìm chiều rộng và chiều cao của bitmap mà bạn muốn đặt ImageViewvà gọi phương thức mong muốn. giả sử chiều rộng 500 của bạn lớn hơn chiều cao so với phương thức gọi

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

Bạn sử dụng lớp này để thay đổi kích thước 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);
   }
 }

mã xml là

<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

Câu trả lời nhanh:

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