Android: ปรับขนาดภาพวาดหรือพื้นหลัง?


134

ในเค้าโครงฉันต้องการปรับขนาดภาพพื้นหลัง (รักษาอัตราส่วนภาพ) ให้เท่ากับพื้นที่ที่จัดสรรเมื่อสร้างเพจ ใครมีความคิดในการทำเช่นนี้?

ฉันใช้layout.setBackgroundDrawable()และBitmapDrawable()ตั้งค่าgravityสำหรับการตัดและการเติม แต่ไม่เห็นตัวเลือกใด ๆ สำหรับการปรับขนาด


ฉันมีปัญหานี้และทำตามคำแนะนำของ Dweebo ด้วยการเปลี่ยนแปลงที่ Anke แนะนำ: เปลี่ยน fitXY เป็น fitCenter ทำงานได้ดี

คำตอบ:


90

ในการปรับแต่งการปรับขนาดภาพพื้นหลังให้สร้างทรัพยากรดังนี้:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:gravity="center"
    android:src="@drawable/list_bkgnd" />

จากนั้นจะอยู่ตรงกลางมุมมองหากใช้เป็นพื้นหลัง นอกจากนี้ยังมีแฟล็กอื่น ๆ : http://developer.android.com/guide/topics/resources/drawable-resource.html


6
ฉันลองใช้บิตแมป แต่รูปภาพอยู่ตรงกลางไม่ได้ปรับขนาดตามที่แซมถาม เมื่อฉันใช้ ImageView มันทำงานได้อย่างสวยงามไม่มีความยุ่งยาก / ยุ่งยาก (nb: ฉันไม่ได้เลื่อนในกรณีของฉันด้วย) ฉันจะเพิ่มบิตแมปด้วยอะไรเพื่อปรับขนาดภาพ
Joe D'Andrea

7
ค่าที่เป็นไปได้คือ: "top" | "ด้านล่าง" | "ซ้าย" | "ถูกต้อง" | "center_vertical" | "fill_vertical" | "center_horizontal" | "fill_horizontal" | "ศูนย์" | "เติม" | "clip_vertical" | "clip_horizontal"
Aleks N.

30
ไม่มีพารามิเตอร์ใดที่ปรับขนาดบิตแมปได้โดยคงไว้ซึ่งอัตราส่วนกว้างยาวดังนั้นคำตอบจึงผิด
Malachiasz

7
เรียน Malachiasz 'center' เคารพอัตราส่วนภาพ แต่จะไม่ลดขนาดภาพลง ซึ่งหมายความว่าเป็นคุณลักษณะที่ค่อนข้างอันตรายในการใช้งาน ขึ้นอยู่กับความละเอียดของเป้าหมายคุณไม่มีทางรู้ว่าสิ่งที่ปรับขนาดจะออกมาเป็นอย่างไร อีกหนึ่งวิธีแก้ปัญหาโดย Google

2
มีวิธีเพิ่มแอตทริบิวต์ scaleType หรือไม่?
ademar111190

57

ยังไม่ได้พยายามทำสิ่งที่คุณต้องการ แต่คุณสามารถปรับขนาด ImageView โดยใช้android:scaleType="fitXY"
และจะมีขนาดพอดีกับขนาดที่คุณให้ ImageView

ดังนั้นคุณสามารถสร้าง FrameLayout สำหรับเลย์เอาต์ของคุณใส่ ImageView ไว้ข้างในจากนั้นเนื้อหาอื่น ๆ ที่คุณต้องการใน FrameLayout รวมทั้งพื้นหลังโปร่งใส

<FrameLayout  
android:layout_width="fill_parent" android:layout_height="fill_parent">

  <ImageView 
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:src="@drawable/back" android:scaleType="fitXY" />

  <LinearLayout>your views</LinearLayout>
</FrameLayout>

1
เป็นไปได้ไหมที่จะทำสิ่งนี้บนพื้นผิว ถ้าไม่ฉันสามารถแสดงตัวอย่าง (สำหรับแอปเครื่องบันทึก) โดยใช้ FrameLayout ได้หรือไม่
น้ำรฐา

1
@dweebo: ลองแล้วหรือยัง? ดูเหมือนจะไม่ได้ผลสำหรับฉัน
เครื่องบินเร็ว

