ปรับขนาดภาพเพื่อเติมเต็มความกว้าง ImageView และรักษาอัตราส่วน


200

GridViewฉันมี ข้อมูลของGridViewคือคำขอจากเซิร์ฟเวอร์

นี่คือเค้าโครงรายการใน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>

ฉันขอข้อมูลจากเซิร์ฟเวอร์รับ URL รูปภาพและโหลดภาพไปที่ 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;
    }
}

และมีรหัสของgetView(int position, View convertView, ViewGroup parent)วิธีการในอะแดปเตอร์

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

210*210ขนาดของภาพที่ได้คือ ฉันเรียกใช้แอปพลิเคชันของฉันใน Nexus 4 ของฉันภาพเต็มImageViewความกว้าง แต่ImageViewความสูงไม่ได้ปรับขนาด ImageViewไม่แสดงภาพรวมทั้งหมด

ฉันจะแก้ปัญหานี้ได้อย่างไร

คำตอบ:


548

โดยไม่ต้องใช้คลาสหรือไลบรารีที่กำหนดเอง:

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

scaleType="fitCenter" (ค่าเริ่มต้นเมื่อละเว้น)

  • จะทำให้มันกว้างเท่าที่ผู้ปกครองอนุญาตและขึ้น / ลงในระดับที่ต้องการรักษาอัตราส่วนกว้างยาว

scaleType="centerInside"

  • หากความกว้างที่แท้จริงของsrcเล็กกว่าความกว้างหลัก
    จะจัดกึ่งกลางของภาพในแนวนอน
  • หากความกว้างที่แท้จริงของsrcมีขนาดใหญ่กว่าความกว้างหลัก
    จะทำให้ความกว้างเท่ากับที่ผู้ปกครองอนุญาตและอัตราส่วนการรักษาในระดับล่าง

มันไม่สำคัญว่าถ้าคุณใช้android:srcหรือวิธีการและที่สำคัญอาจจะเป็นImageView.setImage*adjustViewBounds


5
android: layout_height = "wrap_content" android: adjustViewBounds = "true" android: scaleType = "fitCenter" ทำการหลอกลวง
James Tan

@ James fill_parentสำหรับความกว้างเป็นเพียงการปฏิบัติที่ดีขนาดคงที่เช่นกัน
TWiStErRob

@TWiStErRob ฉันรู้ว่ามันต้องการ android: adjustViewBounds = "true" กับมันมิฉะนั้นมันจะไม่พอดีกับความสูง และใช่ความกว้างที่เหมาะสมกับผู้ปกครองคือเวอร์ชั่นที่สมบูรณ์
James Tan

9
ใช้งานได้อย่างมีเสน่ห์ใน API 19+ แต่ไม่ใช่ใน API 16 (ทดสอบแล้ว) มุมมองที่กำหนดเองของ Alex Semeniuk ใช้งานได้กับ API 16 ด้วย
Ashkan Sarlak

1
@ F.Mysir whops 😅ใช่มันไม่สำคัญว่าปัญหาจะเกิดขึ้นที่ใด แต่สำหรับการเผยแพร่แนวปฏิบัติที่ดีฉันเห็นด้วยอย่างยิ่ง
TWiStErRob

42

ฉันชอบคำตอบของ arnefm แต่เขาทำผิดเล็กน้อย (ดูความคิดเห็น) ซึ่งฉันจะพยายามแก้ไข:

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

}

ดังนั้นคุณ ImageViewจะถูกปรับอย่างเหมาะสมและจะไม่มีปัญหาด้านมิติถ้า (เช่น) ใส่เข้าไปข้างในScrollView


ขอบคุณฉันได้พบทางออกด้านล่างคำตอบของ arnefm ความคิดเห็นแรกที่ฉันเพิ่ม นั่นthereคือลิงค์
Joe

36

ฉันมีปัญหาที่คล้ายกันหนึ่งครั้ง ฉันแก้ไขมันด้วยการสร้าง ImageView ที่กำหนดเอง

public class CustomImageView extends ImageView

จากนั้นแทนที่เมธอด onMeasure ของ imageview ฉันทำอะไรแบบนี้ฉันเชื่อว่า:

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

นี่จะเป็นการยืดภาพให้พอดีกับหน้าจอในขณะที่ยังคงอัตราส่วนไว้


1
เห็นมี คำตอบแรก
Joe

คำตอบนี้ไม่ถูกต้อง android:layout_height="wrap_content"พิจารณาสถานการณ์ที่คุณตั้ง ในกรณีนี้MeasureSpec.getSize(heightMeasureSpec)จะเป็น0ของคุณและviewSideRatioจะมีผลในInfinity(ไม่ต้องสงสัย, Java ช่วยให้ลอยค่าดังกล่าว.) ในกรณีนี้ทั้งของคุณheightและจะwidth 0
Alex Semeniuk

