ImageView - มีความกว้างของการจับคู่ความสูงหรือไม่


166

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

<ImageView
  android:layout_width="fill_parent"
  android:layout_height="whatever the width ends up being" />

เป็นสิ่งที่เป็นไปได้ในไฟล์เลย์เอาต์โดยไม่ต้องสร้างคลาสมุมมองของตัวเองหรือไม่?

ขอบคุณ


คุณเข้าใจวิธีการทำเช่นนี้? ฉันสมมติว่าคุณต้องการให้อัตราส่วนภาพคงเดิม คำตอบส่วนใหญ่ถือว่าคุณต้องการให้ภาพเป็นสี่เหลี่ยมจัตุรัส
อดัม

@ Joe Blow นั่นเป็นวิธีที่แย่มากที่จะทำ
Aggressor

คำตอบ:


170

ปรับปรุง: 14 ก.ย. 2560

ตามความเห็นด้านล่างไลบรารีสนับสนุนเปอร์เซ็นต์จะถูกคัดค้าน ณ Android Support Library 26.0.0 นี่เป็นวิธีใหม่ในการทำ:

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

</android.support.constraint.ConstraintLayout>

ดูที่นี่

เลิกใช้:

ตามโพสต์นี้โดยนักพัฒนา Android สิ่งที่คุณต้องทำตอนนี้คือห่อสิ่งที่คุณต้องการภายใน PercentRelativeLayout หรือ PercentFrameLayout แล้วระบุอัตราส่วนเช่นนั้น

<android.support.percent.PercentRelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        app:layout_widthPercent="100%"
        app:layout_aspectRatio="100%"/>

</android.support.percent.PercentRelativeLayout>

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

ฉันเป็นกรณีของฉันการแก้ปัญหาเช่นนี้ไม่ได้ผลอันนี้ทำได้!
Gooey

5
อย่าลืมที่จะเพิ่ม 'คอมไพล์ com.android.support:percent:23.3.0' ในการพึ่งพาของคุณ
Milad Faridnia

ดูเหมือนว่าวิธีการนี้จะมีปัญหากับ WrappedViewPager ซึ่งคำนวณความสูงตามเนื้อหาลูก ๆ แหล่งที่มาสำหรับ WrappedViewPager คล้ายกับgist.github.com/egslava/589b82a6add9c816a007
หม่า

1
โมดูลสนับสนุนเปอร์เซ็นต์เลิกใช้แล้วเลิกใช้แล้วเนื่องจากไลบรารีสนับสนุน android 26.0.0 ที่มา: developer.android.com/topic/l
ไลบรารี/support

97

อาจจะตอบคำถามของคุณ:

<ImageView
    android:id="@+id/cover_image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true" />

คุณสามารถละเว้นscaleTypeแอตทริบิวต์สำหรับสถานการณ์เฉพาะนี้


12
ใช่แล้วมันไร้ประโยชน์
Fattie

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

3
แก้ไขปัญหาของฉันด้วย
ฝ่ายขาย Dielson

วิธีที่ง่ายที่สุด! ควรทำเครื่องหมายเป็นคำตอบที่ดีที่สุด
H. Farid

30

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

ตัวอย่างของวิธีที่ฉันแก้ไขปัญหาของฉัน:

final FrameLayout mFrame = (FrameLayout) findViewById(R.id.frame_id);

    mFrame.post(new Runnable() {

        @Override
        public void run() {
            RelativeLayout.LayoutParams mParams;
            mParams = (RelativeLayout.LayoutParams) mFrame.getLayoutParams();
            mParams.height = mFrame.getWidth();
            mFrame.setLayoutParams(mParams);
            mFrame.postInvalidate();
        }
    });

LayoutParams จะต้องเป็นประเภทของมุมมองหลักที่มุมมองของคุณอยู่ FrameLayout ของฉันอยู่ใน RelativeLayout ในไฟล์ xml

    mFrame.postInvalidate();

ถูกเรียกให้บังคับให้มุมมองวาดใหม่ในขณะที่อยู่ในเธรดแยกต่างหากกว่าเธรด UI


4
คำตอบที่ยอดเยี่ยมโดยเฉพาะอย่างยิ่งกับ Runnable ขอบคุณ!
jesses.co.tt