3
ลดลงเนื่องจากใช้องค์ประกอบ UI สองรายการแทนที่จะเป็นหนึ่งเป็นความคิดที่ไม่ดีโดยเฉพาะอย่างยิ่งสำหรับส่วนประกอบที่ยุ่งเช่น ListView เป็นไปได้มากว่าคุณจะประสบปัญหาขณะเลื่อน วิธีแก้ปัญหาที่เหมาะสม: stackoverflow.com/a/9362168/145046
Aleks N.

ฉันลองใช้ scaleType ของ fitCenter และ centerCrop (พร้อมกับรูปแบบที่วาดได้ / ภาพบางรูปแบบสำหรับความหนาแน่นที่แตกต่างกัน) และใช้งานได้! ประเภทสเกลทั้งสองแบบเหมาะสำหรับฉัน - ฉันสงสัยว่าเป็นความชอบส่วนตัวตามภาพมากกว่า โปรดทราบว่าฉันใช้การผสานแทน FrameLayout และไม่มีการเลื่อนในกรณีเฉพาะของฉัน
Joe D'Andrea

2
centerInside เหมาะสมไม่ใช่ fitXY เนื่องจาก fitXY ไม่รักษาอัตราส่วนของภาพ
Malachiasz

35

มีวิธีง่ายๆในการทำสิ่งนี้จากสิ่งที่วาดได้:

your_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@color/bg_color"/>
    <item>
        <bitmap
            android:gravity="center|bottom|clip_vertical"
            android:src="@drawable/your_image" />
    </item>

</layer-list>

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

อีกวิธีหนึ่งที่จะเป็นเพียงแค่การสร้างรูปแบบที่คุณจะใช้ImageViewและการตั้งค่าไปscaleTypefitCenter


2
โซลูชันนี้เป็นสิ่งที่ฉันมองหามานานเพื่อแทนที่คุณสมบัติพื้นหลังของธีมของฉันและหลีกเลี่ยงการปรับขนาดภาพที่แตกต่างกันเมื่อมุมมองมีแท็บหรือไม่ ขอบคุณสำหรับการแบ่งปันสิ่งนี้
Bibu

1
มันแสดงข้อผิดพลาด:error: <item> must have a 'name' attribute.
Dmitry

ขอบคุณ @lonutNegru, +1 สำหรับการบันทึกวันของฉัน :)
Ravi Vaniya

18

เพื่อรักษาอัตราส่วนที่คุณต้องใช้android:scaleType=fitCenterหรือfitStartอื่น ๆ การใช้fitXYจะไม่คงอัตราส่วนเดิมของภาพไว้!

หมายเหตุสิ่งนี้ใช้ได้เฉพาะกับรูปภาพที่มีsrcแอตทริบิวต์เท่านั้นไม่ใช่สำหรับภาพพื้นหลัง


18

ใช้ภาพเป็นขนาดพื้นหลังในการจัดวาง:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/imgPlaylistItemBg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true"
        android:maxHeight="0dp"
        android:scaleType="fitXY"
        android:src="@drawable/img_dsh" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >


    </LinearLayout>

</FrameLayout>

ขอบคุณ! ยังใช้android:scaleType="centerCrop"งานได้
CoolMind

5

เมื่อคุณตั้งค่า Drawable ของ ImageView โดยใช้setBackgroundDrawableวิธีนี้ภาพจะถูกปรับขนาดเสมอ พารามิเตอร์ที่เป็นadjustViewBoundsหรือต่างกันScaleTypesจะถูกละเว้น ทางออกเดียวที่จะรักษาอัตราส่วนภาพที่ฉันพบคือการปรับขนาดImageViewหลังจากโหลดที่ดึงได้ นี่คือข้อมูลโค้ดที่ฉันใช้:

// bmp is your Bitmap object
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
int containerHeight = imageView.getHeight();
int containerWidth = imageView.getWidth();
boolean ch2cw = containerHeight > containerWidth;
float h2w = (float) imgHeight / (float) imgWidth;
float newContainerHeight, newContainerWidth;

if (h2w > 1) {
    // height is greater than width
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth * h2w;
    } else {
        newContainerHeight = (float) containerHeight;
        newContainerWidth = newContainerHeight / h2w;
    }
} else {
    // width is greater than height
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth / h2w; 
    } else {
        newContainerWidth = (float) containerHeight;
        newContainerHeight = newContainerWidth * h2w;       
    }
}
Bitmap copy = Bitmap.createScaledBitmap(bmp, (int) newContainerWidth, (int) newContainerHeight, false);
imageView.setBackgroundDrawable(new BitmapDrawable(copy));
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageView.setLayoutParams(params);
imageView.setMaxHeight((int) newContainerHeight);
imageView.setMaxWidth((int) newContainerWidth);

