ImageView ปรับขนาด TOP_CROP


88

ฉันมีImageViewซึ่งกำลังแสดง png ที่มีอัตราส่วนกว้างยาวกว่าของอุปกรณ์ (พูดในแนวตั้ง - หมายถึงยาวกว่า) ฉันต้องการแสดงสิ่งนี้ในขณะที่รักษาอัตราส่วนภาพให้ตรงกับความกว้างของพาเรนต์และตรึงมุมมองภาพไว้ที่ด้านบนสุดของหน้าจอ

ปัญหาที่ฉันพบในการใช้CENTER_CROPเป็นประเภทมาตราส่วนคือจะ (เข้าใจได้) จัดกึ่งกลางภาพที่ปรับขนาดแทนที่จะจัดขอบด้านบนให้ชิดขอบด้านบน f มุมมองภาพ

ปัญหาFIT_STARTคือภาพจะพอดีกับความสูงของหน้าจอและไม่เต็มความกว้าง

ฉันได้แก้ไขปัญหานี้โดยใช้ ImageView แบบกำหนดเองและการลบล้างonDraw(Canvas)และจัดการสิ่งนี้ด้วยตนเองโดยใช้ผืนผ้าใบ ปัญหาของวิธีนี้คือ 1) ฉันกังวลว่าอาจมีวิธีแก้ปัญหาที่ง่ายกว่านี้ 2) ฉันได้รับข้อยกเว้น VM mem เมื่อเรียกsuper(AttributeSet)ในตัวสร้างเมื่อพยายามตั้งค่า src img เป็น 330kb เมื่อฮีปมีพื้นที่ว่าง 3 mb (มีขนาดฮีป 6 mb) และไม่สามารถหาสาเหตุได้

ยินดีรับความคิดเห็น / ข้อเสนอแนะ / แนวทางแก้ไข :)

ขอบคุณ

ป.ล. ฉันคิดว่าวิธีแก้ปัญหาอาจต้องใช้ประเภทมาตราส่วนเมทริกซ์และทำด้วยตัวเอง แต่ดูเหมือนว่าจะเหมือนกันหรือได้ผลมากกว่าโซลูชันปัจจุบันของฉัน!


1
คุณลองใช้ CENTER_CROP และตั้งค่าคุณสมบัติ adjustmentViewBounds เป็นจริงกับ ImageView หรือไม่?
PravinCG

2
ใช่ฉันได้ลองแล้วขอบคุณไม่ประสบความสำเร็จฉันกลัวเพราะมันจะขยายมุมมองจนกว่าจะกว้างขึ้นซึ่งจะไม่ใหญ่กว่าหน้าจอจากนั้นจัดกึ่งกลางภาพบนหน้าจอด้วยความสูงส่วนเกิน / 2 แหย่ออกจากด้านบน และด้านล่าง
Dori

คำตอบ:


85

โอเคฉันมีวิธีแก้ปัญหาที่ใช้ได้ พรอมต์จาก Darko ทำให้ฉันมองไปที่คลาส ImageView อีกครั้ง (ขอบคุณ) และใช้การเปลี่ยนแปลงโดยใช้เมทริกซ์ (ตามที่ฉันเคยสงสัยในตอนแรก แต่ไม่ประสบความสำเร็จในความพยายามครั้งแรก!) ในคลาส imageView ที่กำหนดเองของฉันฉันเรียกsetScaleType(ScaleType.MATRIX)ตามหลังsuper()ในตัวสร้างและมีวิธีการต่อไปนี้

    @Override
    protected boolean setFrame(int l, int t, int r, int b)
    {
        Matrix matrix = getImageMatrix(); 
        float scaleFactor = getWidth()/(float)getDrawable().getIntrinsicWidth();    
        matrix.setScale(scaleFactor, scaleFactor, 0, 0);
        setImageMatrix(matrix);
        return super.setFrame(l, t, r, b);
    }