1
สำหรับผมที่จะทำให้การทำงานเติมฉันต้องการที่จะแลกเปลี่ยน (imageSideRatio> = viewSideRatio) ถึง (imageSideRatio <viewSideRatio) .. มิฉะนั้นคำตอบที่ดี
มาเร็ค Halmo

23

android:scaleType="centerCrop"ใช้


ไม่ใช่คำถามที่ถาม แต่สิ่งที่ฉันต้องการ!
nickjm

คุณช่วยอธิบาย @Jameson ได้ไหม? คุณหมายถึงเวอร์ชั่น Android หรือไม่
มิก

ถ้าฉันใช้ centerCrop ภาพจะถูกตัดทั้งส่วนบนและล่างเล็กน้อย
ชาวกรีก Karumanaghat

9

RelativeLayoutผมทำอะไรคล้ายกับข้างต้นแล้วกระแทกหัวของฉันกับผนังไม่กี่ชั่วโมงเพราะมันไม่ได้ทำงานภายใน ฉันลงเอยด้วยรหัสต่อไปนี้:

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

จากนั้นเพื่อป้องกันไม่ให้มองRelativeLayoutข้ามมิติข้อมูลที่วัดฉันทำสิ่งนี้:

    <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

ใช้คุณสมบัติเหล่านี้ใน ImageView เพื่อรักษาอัตราส่วน:

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

9
fitXY ไม่ได้รักษาอัตราส่วนกว้างยาว มันยืดภาพให้พอดีกับความกว้างและความสูงของเค้าโครงอย่างแน่นอน
รถเข็นที่ถูกทิ้งร้าง

5

สิ่งนี้จะไม่สามารถใช้งานได้หากคุณตั้งภาพเป็นพื้นหลังใน ImageView จำเป็นต้องตั้งไว้ที่ src (android: src)

ขอบคุณ


5

ในการสร้างภาพที่มีความกว้างเท่ากับความกว้างของหน้าจอและความสูงตั้งตามสัดส่วนตามอัตราส่วนให้ทำดังต่อไปนี้

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

หวังว่านี่จะช่วยได้


นี่คือคำตอบที่ดีที่สุดที่ฉันพบฉันค้นหา 2 วันขอบคุณ fathima
Karthick Ramanathan


4

โย่ไม่ต้องการโค้ดจาวาใด ๆ คุณเพียงแค่ต้อง:

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

คีย์อยู่ในพาเรนต์การจับคู่สำหรับความกว้างและความสูง


centerCrop ตัดภาพบางส่วนออกจริง ๆ
ชาวกรีก Karumanaghat

2

ลองกับบรรทัดง่าย ๆ นี้ ... เพิ่มบรรทัดนี้ในโค้ด xml ของคุณในแท็กมุมมองภาพโดยไม่เพิ่มการพึ่งพาใด ๆ android: scaleType = "fitXY"


fitXY ไม่ได้รักษาอัตราส่วนภาพไว้ดังนั้นภาพน่าจะถูกยืดออก
ProjectDelta


1

คุณสามารถพยายามที่จะทำสิ่งที่คุณทำด้วยตนเองโดยการโหลดภาพ แต่ผมมากจะขอแนะนำการดูที่โหลดภาพสากล

ฉันเพิ่งรวมเข้ากับโครงการของฉันและฉันต้องบอกว่ามันยอดเยี่ยม ความกังวลเกี่ยวกับการทำสิ่งต่าง ๆ ไม่ตรงกันปรับขนาดแคชรูปภาพสำหรับคุณหรือไม่ ง่ายมากที่จะรวมและตั้งค่า ภายใน 5 นาทีคุณสามารถทำให้สิ่งที่คุณต้องการได้

รหัสตัวอย่าง:

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

วิธีนี้สามารถทำการโหลดรูปภาพให้พอดีกับขนาดของ imageView ที่แสดงรูปภาพตัวยึดในขณะที่โหลดและแสดงไอคอนเริ่มต้นหากการโหลดล้มเหลวและแคชทรัพยากร

- ฉันควรเพิ่มว่าการกำหนดค่าปัจจุบันนี้รักษาอัตราส่วนภาพด้วยดังนั้นจึงสามารถนำไปใช้กับคำถามเดิมของคุณได้


0

เพียงใช้ UniversalImageLoader และตั้งค่า

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

และไม่มีการตั้งค่ามาตราส่วนบน ImageView


0

dpผมมีปัญหาที่คล้ายกันผมพบว่าเหตุผลนี้เป็นเพราะคุณจะต้องคำนวณ Android สตูดิโอคำนวณImageViewเมื่อคุณโหลดได้จากdrawableแต่เมื่อคุณใช้วิธีอื่นเช่นการโหลดจากบิตแมปdpไม่ได้คิดโดยอัตโนมัติ,

นี่คือ 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 และโหลดได้จากไฟล์เนื้อหานี่คือวิธีคำนวณของฉัน

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

ใช้ปิกัสโซซึ่งใช้งานง่าย ..

ในอะแดปเตอร์ของคุณ ..

@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/ ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.