1
ในขณะที่ใช้งานได้มันไม่เหมาะ การลงรายการบัญชีหมายถึงมุมมองแสดงผลหนึ่งครั้งก่อนการเปลี่ยนแปลงโครงร่าง อาจอนุญาตให้มีเนื้อหาที่ระดับความสูงไม่ถูกต้องก่อนที่จะวาดอย่างถูกต้อง ดีกว่าที่จะแก้ปัญหาก่อนหน้านี้ ช่วงเวลาที่เร็วที่สุดที่จะแก้เป็นช่วงที่กำหนดเองonMeasureตามที่แสดงในคำตอบ Regis' ทางเลือก แต่สำหรับมุมมองการแสดงผลผ่านอะแดปเตอร์เช่นภายในGridViewเป็นคำตอบของแมตต์
ToolmakerSteve

1
มันทำงานได้ดีสำหรับฉันหลังจากโทรrequestLayout()หลังจากตั้งค่าพารามิเตอร์แล้ว ทำไมถึงเป็นเช่นนั้น?
Divew Mathew

mFrame.postInvalidate (); เป็นสิ่งที่ทำโดยไม่มีฉันได้รับมุมมองจากตำแหน่ง
Jacolack

17

ฉันไม่สามารถรับคำตอบของ David Chuเพื่อทำงานกับรายการ RecyclerView และคิดว่าฉันจำเป็นต้อง จำกัด ImageView ให้กับผู้ปกครอง ตั้งค่าความกว้างของ ImageView เป็น0dpและ จำกัด การเริ่มต้นและสิ้นสุดเป็นพาเรนต์ ฉันไม่แน่ใจว่าการตั้งค่าความกว้างเป็นwrap_contentหรือใช้match_parentงานได้ในบางกรณี แต่ฉันคิดว่านี่เป็นวิธีที่ดีกว่าในการทำให้ลูกของ ConstraintLayout เติมผู้ปกครอง

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="1:1"/>

</android.support.constraint.ConstraintLayout>

13

ที่นี่ฉันทำสิ่งที่ฉันมี ImageButton ซึ่งมักจะมีความกว้างเท่ากับความสูงของมัน (และหลีกเลี่ยงขอบว่างเปล่าที่โง่ในทิศทางเดียว ... ซึ่งฉันคิดว่าเป็นข้อบกพร่องของ SDK ... ):

ฉันกำหนดคลาส SquareImageButton ซึ่งขยายจาก ImageButton:

package com.myproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;

    public class SquareImageButton extends ImageButton {

        public SquareImageButton(Context context) {
        super(context);


        // TODO Auto-generated constructor stub
    }

    public SquareImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

    }

    public SquareImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    int squareDim = 1000000000;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        int h = this.getMeasuredHeight();
        int w = this.getMeasuredWidth();
        int curSquareDim = Math.min(w, h);
        // Inside a viewholder or other grid element,
        // with dynamically added content that is not in the XML,
        // height may be 0.
        // In that case, use the other dimension.
        if (curSquareDim == 0)
            curSquareDim = Math.max(w, h);

        if(curSquareDim < squareDim)
        {
            squareDim = curSquareDim;
        }

        Log.d("MyApp", "h "+h+"w "+w+"squareDim "+squareDim);


        setMeasuredDimension(squareDim, squareDim);

    }

}

นี่คือ xml ของฉัน:

<com.myproject.SquareImageButton
            android:id="@+id/speakButton"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerInside"
            android:src="@drawable/icon_rounded_no_shadow_144px"
            android:background="#00ff00"
            android:layout_alignTop="@+id/searchEditText"
            android:layout_alignBottom="@+id/searchEditText"
            android:layout_alignParentLeft="true"
           />

ทำงานเหมือนจับใจ!