ฉันได้วาง int ไว้ในsetFrame()เมธอดเช่นเดียวกับใน ImageView การเรียกไปยังconfigureBounds()อยู่ในเมธอดนี้ซึ่งเป็นที่ที่การปรับขนาดและเมทริกซ์ทั้งหมดเกิดขึ้นดังนั้นดูเหมือนจะมีเหตุผลสำหรับฉัน (พูดว่าคุณไม่เห็นด้วย)

ด้านล่างนี้คือ super.setFrame () วิธีการจาก AOSP

 @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        boolean changed = super.setFrame(l, t, r, b);
        mHaveFrame = true;
        configureBounds();
        return changed;
    }

ค้นหา src คลาสเต็มได้ที่นี่


ขอบคุณสำหรับรหัส @doridori! มันใช้ได้! ฉันไม่เข้าใจว่าทำไมคุณถึงทำซ้ำเมธอด "setFrame" ในคำอธิบายของคุณ ... ฉันใช้เพียงวิธีแรกที่ประสบความสำเร็จ (และไม่สนใจ xD ที่สองโดยสิ้นเชิง)
Alesqui

3
หลังจากต่อสู้กับสิ่งนี้ผ่านเลย์เอาต์ xml เป็นเวลาสองชั่วโมงสิ่งนี้ได้ผล ฉันหวังว่าฉันจะให้คุณขึ้นเรือได้มากกว่านี้
Mark Beaton

5
ฉันต้องโทรหา super () ก่อนร่างกายไม่เช่นนั้นภาพจะไม่แสดงหากไม่มีการทาสีใหม่
sherpya

1
@VitorHugoSchwaab คุณต้องใช้ thms เช่น matrix.postTranslate (.. )
Anton Kizema

1
ใช้พื้นหลังไม่ได้ใช่ไหมใช้ src เท่านั้น?
Egos Zhang

43

นี่คือรหัสของฉันสำหรับจัดกึ่งกลางที่ด้านล่าง Btw. ในรหัสของ Dori เป็นข้อผิดพลาดเล็กน้อยเนื่องจากsuper.frame()มีการเรียกใช้ในตอนท้ายgetWidth()เมธอดอาจส่งคืนค่าที่ไม่ถูกต้อง หากคุณต้องการจัดกึ่งกลางที่ด้านบนเพียงแค่ลบบรรทัด postTranslate เท่านี้ก็เสร็จแล้ว สิ่งที่ดีคือด้วยรหัสนี้คุณสามารถย้ายไปได้ทุกที่ที่คุณต้องการ (ขวาศูนย์ => ไม่มีปัญหา;)

    public class CenterBottomImageView extends ImageView {

        public CenterBottomImageView(Context context) {
            super(context);
            setup();
        }

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

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

        private void setup() {
            setScaleType(ScaleType.MATRIX);
        }

        @Override
        protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) {
            if (getDrawable() == null) {
                return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
            }
            float frameWidth = frameRight - frameLeft;
            float frameHeight = frameBottom - frameTop;

            float originalImageWidth = (float)getDrawable().getIntrinsicWidth();
            float originalImageHeight = (float)getDrawable().getIntrinsicHeight();

            float usedScaleFactor = 1;

            if((frameWidth > originalImageWidth) || (frameHeight > originalImageHeight)) {
                // If frame is bigger than image
                // => Crop it, keep aspect ratio and position it at the bottom and center horizontally

                float fitHorizontallyScaleFactor = frameWidth/originalImageWidth;
                float fitVerticallyScaleFactor = frameHeight/originalImageHeight;

                usedScaleFactor = Math.max(fitHorizontallyScaleFactor, fitVerticallyScaleFactor);
            }

            float newImageWidth = originalImageWidth * usedScaleFactor;
            float newImageHeight = originalImageHeight * usedScaleFactor;

            Matrix matrix = getImageMatrix();
            matrix.setScale(usedScaleFactor, usedScaleFactor, 0, 0); // Replaces the old matrix completly
//comment matrix.postTranslate if you want crop from TOP
            matrix.postTranslate((frameWidth - newImageWidth) /2, frameHeight - newImageHeight);
            setImageMatrix(matrix);
            return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
        }

    }

