วิธีปรับขนาดมุมมอง Android ตามขนาดของผู้ปกครอง


104

ฉันจะปรับขนาดมุมมองตามขนาดของเค้าโครงระดับบนสุดได้อย่างไร ตัวอย่างเช่นฉันมีไฟล์RelativeLayoutที่แสดงเต็มหน้าจอและฉันต้องการมุมมองเด็กพูดว่าImageViewต้องใช้ความสูงทั้งหมดและความกว้าง 1/2?

ฉันได้พยายามเอาชนะทั้งหมดบนonMeasure, onLayout, onSizeChangedฯลฯ และฉันไม่สามารถได้รับมันในการทำงาน ....


เป็นไปได้ที่จะทำโดยใช้ ConstraintLayout ให้ตรวจสอบสิ่งนี้: stackoverflow.com/questions/37318228/…
Ali Nem

คำตอบ:


124

ฉันไม่รู้ว่ายังมีใครอ่านกระทู้นี้อยู่หรือเปล่า แต่วิธีแก้ปัญหาของเจฟฟ์จะทำให้คุณไปถึงที่นั่นได้แค่ครึ่งเดียว (ตามตัวอักษร) สิ่งที่ onMeasure ของเขาจะทำคือแสดงภาพครึ่งหนึ่งในครึ่งแม่ ปัญหาคือการเรียก super.onMeasure ก่อนที่setMeasuredDimensionจะวัดเด็กทั้งหมดในมุมมองตามขนาดดั้งเดิมจากนั้นเพียงแค่ตัดมุมมองลงครึ่งหนึ่งเมื่อsetMeasuredDimensionปรับขนาด

แต่คุณจำเป็นต้องโทรsetMeasuredDimension(เท่าที่จำเป็นสำหรับการแทนที่ onMeasure) และให้ใหม่LayoutParamsสำหรับมุมมองของคุณแล้วsuper.onMeasureโทร จำไว้ว่าคุณLayoutParamsได้มาจากประเภทหลักของมุมมองของคุณไม่ใช่ประเภทของมุมมองของคุณ

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
   int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
   int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
   this.setMeasuredDimension(parentWidth/2, parentHeight);
   this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

ฉันเชื่อว่าครั้งเดียวที่คุณจะมีปัญหากับผู้ปกครองLayoutParamsคือถ้าผู้ปกครองเป็นAbsoluteLayout(ซึ่งเลิกใช้งานแล้ว แต่บางครั้งก็ยังมีประโยชน์)


12
จากประสบการณ์ของฉันสิ่งนี้ไม่ค่อยได้ผลโดยเฉพาะ เมื่อเติม / match_parent หรือ weights ดีกว่าเรียกใช้ measureChildren หลังจาก setMeasuredDimension (ด้วยเช่น MeasureSpec.makeMeasureSpec (newWidth, MeasureSpec.AT_MOST))
M. Schenk

1
ไม่MeasureSpec.getSize(widthMeasureSpec)จริงๆให้ parent's ถูกต้องกว้าง? สำหรับฉันมันส่งกลับความกว้างแบบสุ่มซึ่งค่อนข้างใกล้เคียงกับความกว้างจริง แต่ไม่แน่นอน
Konsumierer

1
@ M.Schenk ได้เลย ฉันมี VideoView อยู่ในเลย์เอาต์แบบถ่วงน้ำหนัก ฉันต้องการความกว้างเป็นเปอร์เซ็นต์ของขนาดหน้าจอและฉันต้องรักษาอัตราส่วน นี่เป็นการยืดวิดีโอจึงwrap_contentไม่เกิดขึ้น คำตอบของ Vic ใช้ไม่ได้กับสถานการณ์นี้ แต่ความคิดเห็นของ @ M.Schenk ทำ นอกจากนี้ยังบันทึกบัตรผ่านแบบพิเศษ คุณควรโพสต์ไว้เป็นคำตอบสำหรับการมองเห็น
dokkaebi

