0

ScaleType của ImageView trong Android

Giới thiệu

  • Hầu hết tất cả các ứng dụng, web, game trên desktop, web, moblie đều sử dụng hình ảnh. Và trong Android để hiển thị hình ảnh chúng ta sử dụng view được xây dựng sẵn trong Android SDK có tên là ImageView. ImageView là một view có chức năng loading, và hiển thị hình ảnh, hoặc bất cứ drawable. ImageView handle cho chúng ta tất cả các công việc để hiển thị hình ảnh.

ScaleType của ImageView có ý nghĩa như thế nào

  • ScaleType là thuộc tính xác định các thức mà hình ảnh sẽ được scale như thế nào để phù hợp với view của chúng ta. ImageView có thể hiển thị image theo nhiều cách khác nhau phụ thuộc vào các giá trị của thuộc tính scaleType

  • Giả sử chúng ta có một ImageView có kích thước là width = 100px, height = 100px, và hình ảnh có kích thước là 400*500

 <ImageView
        android:scaleType="fitXY"
        android:src="@drawable/my_image"
        android:layout_width="100px"
        android:layout_height="100px" />
  • Khi set scaleType=fitXY thì có nghĩa hình ảnh đó sẽ được scale về kích thước đúng bằng với kích thước của view là 100*100, và kết quả là hình ảnh sẽ được fit đúng với view nhưng hình ảnh không còn giử được ratio của nó nữa.

ImageView có các scaleType mà chúng ta sẽ tìm hiểu dưới đây như sau:

  • center
  • centerInside
  • centerCrop
  • fitcenter
  • fitStart
  • fitEnd
  • fitXY
  • matrix

Giá trị mặc định ScaleType của ImageView

  • Khi chúng ta khởi tạo ImageView bằng XML hay bằng Java code và không set giá trị scaleType thì lúc đó giá trị mặc định của ScaleType sẽ là FIT_CENTER.

Các giá trị ScaleType và ý nghĩa của chúng

  • Ý nghĩa các giá trị ScaleType của ImageView được mô tả chi tiết ở bảng dưới đây:

Screen Shot 2016-11-02 at 00.37.58.png

Và dưới đây là hình ảnh được hiển thị với ImageView sử dụng các ScaleType khác nhau

alt

Và dưới đây là đoạn mã nguồn xử lý scaleType của ImageView

private void configureBounds() {
        if (mDrawable == null || !mHaveFrame) {
            return;
        }

        final int dwidth = mDrawableWidth;
        final int dheight = mDrawableHeight;

        final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
        final int vheight = getHeight() - mPaddingTop - mPaddingBottom;

        final boolean fits = (dwidth < 0 || vwidth == dwidth)
                && (dheight < 0 || vheight == dheight);

        if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);

            if (ScaleType.MATRIX == mScaleType) {
                // Use the specified matrix as-is.
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                                         Math.round((vheight - dheight) * 0.5f));
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else if (ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;

                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }

                dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                dy = Math.round((vheight - dheight * scale) * 0.5f);

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

Scale Bitmap

  • Dưới đây mình sẽ hướng dẫn các bạn các để scale một hình ảnh trong Android như sau.
// Load a bitmap from the drawable folder
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
// Resize the bitmap to 150x100 (width x height)
Bitmap bMapScaled = Bitmap.createScaledBitmap(bMap, 150, 100, true);
// Loads the resized Bitmap into an ImageView
ImageView image = (ImageView) findViewById(R.id.test_image);
image.setImageBitmap(bMapScaled);

Phương thức createScaledBitmap sử dụng để scale Bitmap với các đối số truyền vào là width, height và filter.

  • Nếu bạn muốn scale hình ảnh mà vẫn giữ ratio thì sử dụng class sau:
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);
	}

	// ...
}

Tham khảo: title https://guides.codepath.com/android/Working-with-the-ImageView#scale-types https://developer.android.com/reference/android/widget/ImageView.ScaleType.html


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.