เยี่ยมมากขอบคุณที่ชี้ให้เห็นข้อบกพร่อง ฉันไม่ได้แตะรหัสนี้มาระยะหนึ่งแล้วดังนั้นนี่อาจเป็นคำแนะนำที่โง่ แต่เพื่อแก้ไขข้อผิดพลาด setWidth ที่คุณชี้ให้เห็นไม่เพียงแค่ใช้(r-l)แทน
Dori

if((frameWidth > originalImageWidth) || (frameHeight > originalImageHeight))ควรกลับเส้นกันแน่? กล่าวอีกนัยหนึ่งคุณไม่ควรทดสอบว่าภาพใหญ่กว่าเฟรมหรือไม่? ฉันขอแนะนำให้แทนที่ด้วยif((originalImageWidth > frameWidth ) || (originalImageHeight > frameHeight ))
Carlos P

ฉันเลือกความกว้างจากผู้ปกครองที่ใช้((View) getParent()).getWidth()ตั้งแต่ImageViewมีMATCH_PARENT
sherpya

@ มันใช้งานได้ดี ฉันกำลังทำการคำนวณเมทริกซ์ในเมธอด onLayout () ซึ่งจะถูกเรียกในการหมุนเวียนด้วยโดยที่ setFrame ไม่ได้
กล่อง

ขอบคุณสำหรับสิ่งนี้ทำงานได้อย่างสมบูรณ์และขอบคุณที่ให้วิธีการเปลี่ยนการครอบตัดล่างเป็นการครอบตัดด้านบนอย่างรวดเร็วโดยการแสดงความคิดเห็น 1 บรรทัดของรหัส
Moonbloom

39

คุณไม่จำเป็นต้องเขียน Custom Image View เพื่อรับTOP_CROPฟังก์ชัน คุณเพียงแค่ต้องแก้ไขmatrixไฟล์ImageView.

  1. ตั้งค่าscaleTypeการmatrixสำหรับImageView:

    <ImageView
          android:id="@+id/imageView"
          android:contentDescription="Image"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:src="@drawable/image"
          android:scaleType="matrix"/>
    
  2. ตั้งค่าเมทริกซ์ที่กำหนดเองสำหรับImageView:

    final ImageView imageView = (ImageView) findViewById(R.id.imageView);
    final Matrix matrix = imageView.getImageMatrix();
    final float imageWidth = imageView.getDrawable().getIntrinsicWidth();
    final int screenWidth = getResources().getDisplayMetrics().widthPixels;
    final float scaleRatio = screenWidth / imageWidth;
    matrix.postScale(scaleRatio, scaleRatio);
    imageView.setImageMatrix(matrix);
    

การทำเช่นนี้จะทำให้คุณมีTOP_CROPฟังก์ชันการทำงาน


2
สิ่งนี้ได้ผลสำหรับฉัน แต่ผมต้องตรวจสอบ scaleRation ถ้ามันเป็น <1 ผมแล้วก็เปลี่ยนscaleTypeไปcenterCropมิฉะนั้นผมจะเห็นพื้นที่ว่างบนขอบ
ARST

วิธีทำให้ใช้งานได้ในกรณีที่ต้องการรูปภาพที่จัดชิดด้านล่าง
Sagar

26

ตัวอย่างนี้ใช้ได้กับรูปภาพที่โหลดหลังจากสร้างอ็อบเจกต์ + การปรับให้เหมาะสมบางอย่าง ฉันเพิ่มความคิดเห็นในโค้ดที่อธิบายว่าเกิดอะไรขึ้น

อย่าลืมโทร:

imageView.setScaleType(ImageView.ScaleType.MATRIX);

หรือ

android:scaleType="matrix"

แหล่ง Java:

import com.appunite.imageview.OverlayImageView;