7
การโทรจะไม่super.onMeasure()เพียงแค่ลบล้างและลบล้างผลกระทบของการโทรก่อนหน้านี้this.setMeasuredDimension()หรือไม่?
Spinner

1
ฉันก็อยากรู้เหมือนกันตามที่ @Spinner พูดถึงทำไมการโทรถึงsuper.onMeasure()ไม่แทนที่การคำนวณก่อนหน้านี้
jwir3

39

คุณสามารถแก้ปัญหานี้ได้โดยสร้างมุมมองแบบกำหนดเองและแทนที่เมธอด onMeasure () หากคุณใช้ "fill_parent" สำหรับ layout_width ใน xml ของคุณเสมอพารามิเตอร์ widthMeasureSpec ที่ถูกส่งไปยังเมธอด onMeasusre () ควรมีความกว้างของพาเรนต์

public class MyCustomView extends TextView {

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

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

        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        this.setMeasuredDimension(parentWidth / 2, parentHeight);
    }
}   

XML ของคุณจะมีลักษณะดังนี้:

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <view
        class="com.company.MyCustomView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2
@jeff => ทำไม parentWidth / 2 ??
Saeed-rz

6
@Leon_SFS: คำถามถามว่า "ความสูงทั้งหมดและความกว้าง 1/2"
EdgarT

28

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