ในส่วนโค้ดด้านบนคือbmpอ็อบเจ็กต์ Bitmap ที่จะแสดงและimageViewคือImageViewอ็อบเจ็กต์

สิ่งสำคัญที่ควรทราบก็คือการเปลี่ยนแปลงของพารามิเตอร์รูปแบบที่ นี่เป็นสิ่งที่จำเป็นเพราะsetMaxHeightและsetMaxWidthจะสร้างความแตกต่างก็ต่อเมื่อมีการกำหนดความกว้างและความสูงเพื่อห่อเนื้อหาไม่ใช่เพื่อเติมเต็มแม่บท ในทางกลับกัน Fill parent คือการตั้งค่าที่ต้องการในตอนเริ่มต้นเพราะไม่เช่นนั้นcontainerWidthและcontainerHeightทั้งสองจะมีค่าเท่ากับ 0 ดังนั้นในไฟล์เลย์เอาต์ของคุณคุณจะมีสิ่งนี้สำหรับ ImageView ของคุณ:

...
<ImageView android:id="@+id/my_image_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
...

4

นี่ไม่ใช่วิธีแก้ปัญหาที่มีประสิทธิภาพมากที่สุด แต่เนื่องจากมีคนแนะนำแทนที่จะเป็นพื้นหลังคุณสามารถสร้าง FrameLayout หรือ RelativeLayout และใช้ ImageView เป็นพื้นหลังหลอก - องค์ประกอบอื่น ๆ จะอยู่ในตำแหน่งเหนือมัน:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <ImageView
        android:id="@+id/ivBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:scaleType="fitStart"
        android:src="@drawable/menu_icon_exit" />

    <Button
        android:id="@+id/bSomeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="61dp"
        android:layout_marginTop="122dp"
        android:text="Button" />

</RelativeLayout>