public class TopAlignedImageView extends ImageView {
    private Matrix mMatrix;
    private boolean mHasFrame;

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context) {
        this(context, null, 0);
    }

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mHasFrame = false;
        mMatrix = new Matrix();
        // we have to use own matrix because:
        // ImageView.setImageMatrix(Matrix matrix) will not call
        // configureBounds(); invalidate(); because we will operate on ImageView object
    }

    @Override
    protected boolean setFrame(int l, int t, int r, int b)
    {
        boolean changed = super.setFrame(l, t, r, b);
        if (changed) {
            mHasFrame = true;
            // we do not want to call this method if nothing changed
            setupScaleMatrix(r-l, b-t);
        }
        return changed;
    }

    private void setupScaleMatrix(int width, int height) {
        if (!mHasFrame) {
            // we have to ensure that we already have frame
            // called and have width and height
            return;
        }
        final Drawable drawable = getDrawable();
        if (drawable == null) {
            // we have to check if drawable is null because
            // when not initialized at startup drawable we can
            // rise NullPointerException
            return;
        }
        Matrix matrix = mMatrix;
        final int intrinsicWidth = drawable.getIntrinsicWidth();
        final int intrinsicHeight = drawable.getIntrinsicHeight();

        float factorWidth = width/(float) intrinsicWidth;
        float factorHeight = height/(float) intrinsicHeight;
        float factor = Math.max(factorHeight, factorWidth);

        // there magic happen and can be adjusted to current
        // needs
        matrix.setTranslate(-intrinsicWidth/2.0f, 0);
        matrix.postScale(factor, factor, 0, 0);
        matrix.postTranslate(width/2.0f, 0);
        setImageMatrix(matrix);
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    // We do not have to overide setImageBitmap because it calls 
    // setImageDrawable method

}

วิธีทำให้ใช้งานได้ในกรณีที่ต้องการภาพที่จัดชิดด้านล่าง?
Sagar

13

จาก Dori ฉันใช้วิธีแก้ปัญหาที่ปรับขนาดภาพตามความกว้างหรือความสูงของรูปภาพเพื่อเติมเต็มคอนเทนเนอร์โดยรอบเสมอ สิ่งนี้ช่วยให้การปรับขนาดภาพเพื่อเติมเต็มพื้นที่ว่างทั้งหมดโดยใช้จุดบนซ้ายของภาพแทนที่จะเป็นจุดศูนย์กลางเป็นจุดเริ่มต้น (CENTER_CROP):

@Override
protected boolean setFrame(int l, int t, int r, int b)
{

    Matrix matrix = getImageMatrix(); 
    float scaleFactor, scaleFactorWidth, scaleFactorHeight;
    scaleFactorWidth = (float)width/(float)getDrawable().getIntrinsicWidth();
    scaleFactorHeight = (float)height/(float)getDrawable().getIntrinsicHeight();    

    if(scaleFactorHeight > scaleFactorWidth) {
        scaleFactor = scaleFactorHeight;
    } else {
        scaleFactor = scaleFactorWidth;
    }

    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);

    return super.setFrame(l, t, r, b);
}

ฉันหวังว่านี่จะช่วยได้ - ใช้งานได้เหมือนการรักษาในโครงการของฉัน


11
นี่คือทางออกที่ดีกว่า ... และเพิ่ม: float width = r - l; ลอยสูง = b - t;
Geltrude

9

วิธีแก้ปัญหาเหล่านี้ไม่ได้ผลสำหรับฉันเพราะฉันต้องการคลาสที่รองรับการครอบตัดตามอำเภอใจจากทิศทางแนวนอนหรือแนวตั้งและฉันต้องการให้ฉันเปลี่ยนการครอบตัดแบบไดนามิก ฉันต้องการความเข้ากันได้ของPicassoด้วยและ Picasso ก็ตั้งค่าการวาดภาพอย่างเฉื่อยชา

การใช้งานของฉันได้รับการดัดแปลงโดยตรงจากImageView.javaใน AOSP หากต้องการใช้ให้ประกาศเช่นนี้ใน XML:

    <com.yourapp.PercentageCropImageView
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="matrix"/>

จากแหล่งที่มาหากคุณต้องการมีการปลูกพืชด้านบนโทร:

imageView.setCropYCenterOffsetPct(0f);

หากต้องการครอปล่างโทร:

imageView.setCropYCenterOffsetPct(1.0f);

หากคุณต้องการครอบตัด 1/3 ของทางลงให้โทร:

imageView.setCropYCenterOffsetPct(0.33f);

นอกจากนี้หากคุณเลือกที่จะใช้วิธีการครอบตัดแบบอื่นเช่น fit_center คุณสามารถทำได้และจะไม่มีการทริกเกอร์ตรรกะที่กำหนดเองนี้ (การใช้งานอื่น ๆ ให้คุณใช้วิธีการครอบตัดเท่านั้น)

สุดท้ายนี้ฉันได้เพิ่มวิธีการวาดใหม่ () ดังนั้นหากคุณเลือกที่จะเปลี่ยนวิธีการครอบตัด / scaleType แบบไดนามิกในโค้ดคุณสามารถบังคับให้มุมมองวาดใหม่ได้ ตัวอย่างเช่น:

fullsizeImageView.setScaleType(ScaleType.FIT_CENTER);
fullsizeImageView.redraw();

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

fullsizeImageView.setScaleType(ScaleType.MATRIX);
fullsizeImageView.redraw();

นี่คือชั้นเรียน:

/* 
 * Adapted from ImageView code at: 
 * http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/widget/ImageView.java
 */
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class PercentageCropImageView extends ImageView{

    private Float mCropYCenterOffsetPct;
    private Float mCropXCenterOffsetPct;

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

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

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

    public float getCropYCenterOffsetPct() {
        return mCropYCenterOffsetPct;
    }

    public void setCropYCenterOffsetPct(float cropYCenterOffsetPct) {
        if (cropYCenterOffsetPct > 1.0) {
            throw new IllegalArgumentException("Value too large: Must be <= 1.0");
        }
        this.mCropYCenterOffsetPct = cropYCenterOffsetPct;
    }

    public float getCropXCenterOffsetPct() {
        return mCropXCenterOffsetPct;
    }

    public void setCropXCenterOffsetPct(float cropXCenterOffsetPct) {
        if (cropXCenterOffsetPct > 1.0) {
            throw new IllegalArgumentException("Value too large: Must be <= 1.0");
        }
        this.mCropXCenterOffsetPct = cropXCenterOffsetPct;
    }

    private void myConfigureBounds() {
        if (this.getScaleType() == ScaleType.MATRIX) {
            /*
             * Taken from Android's ImageView.java implementation:
             * 
             * Excerpt from their source:
    } 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((int) (dx + 0.5f), (int) (dy + 0.5f));
    }
             */

            Drawable d = this.getDrawable();
            if (d != null) {
                int dwidth = d.getIntrinsicWidth();
                int dheight = d.getIntrinsicHeight();

                Matrix m = new Matrix();

                int vwidth = getWidth() - this.getPaddingLeft() - this.getPaddingRight();
                int vheight = getHeight() - this.getPaddingTop() - this.getPaddingBottom();

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

                if (dwidth * vheight > vwidth * dheight) {
                    float cropXCenterOffsetPct = mCropXCenterOffsetPct != null ? 
                            mCropXCenterOffsetPct.floatValue() : 0.5f;
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * cropXCenterOffsetPct;
                } else {
                    float cropYCenterOffsetPct = mCropYCenterOffsetPct != null ? 
                            mCropYCenterOffsetPct.floatValue() : 0f;

                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * cropYCenterOffsetPct;
                }

                m.setScale(scale, scale);
                m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

                this.setImageMatrix(m);
            }
        }
    }

    // These 3 methods call configureBounds in ImageView.java class, which
    // adjusts the matrix in a call to center_crop (android's built-in 
    // scaling and centering crop method). We also want to trigger
    // in the same place, but using our own matrix, which is then set
    // directly at line 588 of ImageView.java and then copied over
    // as the draw matrix at line 942 of ImageVeiw.java
    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        boolean changed = super.setFrame(l, t, r, b);
        this.myConfigureBounds();
        return changed;
    }
    @Override
    public void setImageDrawable(Drawable d) {          
        super.setImageDrawable(d);
        this.myConfigureBounds();
    }
    @Override
    public void setImageResource(int resId) {           
        super.setImageResource(resId);
        this.myConfigureBounds();
    }

    public void redraw() {
        Drawable d = this.getDrawable();

        if (d != null) {
            // Force toggle to recalculate our bounds
            this.setImageDrawable(null);
            this.setImageDrawable(d);
        }
    }
}