สิ่งที่คุณสามารถทำได้คือแก้ไข measureSpecs แล้วโทรหา super กับพวกเขา มุมมองของคุณจะไม่มีทางรู้เลยว่าได้รับข้อความที่แก้ไขจากผู้ปกครองและจะดูแลทุกอย่างให้คุณ:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    int myWidth = (int) (parentHeight * 0.5);
    super.onMeasure(MeasureSpec.makeMeasureSpec(myWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}

16

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

   <LinearLayout android:layout_width="fill_parent"
                android:layout_height="fill_parent">
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
   </LinearLayout>

การให้สองสิ่งที่มีน้ำหนักเท่ากันหมายความว่าพวกมันจะยืดออกเพื่อรับสัดส่วนของหน้าจอ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเค้าโครงโปรดดูเอกสารการพัฒนา


ฉันไม่แนะนำสิ่งนี้ แต่ ... ในฐานะแฮ็กหากคุณใช้วิธีการข้างต้นคุณสามารถทำให้มุมมองเหล่านี้เป็น "หุ่นจำลอง" และตั้งค่า android: visibility = "มองไม่เห็น" ให้เต็มพื้นที่ครึ่งหนึ่ง
RickNotFred

จุดประสงค์ของการใช้พื้นที่เพียงครึ่งเดียวคืออะไร? คุณวางแผนที่จะแสดงอะไรในอีกครึ่งหนึ่งหรือไม่? สิ่งที่คุณทำกับพื้นที่ที่เหลือจะแจ้งแนวทางที่ดีที่สุด
RickNotFred

สิ่งนี้ควรเป็นอันดับ 1 อย่างแน่นอน - ถ้าคุณทำได้ใน xml ของคุณทำไมถึงทำใน java ของคุณ?
fandang

9

ฉันเชื่อว่าวิธี XML ของ Mayrasสามารถทำได้อย่างเรียบร้อย อย่างไรก็ตามเป็นไปได้ที่จะทำให้แม่นยำยิ่งขึ้นด้วยการดูเพียงครั้งเดียวโดยการตั้งค่า weightSum ฉันจะไม่เรียกสิ่งนี้ว่าแฮ็คอีกต่อไป แต่ในความคิดของฉันวิธีที่ตรงไปตรงมาที่สุด:

<LinearLayout android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:weightSum="1">
    <ImageView android:layout_height="fill_parent"
               android:layout_width="0dp"
               android:layout_weight="0.5"/>
</LinearLayout>

เช่นนี้คุณสามารถใช้น้ำหนักเท่าใดก็ได้ตัวอย่างเช่น 0.6 (และศูนย์กลาง) คือน้ำหนักที่ฉันชอบใช้สำหรับปุ่ม


3

ลองทำตามนี้

int parentWidth = ((parentViewType)childView.getParent()).getWidth();
int parentHeight = ((parentViewType)childView.getParent()).getHeight();

จากนั้นคุณสามารถใช้ LinearLayout.LayoutParams เพื่อตั้งค่าพารามิเตอร์ของ chileView

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(childWidth,childLength);
childView.setLayoutParams(params);

2

ตอนนี้คุณสามารถใช้ PercentRelativeLayout ตูม! แก้ไขปัญหา.


2
PercentRelativeLayout เลิกใช้งานแล้วในระดับ API 26.0.0-beta1
dzikovskyy

คุณหมายถึงอะไร "ในระดับ API"? คุณหมายถึงหมายเลขเวอร์ชันของไลบรารีหรือไม่? PRL อยู่ในไลบรารีการสนับสนุนไม่มีระดับ API
androidguy

ตามระดับ API ฉันหมายถึงเวอร์ชันของ Android ข้อมูลจากที่นี่developer.android.com/reference/android/support/percent/… . ข้อมูลเพิ่มเติมเกี่ยวกับระดับ API ที่นี่developer.android.com/guide/topics/manifest/…
dzikovskyy

คุณยังคงสามารถใช้คลาสนี้ได้เว้นแต่ด้วยเหตุผลบางประการที่คุณต้องการเวอร์ชัน 26.0.0 ขึ้นไป
androidguy

1

Roman หากคุณต้องการสร้างเลย์เอาต์ของคุณในโค้ด Java (ลูกหลานของ ViewGroup) ก็เป็นไปได้ เคล็ดลับคือคุณต้องใช้วิธีการทั้ง onMeasure และ onLayout onMeasure จะถูกเรียกก่อนและคุณต้อง "วัด" มุมมองย่อย (ปรับขนาดตามค่าที่ต้องการอย่างมีประสิทธิภาพ) ที่นั่น คุณต้องปรับขนาดอีกครั้งในการโทร onLayout หากคุณไม่ทำตามลำดับนี้หรือไม่สามารถเรียกใช้ setMeasuredDimension () ในตอนท้ายของโค้ด onMeasure คุณจะไม่ได้รับผลลัพธ์ เหตุใดสิ่งนี้จึงได้รับการออกแบบในลักษณะที่ซับซ้อนและเปราะบางเช่นนี้จึงเป็นเรื่องที่เกินตัวฉัน


1

ถ้าอีกด้านว่าง. ฉันเดาว่าวิธีที่ง่ายที่สุดคือการเพิ่มมุมมองที่ว่างเปล่า (เช่นเลย์เอาต์เชิงเส้น) จากนั้นตั้งค่าความกว้างของมุมมองทั้งสองเป็น Fill_parent และน้ำหนักทั้งสองเป็น 1

ใช้งานได้ใน LinearLayout ...


0

มันเป็นดังนี้:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.company.myapp.ActivityOrFragment"
    android:id="@+id/activity_or_fragment">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/linearLayoutFirst"
    android:weightSum="100">   <!-- Overall weights sum of children elements -->

    <Spinner
        android:layout_width="0dp"   <!-- It's 0dp because is determined by android:layout_weight -->
        android:layout_weight="50"
        android:layout_height="wrap_content"
        android:id="@+id/spinner" />

</LinearLayout>


<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:layout_below="@+id/linearLayoutFirst"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:id="@+id/linearLayoutSecond">

    <EditText
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="75"
        android:inputType="numberDecimal"
        android:id="@+id/input" />

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="25"
        android:id="@+id/result"/>

</LinearLayout>
</RelativeLayout>

-1

ฉันต่อสู้กับคำถามนี้มานานแล้วฉันต้องการเปลี่ยนความกว้างลิ้นชักของ DrawerLayout ซึ่งเป็นลูกคนที่สองของผู้ปกครอง เมื่อเร็ว ๆ นี้ฉันคิดออก แต่ไม่รู้ว่ามีความคิดที่ดีกว่านี้ไหม

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    super.onLayout(changed, l, t, r, b)
    (getChildAt(1).layoutParams as LayoutParams).width = measuredWidth/2
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.