ปัญหาเกี่ยวกับ ImageView คือมีเฉพาะ scaleTypes เท่านั้น: CENTER, CENTER_CROP, CENTER_INSIDE, FIT_CENTER, FIT_END, FIT_START, FIT_XY, MATRIX ( http://etcodehome.blogspot.de/2011/05/android-imageview-scaletype-samples.html )

และในการ "ปรับขนาดภาพพื้นหลัง (รักษาอัตราส่วนภาพ)" ในบางกรณีเมื่อคุณต้องการให้ภาพเต็มทั้งหน้าจอ (เช่นภาพพื้นหลัง) และอัตราส่วนของหน้าจอแตกต่างจากภาพขนาดมาตราส่วนที่จำเป็นจะเป็นชนิด ของ TOP_CROP เนื่องจาก:

CENTER_CROP จัดกึ่งกลางภาพที่ปรับขนาดแทนที่จะจัดแนวขอบด้านบนให้ชิดขอบด้านบนของมุมมองภาพและ FIT_START พอดีกับความสูงของหน้าจอและไม่เต็มความกว้าง และตามที่ผู้ใช้ Anke สังเกตว่า FIT_XY ไม่รักษาอัตราส่วน

ดีใจที่มีคนขยาย ImageView เพื่อรองรับ TOP_CROP

public class ImageViewScaleTypeTopCrop extends ImageView {
    public ImageViewScaleTypeTopCrop(Context context) {
        super(context);
        setup();
    }

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

    public ImageViewScaleTypeTopCrop(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) {

        float frameWidth = frameRight - frameLeft;
        float frameHeight = frameBottom - frameTop;

        if (getDrawable() != null) {

            Matrix matrix = getImageMatrix();
            float scaleFactor, scaleFactorWidth, scaleFactorHeight;

            scaleFactorWidth = (float) frameWidth / (float) getDrawable().getIntrinsicWidth();
            scaleFactorHeight = (float) frameHeight / (float) getDrawable().getIntrinsicHeight();

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

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

        return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
    }

}

https://stackoverflow.com/a/14815588/2075875

ตอนนี้ IMHO จะสมบูรณ์แบบถ้ามีคนเขียน Drawable แบบกำหนดเองซึ่งจะปรับขนาดภาพเช่นนั้น จากนั้นสามารถใช้เป็นพารามิเตอร์พื้นหลัง


Reflog แนะนำให้วาดล่วงหน้าก่อนใช้งาน นี่คือคำแนะนำวิธีการทำ: Java (Android): วิธีการปรับขนาดที่วาดได้โดยไม่ต้องใช้ Bitmap แม้ว่าจะมีข้อเสีย แต่การขยายขนาด / บิตแมปที่ปรับขนาดได้จะใช้ RAM มากขึ้นในขณะที่การปรับขนาดได้ทันทีที่ใช้โดย ImageView ไม่ต้องการหน่วยความจำเพิ่มเติม ข้อได้เปรียบอาจเป็นภาระของโปรเซสเซอร์น้อยลง


ทำได้ดีนี่! ทำตามสิ่งที่ฉันเป็น: ภาพพื้นหลังเพื่อเติมเต็มหน้าจอโดยการเพิ่มความกว้างตามสัดส่วนและครอบตัดด้านล่างของรูปภาพ
CMash

4

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

int bwidth=bitMap1.getWidth();
int bheight=bitMap1.getHeight();
int swidth=imageView_location.getWidth();
int sheight=imageView_location.getHeight();
new_width=swidth;
new_height = (int) Math.floor((double) bheight *( (double) new_width / (double) bwidth));
Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap1,new_width,new_height, true);
imageView_location.setImageBitmap(newbitMap)

2

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

 < RelativeLayout 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/black">

    <LinearLayout
        android:layout_width="500dip"
        android:layout_height="450dip"
        android:layout_centerInParent="true"
        android:background="@drawable/my_drawable"
        android:orientation="vertical"
        android:padding="30dip"
        >
        ...
     </LinearLayout>
 < / RelativeLayout>

2
ความเข้าใจของฉันคือพื้นหลังจะขยายเพื่อเติมเต็มมุมมอง แต่ไม่หดตัว
Edward Falk

1

ทางเลือกหนึ่งที่ควรลองคือใส่รูปภาพในdrawable-nodpiโฟลเดอร์และตั้งค่าพื้นหลังของเค้าโครงเป็นรหัสทรัพยากรที่วาดได้

สิ่งนี้ใช้ได้ผลกับการลดขนาดอย่างแน่นอนฉันยังไม่ได้ทดสอบด้วยการขยายขนาด


0

Kotlin:

หากคุณต้องการวาดบิตแมปในมุมมองให้ปรับขนาดเป็น FIT

คุณสามารถทำการคำนวณที่เหมาะสมเพื่อกำหนด bm ให้มีความสูงเท่ากับคอนเทนเนอร์และปรับความกว้างในกรณีที่อัตราส่วนความกว้าง bm ต่อความสูงน้อยกว่าอัตราส่วนความกว้างของคอนเทนเนอร์ต่อความสูงหรือการผกผันในสถานการณ์ตรงกันข้าม

รูปภาพ:

ภาพตัวอย่าง 1

ภาพตัวอย่าง 2

// binding.fragPhotoEditDrawCont is the RelativeLayout where is your view
// bm is the Bitmap
val ch = binding.fragPhotoEditDrawCont.height
val cw = binding.fragPhotoEditDrawCont.width
val bh = bm.height
val bw = bm.width
val rc = cw.toFloat() / ch.toFloat()
val rb = bw.toFloat() / bh.toFloat()

if (rb < rc) {
    // Bitmap Width to Height ratio is less than Container ratio
    // Means, bitmap should pin top and bottom, and have some space on sides.
    //              _____          ___
    // container = |_____|   bm = |___| 
    val bmHeight = ch - 4 //4 for container border
    val bmWidth = rb * bmHeight //new width is bm_ratio * bm_height
    binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth.toInt(), bmHeight)
}
else {
    val bmWidth = cw - 4 //4 for container border
    val bmHeight = 1f/rb * cw
    binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth, bmHeight.toInt())
}

-4

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


นี่เป็นทางเลือกเดียวจริงๆหรือ? ไม่มีคอนเทนเนอร์ประเภทใดที่จะวาง ImageView ซึ่งสามารถระบุขนาดการแสดงผลได้?
GrkEngineer

ฉันกำลังมีปัญหากับ SurfaceView
AZ_

3
ไม่มีอะไรที่เหมือนกับความพอดีด้านซ้ายด้านบนและด้านบนเช่นบน iOS? ที่ห่วย ..
Maciej Swic

ดังที่ @Aleksej กล่าวคำตอบที่ไม่เป็นความจริง
ผู้เรียน

-5

คุณสามารถใช้สิ่งใดสิ่งหนึ่งต่อไปนี้:

หุ่นยนต์: แรงโน้มถ่วง = "fill_horizontal | clip_vertical"

หรือ

หุ่นยนต์: แรงโน้มถ่วง = "fill_vertical | clip_horizontal"

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