ใช่นั่นคือคำตอบที่ดีที่สุด (และเป็นคนเดียวที่ตรงกับคำถาม
OPs

6

ใน Android 26.0.0 PercentRelativeLayout ได้เลิก

วิธีที่ดีที่สุดในการแก้ปัญหาคือตอนนี้ด้วยConstraintLayoutสิ่งนี้:

<android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

    <ImageView android:layout_width="match_parent"
               android:layout_height="0dp"
               android:scaleType="centerCrop"
               android:src="@drawable/you_image"                       
               app:layout_constraintDimensionRatio="1:1"/>


</android.support.constraint.ConstraintLayout>


นี่คือการสอนเกี่ยวกับวิธีเพิ่มลงConstraintLayoutในโครงการของคุณ


6

หากมุมมองภาพของคุณอยู่ในเค้าโครงข้อ จำกัด คุณสามารถใช้ข้อ จำกัด ต่อไปนี้เพื่อสร้างมุมมองภาพสี่เหลี่ยม

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:id="@+id/ivImageView"
    app:layout_constraintDimensionRatio="W,1:1"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

5

คุณไม่สามารถทำได้ด้วยเค้าโครงเพียงอย่างเดียวฉันได้ลองแล้ว ฉันลงเอยด้วยการเขียนคลาสที่ง่ายมากที่จะจัดการกับมันคุณสามารถตรวจสอบได้บน GitHub SquareImage.javaเป็นส่วนหนึ่งของโครงการขนาดใหญ่ แต่ไม่มีอะไรที่คัดลอกและวางเล็กน้อยไม่สามารถแก้ไขได้ (ได้รับอนุญาตภายใต้ Apache 2.0)

โดยพื้นฐานแล้วคุณเพียงแค่ตั้งค่าความสูง / ความกว้างเท่ากับมิติอื่น ๆ (ขึ้นอยู่กับวิธีที่คุณต้องการปรับขนาด)

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


3

ในการตั้งค่า ImageView เท่ากับครึ่งหน้าจอคุณต้องเพิ่มสิ่งต่อไปนี้ลงใน XML ของคุณสำหรับ ImageView:

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

หากต้องการตั้งค่าความสูงเท่ากับความกว้างนี้คุณต้องทำในรหัส ในgetViewวิธีการของGridViewอะแดปเตอร์ของคุณตั้งค่าImageViewความสูงเท่ากับความกว้างที่วัดได้:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();

3

สำหรับผู้ที่ผ่านไปแล้วในปี 2560 วิธีที่ดีที่สุดในการบรรลุสิ่งที่คุณต้องการคือการใช้ConstraintLayoutดังนี้:

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:layout_constraintDimensionRatio="1:1" />

และอย่าลืมเพิ่มข้อ จำกัด ของทั้งสี่ทิศทางตามที่คุณต้องการ

สร้าง UI ที่ตอบสนองต่อด้วย ConstraintLayout

นอกจากนี้ตอนนี้ PercentRelativeLayout เลิกใช้แล้ว (ดูเอกสารประกอบ Android )


1

นี่คือวิธีที่ฉันแก้ไขปัญหา:

int pHeight =  picture.getHeight();
int pWidth = picture.getWidth();
int vWidth = preview.getWidth();
preview.getLayoutParams().height = (int)(vWidth*((double)pHeight/pWidth));

ดูตัวอย่าง - imageView พร้อมความกว้างกำหนดเป็น "match_parent" และ scaleType เป็น "ครอบตัดศูนย์"

รูปภาพ - วัตถุบิตแมปที่จะตั้งค่าใน imageView src

มันใช้งานได้ดีสำหรับฉัน


คุณยังไม่ได้อธิบายว่าต้องใส่รหัสนี้ที่ไหน นอกจากนี้คุณยังไม่ได้อธิบายว่าทำไมคุณทำแทนของง่าย= vw*ph/pw = vw(ฉันคิดว่าคุณทำเช่นนี้เพื่อรักษาอัตราส่วนภาพต้นฉบับแทนที่จะบังคับให้แสดงตัวอย่างภาพสี่เหลี่ยม)
ToolmakerSteve

0

ฉันไม่คิดว่าจะมีวิธีใดที่คุณสามารถทำได้ในรูปแบบไฟล์ XML และฉันไม่คิดว่าandroid:scaleTypeคุณลักษณะจะทำงานได้ตามที่คุณต้องการ
วิธีเดียวที่จะทำได้โดยทางโปรแกรม คุณสามารถตั้งค่าความกว้างเพื่อ fill_parent และทั้งสามารถใช้ความกว้างหน้าจอความสูงของViewหรือสามารถใช้View.getWidth()วิธีการ


0

ฟังก์ชัน ImageView "scaleType" อาจช่วยคุณได้ที่นี่

รหัสนี้จะรักษาอัตราส่วนภาพและจัดตำแหน่งภาพที่ด้านบน:

android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitStart"

นี่คือโพสต์ที่ยอดเยี่ยมที่แสดงถึงความเป็นไปได้และลักษณะที่ปรากฏจากการใช้ scaleType

ตัวอย่าง ImageView สเกลประเภท


"scaleType" ไม่ได้ช่วยที่นี่ เป้าหมายคือการให้ ImageView ตัวเองเป็นรูปสี่เหลี่ยมจัตุรัสไม่ใช่เฉพาะภาพที่อยู่ภายใน ด้วย scaleType, ImageView อาจมีขนาดใหญ่กว่าภาพ
ToolmakerSteve

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