5

อาจจะเข้าไปในซอร์สโค้ดสำหรับมุมมองภาพบน Android และดูว่ามันดึงการครอบตัดกลางเป็นต้นและอาจคัดลอกโค้ดบางส่วนลงในวิธีการของคุณ ฉันไม่รู้วิธีแก้ปัญหาที่ดีไปกว่าการทำเช่นนี้ ฉันมีประสบการณ์ในการปรับขนาดและครอบตัดบิตแมปด้วยตนเอง (ค้นหาการแปลงบิตแมป) ซึ่งจะลดขนาดจริง แต่ยังคงสร้างค่าใช้จ่ายเล็กน้อยในกระบวนการ


3
public class ImageViewTopCrop extends ImageView {
public ImageViewTopCrop(Context context) {
    super(context);
    setScaleType(ScaleType.MATRIX);
}

public ImageViewTopCrop(Context context, AttributeSet attrs) {
    super(context, attrs);
    setScaleType(ScaleType.MATRIX);
}

public ImageViewTopCrop(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setScaleType(ScaleType.MATRIX);
}

@Override
protected boolean setFrame(int l, int t, int r, int b) {
    computMatrix();
    return super.setFrame(l, t, r, b);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    computMatrix();
}

private void computMatrix() {
    Matrix matrix = getImageMatrix();
    float scaleFactor = getWidth() / (float) getDrawable().getIntrinsicWidth();
    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);
}

}


computMatrix: คุณสามารถทำเมทริกซ์ใดก็ได้ที่นี่
tianxia

onLayoutช่วยฉันได้มาก! ขอบคุณ! ฉันพบปัญหาที่คำนวณเมทริกซ์ แต่ไม่แสดงภาพทันทีและการเพิ่มonLayoutโค้ดช่วยแก้ปัญหาของฉันได้
natsumiyu

1

หากคุณใช้Fresco (SimpleDraweeView)คุณสามารถทำได้อย่างง่ายดายด้วย:

 PointF focusPoint = new PointF(0.5f, 0f);
 imageDraweeView.getHierarchy().setActualImageFocusPoint(focusPoint);

อันนี้จะเป็นสำหรับการปลูกพืชด้านบน

ข้อมูลเพิ่มเติมที่ลิงค์อ้างอิง


0

มี 2 ​​ปัญหาในการแก้ไขที่นี่:

  • พวกเขาไม่แสดงผลในโปรแกรมแก้ไขเค้าโครงของ Android Studio (คุณจึงสามารถดูตัวอย่างในขนาดหน้าจอและอัตราส่วนต่างๆได้)
  • มันปรับขนาดตามความกว้างเท่านั้นดังนั้นขึ้นอยู่กับอัตราส่วนภาพของอุปกรณ์และรูปภาพคุณสามารถจบลงด้วยแถบว่างที่ด้านล่าง

การปรับเปลี่ยนเล็กน้อยนี้ช่วยแก้ปัญหาได้ (วางโค้ดใน onDraw และตรวจสอบปัจจัยขนาดความกว้างและความสูง):

@Override
protected void onDraw(Canvas canvas) {

    Matrix matrix = getImageMatrix();

    float scaleFactorWidth = getWidth() / (float) getDrawable().getIntrinsicWidth();
    float scaleFactorHeight = getHeight() / (float) getDrawable().getIntrinsicHeight();

    float scaleFactor = (scaleFactorWidth > scaleFactorHeight) ? scaleFactorWidth : scaleFactorHeight;

    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);

    super.onDraw(canvas);
}

-1

วิธีแก้ไขที่ง่ายที่สุด: ตัดภาพ

 @Override
    public void draw(Canvas canvas) {
        if(getWidth() > 0){
            int clipHeight = 250;
            canvas.clipRect(0,clipHeight,getWidth(),getHeight());
         }
        super.draw(canvas);
    }

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