วิธีการตั้งค่าความกว้างและความสูงของ DialogFragment


173

ฉันระบุรูปแบบของ DialogFragment ของฉันในไฟล์รูปแบบ XML (ขอเรียกว่าlayout_mydialogfragment.xml) และlayout_widthและlayout_heightคุณลักษณะเฉพาะอย่างยิ่ง (จะ100dpแต่ละสมมติ) ฉันขยายรูปแบบนี้ในonCreateView(...)วิธีการDialogFragment ของฉันดังนี้

View view = inflater.inflate(R.layout.layout_mydialogfragment, container, false);

น่าเสียดายที่ฉันพบว่าเมื่อไดอะล็อกของฉัน (DialogFragment) ปรากฏขึ้นจะไม่เคารพlayout_widthและlayout_heightระบุในไฟล์เลย์เอาต์ xml (และไดอะล็อกของฉันจะย่อเล็กลงหรือขยายได้ขึ้นอยู่กับเนื้อหา) ใครรู้หรือไม่ว่าฉันจะได้รับกล่องโต้ตอบของฉันที่จะเคารพlayout_widthและlayout_heightระบุไว้ในไฟล์รูปแบบของ XML? ในขณะนี้ฉันต้องระบุความกว้างและความสูงของกล่องโต้ตอบอีกครั้งในonResume()วิธีการDialogFragment ของฉันดังนี้ ...

getDialog().getWindow().setLayout(width, height);

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


2
พิจารณาการยอมรับคำตอบของ jpmcosta มันไม่ใช่แฮ็คและมันแก้ปัญหาได้จริง
Bogdan Zurac

คำตอบ:


168

หากคุณแปลงโดยตรงจากค่าทรัพยากร:

int width = getResources().getDimensionPixelSize(R.dimen.popup_width);
int height = getResources().getDimensionPixelSize(R.dimen.popup_height);        
getDialog().getWindow().setLayout(width, height);

จากนั้นระบุ match_parent ในรูปแบบของคุณสำหรับกล่องโต้ตอบ:

android:layout_width="match_parent"
android:layout_height="match_parent"

คุณต้องกังวลเกี่ยวกับสถานที่แห่งเดียว (วางไว้ในของคุณDialogFragment#onResume) มันไม่สมบูรณ์แบบ แต่อย่างน้อยก็ใช้งานได้กับ RelativeLayout ในฐานะรูทของไฟล์เลย์เอาต์ของกล่องโต้ตอบ


3
คำตอบนี้ไม่ทำงานในกรณีของฉัน (สำหรับ DialogFragment) ฉันต้องใช้ FragmentLayout params เพื่อเปลี่ยนขนาดการแสดงหน้าต่าง
Rusfearuth

3
ฉันต้องห่อเค้าโครงของฉันRelativeLayoutและมันช่วยฉัน ขอบคุณมากสำหรับการแก้ปัญหา - ช่วยฉันได้มากเวลา
Johnny Doe

62
นี้ทำงานได้ดีสำหรับฉัน (Android 4.0 ขึ้นไป) เมื่อฉันตระหนักในเรื่องนี้จะต้องอยู่ในไม่onResume() onCreateView()(เลย์เอาต์รากของฉันคือ RelativeLayout ซึ่งห่อด้วย ScrollView)
Jonik

14
มีประโยชน์ในบางกรณี: ใช้ความกว้างของหน้าจอทั้งหมด:int width = getResources().getDisplayMetrics().widthPixels
Jonik

6
+1 สำหรับ Jonik -1 สำหรับ Richard onCreateDialog()ฉันมักจะใช้ชิ้นส่วนสนับสนุนและไม่เคยได้รับสามารถที่จะได้รับการทำงานใน onResume()ความต้องการที่จะอยู่ใน
MinceMan

146

ฉันลงเอยด้วยการเอาชนะFragment.onResume()และคว้าคุณลักษณะจากกล่องโต้ตอบพื้นฐานแล้วตั้งค่าความกว้าง / ความสูงที่นั่น ฉันตั้งค่าเลย์เอาต์ความสูง / ความกว้างด้านนอกสุดmatch_parentไว้ที่ โปรดทราบว่ารหัสนี้ดูเหมือนว่าจะเคารพขอบที่ฉันกำหนดในรูปแบบ xml เช่นกัน

@Override
public void onResume() {
    super.onResume();
    ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes();
    params.width = LayoutParams.MATCH_PARENT;
    params.height = LayoutParams.MATCH_PARENT;
    getDialog().getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
}

2
ขอบคุณมาก! มันใช้งานได้สำหรับฉัน! ยิ่งไปกว่านั้นนี่เป็นวิธีที่ยอดเยี่ยมที่จะทำ
AntoineP

1
@jmaculate - คำถามด่วน: เมื่อคุณคัดเลือกนักแสดง(android.view.WindowManager.LayoutParams)คุณมาจากอะไร ฉันงงเมื่อเลือกการนำเข้าที่ถูกต้องเพื่อให้LayoutParamsปรากฏใน 3 บรรทัดแรกของฟังก์ชั่น (android.view.WindowManager.LayoutParams)จบลงด้วยการเลือก สิ่งนี้ควรจะถูกต้องหรือไม่?
Dev-iL

@ Dev-iL getAttributes () ส่งคืน WindowManger.LayoutParams แต่ในกรณีของฉันฉันส่งไปยัง ViewGroup โดยปริยายเพราะ ViewSroup เพราะนั่นคือทั้งหมดที่ฉันต้องการ (Java ที่มีประสิทธิภาพ 52 รายการ) - ฉันจะแก้ไขคำถามเพื่อสะท้อนสิ่งนี้
jmaculate

1
ถ้าคุณต้องการที่จะใช้มันอีกครั้งandroid.view.WindowManager.LayoutParamsมันไม่มีประโยชน์ที่จะใช้ViewGroup.LayoutParamsสามบรรทัดด้านบน ... คุณไม่ได้รับความยืดหยุ่นที่นี่ อะไรก็ตามขอบคุณสำหรับคำตอบที่ดีนี้!
Kevin Robatel

2
นี่คือทางออกที่ดีที่สุด คุณสามารถใช้ค่าของพิกเซลพร้อมกับ MATCH_PARENT หรือ WRAP_CONTENT
Koesh

98

ฉันได้ DialogFragment ขนาดคงที่กำหนดต่อไปนี้ในเค้าโครงหลัก XML (LinearLayout ในกรณีของฉัน):

android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"

4
ฉันพบว่าฉันต้องการกลางกว้างและต่ำสุดในรังผึ้ง - แต่ไม่ใช่ใน ICS
daveywc

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

มุมมองไม่ได้ปิดหน้าจออย่างต่อเนื่อง ระบบ Android ดูเหมือนว่าจะทำให้แน่ใจว่า DialogFragment อยู่ในขอบเขตของมุมมอง (ด้วยระยะขอบเล็ก ๆ ) แม้ว่าขอบเขตเหล่านี้จะเล็กกว่า minWidth และ minHeight ที่ระบุ
Lensflare

51

สิ่งเดียวที่ทำงานในกรณีของฉันคือโซลูชันชี้ไปที่นี่: http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.htmlที่นี่

ตัวอย่างจากโพสต์บล็อก Adil:

@Override
public void onStart()
{
  super.onStart();

  // safety check
  if (getDialog() == null)
    return;

  int dialogWidth = ... // specify a value here
  int dialogHeight = ... // specify a value here

  getDialog().getWindow().setLayout(dialogWidth, dialogHeight);

  // ... other stuff you want to do in your onStart() method
}

โซลูชั่นที่สมบูรณ์แบบและอธิบายได้เป็นอย่างดีในบล็อก
varun bhardwaj

+1 getDialog().getWindow().setLayout(dialogWidth, dialogHeight); ทำงานอย่างสมบูรณ์แบบสำหรับ DialogFragment แต่ฉันไม่เข้าใจการตรวจสอบความปลอดภัย ทำไมเราต้องตรวจสอบnull?
tpk

3
@ 2943 - เพียงเพราะไม่มีการรับประกันว่าDialog(ลูกของDialogFragment) จะสามารถใช้ได้ในเวลาที่มีการร้องขอ เป็นไปได้ว่า Android จะกลับ null getDialog()เมื่อเราเรียกว่า
rmirabelle

@mirabelle ถ้าคุณใช้ onStart callback ของไดอะล็อกวิธีที่ไดอะล็อกสามารถเป็นโมฆะ?
rommex

49

วิธีหนึ่งในการควบคุมของคุณกว้างและความสูงคือการทำให้แน่ใจว่ากว้างประการโต้ตอบของมุมมองของคุณและถ้าค่าความสูงของพวกเขาคือDialogFragmentWRAP_CONTENT

การใช้ ThemeOverlay.AppCompat.Dialog

วิธีง่ายๆในการบรรลุเป้าหมายนี้คือการใช้ประโยชน์จากThemeOverlay.AppCompat.Dialogสไตล์ที่รวมอยู่ในห้องสมุดสนับสนุน Android

DialogFragmentด้วยDialog:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    dialog.setContentView(view);
    return dialog;
}

DialogFragmentด้วยAlertDialog(คำเตือน:) minHeight="48dp":

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    builder.setView(view);
    return builder.create();
}

คุณยังสามารถตั้งThemeOverlay.AppCompat.Dialogเป็นธีมเริ่มต้นเมื่อสร้างกล่องโต้ตอบโดยเพิ่มไปยังธีม xml ของแอป
ระวังเนื่องจากกล่องโต้ตอบหลาย ๆ อันต้องการความกว้างต่ำสุดที่เป็นค่าเริ่มต้นเพื่อให้ดูดี

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- For Android Dialog. -->
    <item name="android:dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For Android AlertDialog. -->
    <item name="android:alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For AppCompat AlertDialog. -->
    <item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- Other attributes. -->
</style>

DialogFragmentด้วยDialogทำให้การใช้android:dialogTheme:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.setContentView(view);
    return dialog;
}

DialogFragmentด้วยAlertDialog, การใช้งานandroid:alertDialogThemeหรือalertDialogTheme(caveat:) minHeight="48dp":

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setView(view);
    return builder.create();
}

โบนัส

สำหรับ Android API ที่เก่ากว่าDialogดูเหมือนว่าจะมีปัญหาด้านความกว้างเนื่องจากมีชื่อเรื่อง (แม้ว่าคุณจะไม่ได้ตั้งค่าก็ตาม)
หากคุณไม่ต้องการใช้ThemeOverlay.AppCompat.Dialogสไตล์และDialogไม่ต้องการชื่อ (หรือมีแบบกำหนดเอง) คุณอาจต้องการปิดใช้งาน:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(view);
    return dialog;
}

คำตอบที่ล้าสมัยจะไม่ทำงานในกรณีส่วนใหญ่

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

ฉันคิดว่าandroid:windowMinWidthMinorและandroid:windowMinWidthMajorทำให้เกิดปัญหา แม้ว่าพวกเขาจะไม่รวมอยู่ในธีมของฉันActivityหรือDialogพวกเขาก็ยังคงถูกนำไปใช้กับActivityชุดรูปแบบ แต่อย่างใด

ฉันคิดวิธีแก้ปัญหาที่เป็นไปได้สามข้อ

โซลูชันที่ 1:DialogFragmentสร้างรูปแบบโต้ตอบที่กำหนดเองและใช้งานได้เมื่อมีการสร้างโต้ตอบในที่

<style name="Theme.Material.Light.Dialog.NoMinWidth" parent="android:Theme.Material.Light.Dialog">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), R.style.Theme_Material_Light_Dialog_NoMinWidth);
}

โซลูชันที่ 2:สร้างชุดรูปแบบกำหนดเองเพื่อใช้ในการContextThemeWrapperที่จะทำหน้าที่เป็นContextกล่องโต้ตอบ ใช้สิ่งนี้หากคุณไม่ต้องการสร้างธีมไดอะล็อกที่กำหนดเอง (เช่นเมื่อคุณต้องการใช้ธีมที่ระบุโดยandroid:dialogTheme)

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(new ContextThemeWrapper(getActivity(), R.style.Theme_Window_NoMinWidth), getTheme());
}

โซลูชัน 3 (กับAlertDialog):บังคับใช้android:windowMinWidthMinorและandroid:windowMinWidthMajorเข้าสู่ContextThemeWrapperAlertDialog$Builderที่สร้างขึ้นโดย

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public final Dialog onCreateDialog(Bundle savedInstanceState) {
    View view = new View(); // Inflate your view here.
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setView(view);
    // Make sure the dialog width works as WRAP_CONTENT.
    builder.getContext().getTheme().applyStyle(R.style.Theme_Window_NoMinWidth, true);
    return builder.create();
}

4
ฉันไม่รู้จริงๆว่าทำไมนรกนี่ไม่ใช่คำตอบที่ยอมรับได้ นี่เป็นคำตอบเดียวที่ใช้งานได้จริงและไม่ใช่แฮ็ค (ฉันกำลังพูดถึงคำตอบแรกของคุณ)
Bogdan Zurac

1
น่าเสียดายที่พบสิ่งนี้เฉพาะหลังจากใช้เวลาหนึ่งชั่วโมงเพื่อหาวิธีการแก้ปัญหา!
ระดมสมอง

โซลูชันที่ 3 ช่วยชีวิตฉัน ขอบคุณมาก
Simon

ฉันสามารถสร้างปัญหาของคุณกับ Android API ที่เก่ากว่าได้ เพิ่มทางเลือกอื่นที่อาจช่วยคุณได้
jpmcosta

โซลูชันที่ 1 ทำงานสำหรับฉัน ฉันเพียงแค่ใช้เป็นพ่อแม่และใช้รูปแบบนี้ในตัวสร้างของTheme.MaterialComponents.Light.Dialog MaterialAlertDialogBuilderสะดุดกับคำตอบของคุณหลังจากการวิจัย 1 ชั่วโมง ขอขอบคุณและยกนิ้วให้
Shahood ul Hassan

39

Gotcha # 13: DialogFragmentเลย์เอาต์

มันช่างทำให้มึนงงจริงๆ

เมื่อสร้าง a DialogFragmentคุณสามารถเลือกที่จะแทนที่onCreateView(ซึ่งผ่าน a ViewGroupเพื่อแนบเค้าโครง. xml ของคุณ) หรือonCreateDialogซึ่งไม่

คุณต้องไม่แทนที่ทั้งสองวิธีเนื่องจากคุณจะสับสน Android มากว่าเมื่อใดหรือรูปแบบของกล่องโต้ตอบของคุณสูงเกินจริง! WTF?

ตัวเลือกว่าจะแทนที่OnCreateDialogหรือOnCreateViewขึ้นอยู่กับว่าคุณตั้งใจจะใช้กล่องโต้ตอบ

  • ถ้าคุณจะเปิดโต้ตอบในหน้าต่าง (พฤติกรรมปกติ), OnCreateDialogคุณคาดว่าจะแทนที่
  • ถ้าคุณตั้งใจจะฝังส่วนโต้ตอบภายในรูปแบบที่มีอยู่ UI (FAR น้อยกว่าปกติ) OnCreateViewแล้วคุณคาดว่าจะแทนที่

นี่อาจเป็นสิ่งที่เลวร้ายที่สุดในโลก

onCreateDialog ความบ้า

ดังนั้นคุณจะเอาชนะonCreateDialogคุณในDialogFragmentการสร้างอินสแตนซ์ที่กำหนดเองของAlertDialogจอแสดงผลในหน้าต่าง เย็น. แต่จำonCreateDialogไม่ได้รับViewGroupการแนบกำหนดเองของคุณ .xml รูปแบบเพื่อ ไม่มีปัญหาคุณเพียงส่งผ่านnullไปยังinflateวิธีการ

ปล่อยให้ความบ้าคลั่งเริ่มขึ้น

เมื่อคุณแทนที่onCreateDialogAndroid จะทำหน้าที่อธิบายคุณลักษณะต่าง ๆ ของโหนดรูทของ. xml Layout ที่คุณพองตัว ซึ่งรวมถึง แต่อาจไม่ จำกัด เพียง:

  • background_color
  • layout_gravity
  • layout_width
  • layout_height

นี่เกือบจะเป็นเรื่องตลกเพราะคุณจะต้องตั้งค่าlayout_widthและlayout_heightทุก ๆ . xml เลย์เอาต์หรือ Android Studio จะตบหน้าคุณด้วยความอัปยศสีแดงเล็กน้อย

เพียงแค่คำว่า DialogFragmentทำให้ฉันต้องการอ้วก ฉันสามารถเขียนนวนิยายที่เต็มไปด้วย gotchas และ snafus ของ Android แต่อันนี้เป็นหนึ่งในส่วนใหญ่

หากต้องการกลับสู่ความมีสติอันดับแรกเราขอประกาศสไตล์ที่จะคืนค่าความยุติธรรมbackground_colorและlayout_gravityเราคาดหวัง:

<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:layout_gravity">center</item>
</style>

สไตล์ด้านบนสืบทอดมาจากชุดรูปแบบพื้นฐานสำหรับกล่องโต้ตอบ (ในAppCompatชุดรูปแบบในตัวอย่างนี้)

ต่อไปเราใช้สไตล์โดยทางโปรแกรมเพื่อนำค่า Android กลับมาใช้ใหม่และคืนค่าAlertDialogรูปลักษณ์และความรู้สึกมาตรฐาน:

public class MyDialog extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        View layout = getActivity().getLayoutInflater().inflate(R.layout.my_dialog_layout, null, false);
        assert layout != null;
        //build the alert dialog child of this fragment
        AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
        //restore the background_color and layout_gravity that Android strips
        b.getContext().getTheme().applyStyle(R.style.MyAlertDialog, true);
        b.setView(layout);
        return b.create();
    }
}

รหัสด้านบนจะทำให้AlertDialogหน้าตาของคุณเหมือนเดิมAlertDialogอีกครั้ง บางทีนี่อาจจะดีพอ

แต่เดี๋ยวก่อนมีอีกมาก!

หากคุณกำลังมองหาการตั้งค่าแบบเฉพาะเจาะจง layout_widthหรือlayout_heightเป็นแบบของคุณAlertDialogเมื่อมันปรากฏขึ้น (น่าจะเป็นไปได้มาก) จากนั้นเดาว่าคุณยังไม่ได้ทำ!

ความฮือฮายังคงดำเนินต่อไปเมื่อคุณตระหนักว่าหากคุณพยายามที่จะตั้งค่าเฉพาะlayout_widthหรือlayout_heightในรูปแบบใหม่ของคุณ Android จะไม่สนใจสิ่งนั้นด้วยเช่นกัน!:

<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:layout_gravity">center</item>
    <!-- NOPE!!!!! --->
    <item name="android:layout_width">200dp</item>
    <!-- NOPE!!!!! --->
    <item name="android:layout_height">200dp</item>
</style>

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

@Override
public void onResume() {
    super.onResume();
    Window window = getDialog().getWindow();
    if(window == null) return;
    WindowManager.LayoutParams params = window.getAttributes();
    params.width = 400;
    params.height = 400;
    window.setAttributes(params);
}

ผู้คนจำนวนมากทำตามตัวอย่างที่ไม่ดีของ Android ในการคัดเลือกนักWindowManager.LayoutParamsเตะให้กว้างขึ้นโดยViewGroup.LayoutParamsเฉพาะเพื่อเลี้ยวขวาและโยนViewGroup.LayoutParamsลงไปWindowManager.LayoutParamsอีกไม่กี่บรรทัดในภายหลัง Java ที่มีประสิทธิภาพถูกสาปแช่ง, การคัดเลือกนักแสดงที่ไม่จำเป็นนั้นไม่มีอะไรนอกจากการทำโค้ดให้ยากต่อการถอดรหัส

หมายเหตุด้านข้าง: มีการทำซ้ำยี่สิบครั้งLayoutParamsทั่วทั้ง Android SDK ซึ่งเป็นตัวอย่างที่สมบูรณ์แบบของการออกแบบที่ไม่ดีนัก

สรุป

สำหรับDialogFragments ที่แทนที่onCreateDialog:

  • หากต้องการคืนค่าAlertDialogรูปลักษณ์และความรู้สึกมาตรฐานให้สร้างสไตล์ที่กำหนดbackground_color= transparentและlayout_gravity= centerและใช้สไตล์onCreateDialogนั้น
  • หากต้องการตั้งค่าเฉพาะlayout_widthและ / หรือlayout_heightให้ตั้งโปรแกรมonResumeโดยใช้LayoutParams
  • เพื่อรักษาสติให้ดีอย่าพยายามนึกถึง Android SDK

13
การอ่านคำตอบนี้ทำให้ฉันอยากร้องไห้
Bassinator

3
เพื่อนคุณอธิบายสิ่งที่ฉันกำลังประสบอยู่ในตอนนี้
Mert Gülsoy

2
Android อึ ฉันรู้สึกถึงคุณพี่ ต้องการบริบทสำหรับทุกอย่างกระบวนการฆ่าแอปขาดห้องสมุดสนับสนุนสำหรับบางสิ่งรายการดังกล่าวดำเนินต่อไป
DennisVA

1
@rmirabelle - คำตอบนี้ช่วยได้จริงคุณสามารถเขียนบล็อกขนาดกลางได้จริงและมีประโยชน์สำหรับคนจำนวนมาก ในกรณีของฉันฉันกำลังใช้เลย์เอาต์ข้อ จำกัด และ DialogFragment ดังนั้นด้วยการถูกละเว้นใน Android 9 ด้านล่าง Android 9 มันทำงานได้ดี ฉันได้เพิ่ม - "android: windowMinWidthMajor," android: windowMinWidthMinor "อย่างมีสไตล์และมันก็เริ่มทำงานได้ดี
Rahul


14

เมื่อฉันต้องการทำให้ DialogFragment กว้างขึ้นฉันกำลังตั้งค่า minWidth:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="320dp"
    ... />

1
ทางออกที่ดีที่สุดในความคิดของฉัน!
Fabian Knapp

ถ้าคุณต้องการทำให้มันแคบลง
แดเนียล

8

ผมไม่เห็นเหตุผลที่น่าสนใจที่จะแทนที่onResumeหรือonStartการตั้งค่าความกว้างและความสูงของWindowภายในDialogFragment's Dialog- วิธีการเหล่านี้วงจรชีวิตโดยเฉพาะอย่างยิ่งจะได้รับการเรียกซ้ำโดยไม่จำเป็นและดำเนินการว่ารหัสการปรับขนาดมากกว่าหนึ่งครั้งเนื่องจากสิ่งที่ต้องการสลับหน้าต่างหลาย backgrounding จากนั้นเบื้องหน้าแอปและอื่น ๆ ผลที่ตามมาของการทำซ้ำนั้นค่อนข้างน่าสนใจ แต่ทำไมถึงเป็นเช่นนั้น

การตั้งค่าความกว้าง / สูงแทนภายในแทนที่วิธีการจะมีการปรับปรุงเพราะวิธีนี้แนบเนียนเพียงได้รับการเรียกหนึ่งครั้งต่อหนึ่งตัวอย่างของคุณonActivityCreated() DialogFragmentตัวอย่างเช่น:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Window window = getDialog().getWindow();
    assert window != null;

    WindowManager.LayoutParams layoutParams = window.getAttributes();
    layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    window.setAttributes(layoutParams);
}

ด้านบนฉันเพิ่งตั้งค่าความกว้างให้match_parentคำนึงถึงการวางแนวของอุปกรณ์ หากคุณต้องการให้กล่องโต้ตอบแนวนอนไม่กว้างคุณสามารถทำการตรวจสอบgetResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAITก่อนล่วงหน้าได้


6

ส่วนข้อมูลในเค้าโครงด้านนอกสุดไม่สามารถใช้งานได้ในกล่องโต้ตอบ คุณสามารถเพิ่มเค้าโครงที่ตั้งค่ามิติไว้ด้านล่างสุด

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

<LinearLayout
    android:layout_width="xxdp"
    android:layout_height="xxdp"
    android:orientation="vertical">

</LinearLayout>


5

ฉันแก้ไขการตั้งค่าพารามิเตอร์โครงร่างองค์ประกอบราก

int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));

5

ต่อไปนี้เป็นวิธีตั้งค่าความกว้าง / ความสูง DialogFragment เป็น xml เพียงห่อมุมมองลำดับชั้นของคุณใน Framelayout (เลย์เอาต์ใด ๆ ก็ได้) ด้วยพื้นหลังที่โปร่งใส

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

<?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="match_parent"
    android:background="@color/transparent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="@color/background_material_light">

      .....

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

ฉันชอบแนวคิดของวิธีการนี้ แต่เมื่อทดสอบแล้วจะให้รูปแบบที่แตกต่างจากการเปลี่ยนความสูงและความกว้างของโปรแกรม ยกตัวอย่างเช่นความกว้างโดยรวมจะลดลงเหลือความกว้างสูงสุดที่ได้รับจาก AlertDialog (น่าจะเป็นเพราะสไตล์ Android) เมื่อฉันตั้งค่า w และ h ผ่านโค้ดสไตล์ AlertDialog จะถูกเขียนทับ สิ่งนี้อาจเหมาะกับความต้องการมากมายและเป็นความคิดที่ดี ลองใช้ SDK ที่แย่ที่สุดในประวัติศาสตร์
rmirabelle

ทำงานได้ดีเยี่ยมสำหรับ onCreateView จนกว่าฉันจะต้องการเปลี่ยนความกว้างด้านในเป็น match_parent ...
ทิวดอร์

5

นี่คือรุ่น kotlin

    override fun onResume() {
        super.onResume()

        val params:ViewGroup.LayoutParams = dialog.window.attributes
        params.width = LinearLayout.LayoutParams.MATCH_PARENT
        params.height = LinearLayout.LayoutParams.MATCH_PARENT
        dialog.window.attributes = params as android.view.WindowManager.LayoutParams
    }

4

คุณสามารถใช้เปอร์เซ็นต์สำหรับความกว้าง

<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">70%</item>

ฉันใช้ Holo Theme สำหรับตัวอย่างนี้


3

คุณสามารถโค้ดด้านล่างเพื่อตั้งค่าความกว้างและความสูงเค้าโครงจากจาวา

final AlertDialog alertDialog  = alertDialogBuilder.create();
final WindowManager.LayoutParams WMLP = alertDialog.getWindow().getAttributes();

WMLP.gravity = Gravity.TOP;
WMLP.y = mActionBarHeight;
WMLP.x = getResources().getDimensionPixelSize(R.dimen.unknown_image_width);

alertDialog.getWindow().setAttributes(WMLP);
alertDialog.show();

2

ฉันสร้างกล่องโต้ตอบโดยใช้ AlertDialog.Builder ดังนั้นฉันจึงใช้คำตอบของ Rodrigo ใน OnShowListener

dialog.setOnShowListener(new OnShowListener() {

            @Override
            public void onShow(DialogInterface dialogInterface) {
                Display display = getWindowManager().getDefaultDisplay();
                DisplayMetrics outMetrics = new DisplayMetrics ();
                display.getMetrics(outMetrics);
                dialog.getWindow().setLayout((int)(312 * outMetrics.density), (int)(436 * outMetrics.density));
            }

        });

(ส่วนใหญ่สำหรับผู้อ่านในอนาคต :) ความคิดเห็นดูโดยSnicolasในการอภิปรายของ " DialogFragmentVS AlertDialog" ในstackoverflow.com/a/7979823/3372061
Dev-iL

2

ทำงานกับ Android 6.0 แล้วพบปัญหาเดียวกัน AlertDialogจะเริ่มต้นที่จะกำหนดไว้ล่วงหน้าwidthชุดในรูปแบบที่ไม่คำนึงถึงความเป็นจริงชุดในรากมุมมองที่กำหนดเองของwidth Layoutฉันก็สามารถที่จะได้รับมันไปยังชุดถูกปรับของwidth loading_message TextViewโดยไม่ต้องตรวจสอบเพิ่มเติมดูเหมือนว่าการปรับขนาดองค์ประกอบที่แท้จริงและการมีการปิดรูทLayoutนั้นทำให้มันทำงานได้ตามที่คาดหวัง ด้านล่างเป็นโครงร่าง XML ของกล่องโต้ตอบโหลดซึ่งชุดwidthของกล่องโต้ตอบถูกต้อง ใช้ไลบรารีนี้สำหรับภาพเคลื่อนไหว

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/custom_color"
    android:padding="@dimen/custom_dimen">
    <com.github.rahatarmanahmed.cpv.CircularProgressView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/progress_view"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_centerHorizontal="true"
        app:cpv_color="@color/white"
        app:cpv_animAutostart="true"
        app:cpv_indeterminate="true" />
    <TextView
        android:id="@+id/loading_message"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/progress_view"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:textSize="18dp"
        android:layout_marginTop="@dimen/custom_dimen"
        android:textColor="@color/white"
        android:text="@string/custom_string"/>
</RelativeLayout>

2

ง่ายและมั่นคง:

@Override
    public void onResume() {
        // Sets the height and the width of the DialogFragment
        int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
        int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
        getDialog().getWindow().setLayout(width, height);

        super.onResume();
    }

2

ในกรณีของฉันครอบครองขนาดกิจกรรมเต็มรูปแบบเช่นDialogFragment อยู่บนพื้นฐานของ XML ที่รูปแบบไม่ได้ ความผิดพลาดของฉันคือการเพิ่มส่วนของการโต้ตอบเป็นชิ้นส่วนปกติ:FragmentDialogFragmentAlertDialogFragmentManager

fragmentManager?.beginTransaction()?.run {
    replace(R.id.container, MyDialogFragment.newInstance(), MyDialogFragment.TAG)
    addToBackStack(MyDialogFragment.TAG)
}?.commitAllowingStateLoss()

แต่ฉันต้องshowแยกส่วนโต้ตอบ:

val dialogFragment = MyDialogFragment.newInstance()
fragmentManager?.let { dialogFragment.show(it, MyDialogFragment.TAG) }

หลังจากแก้ไขบางส่วน (ฉันมีViewPager2ในโครงร่าง) ส่วนของกล่องโต้ตอบแคบเกินไป:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันใช้วิธีแก้ปัญหาของN1hk :

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    dialog?.window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
}

ตอนนี้มันได้กำหนดความกว้างและความสูงไม่ใช่ขนาดกิจกรรมเต็ม

ผมอยากจะบอกเกี่ยวกับและonCreateView onCreateDialogหากคุณมีส่วนย่อยของไดอะล็อกตามเลย์เอาท์คุณสามารถใช้วิธีการใดก็ได้ 2 วิธีนี้

1) ถ้าคุณใช้onCreateViewคุณควรใช้onActivityCreatedเพื่อตั้งค่าความกว้าง

2) ถ้าคุณใช้onCreateDialogแทนคุณonCreateViewสามารถตั้งค่าพารามิเตอร์ที่นั่น onActivityCreatedจะไม่ต้องการ

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    super.onCreateDialog(savedInstanceState)

    val view = activity?.layoutInflater?.inflate(R.layout.your_layout, null)

    val dialogBuilder = MaterialAlertDialogBuilder(context!!).apply { // Or AlertDialog.Builder(context!!).apply
        setView(view)
        // setCancelable(false)
    }

    view.text_view.text = "Some text"

    val dialog = dialogBuilder.create()
    // You can access dialog.window here, if needed.

    return dialog
}

คุณบันทึกวันของฉันการตั้งค่าความกว้างใน onActivityCreated ใช้งานได้สำหรับฉัน
Hagar Magdy

@ManishKumarSharma ขอให้โชคดี!
CoolMind

1

ในกรณีของฉันมันเกิดจากที่กำหนดให้มุมมองภายในalign_parentBottom="true" RelativeLayoutลบ alignParentBottom ทั้งหมดและเปลี่ยนเค้าโครงทั้งหมดเป็น LinearLayouts แนวตั้งและปัญหาหายไป


1

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

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

สิ่งนี้ใช้ได้สำหรับฉัน ฉันต้องการใช้ ConstraintLayout เพื่อจัดวางตัวควบคุมในกล่องโต้ตอบของฉันดังนั้นฉันจึงใช้ RelativeLayout สำหรับเค้าโครงของรูทแล้ววาง ConstraintLayout ไว้ข้างใน นี่ทำให้ฉันมีกล่องโต้ตอบขนาดปกติ เมื่อฉันใส่ ConstraintLayout เป็นรูทโดยไม่เปลี่ยนแปลงอะไรเลยความกว้างของไดอะล็อกที่ถูก imploded จะไม่กว้างมาก!
leafcutter

1

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

(ตรวจสอบให้แน่ใจว่าคุณมองหาวิธีแก้ปัญหาของเขา) นี่คือวิธีแก้ปัญหาของเขา .. คลิกที่นี่ มันทำงานได้ยกเว้น: builder.getContext (). getTheme (). ใช้สไตล์ (R.styleTheme_Window_NoMinWidth, true);

ฉันเปลี่ยนเป็น

 @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {


        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // Get layout inflater
        LayoutInflater layoutInflater = getActivity().getLayoutInflater();

        // Set layout by setting view that is returned from inflating the XML layout
        builder.setView(layoutInflater.inflate(R.layout.dialog_window_layout, null));


        AlertDialog dialog = builder.create();

        dialog.getContext().setTheme(R.style.Theme_Window_NoMinWidth);

บรรทัดสุดท้ายคืออะไรที่แตกต่างกันจริงๆ


0
@Override
public void onStart() {
    super.onStart();
    Dialog dialog = getDialog();
    if (dialog != null)
    {
        dialog.getWindow().setLayout(-1, -2);
        dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.dimAmount = 1.0f;
        window.setAttributes(params);
        window.setBackgroundDrawableResource(android.R.color.transparent);
    }
}

0

นี่คือทางออกที่ง่ายที่สุด

ทางออกที่ดีที่สุดที่ฉันได้พบคือการแทนที่แทนonCreateDialog() onCreateView()setContentView () จะตั้งค่าขนาดหน้าต่างที่ถูกต้องก่อนที่จะขยาย มันไม่จำเป็นต้องจัดเก็บ / ตั้งค่ามิติสีพื้นหลังสไตล์ ฯลฯ ในไฟล์ทรัพยากรและตั้งค่าด้วยตนเอง

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(getActivity());
    dialog.setContentView(R.layout.fragment_dialog);

    Button button = (Button) dialog.findViewById(R.id.dialog_button);
    // ...
    return dialog;
}

0

เพิ่มของคุณFragmentDialog:

public void onResume() {
    Window window = getDialog().getWindow();
    Point size = new Point();
    Display display = window.getWindowManager().getDefaultDisplay();
    display.getSize(size);
    window.setLayout( (int)(size.x * 0.9), WindowManager.LayoutParams.WRAP_CONTENT );
    window.setGravity( Gravity.CENTER );
    super.onResume();
}

0

มันจะทำงานได้อย่างสมบูรณ์แบบ

@Override
public void onResume() {
    super.onResume();
    Window window = getDialog().getWindow();
    if(window == null) return;
    WindowManager.LayoutParams params = window.getAttributes();
    params.width = 400;
    params.height = 400;
    window.setAttributes(params);
}

นี่เป็นคำตอบที่ได้รับการยอมรับจาก 3 ปีที่ผ่านมา
Adil Hussain

-4

ในการรับ Dialog ที่ครอบคลุมเกือบทั้งหินกรวด: ก่อนกำหนดคลาส ScreenParameter

public class ScreenParameters
{
    public static int Width;
    public static  int Height;

    public ScreenParameters()
    {
        LayoutParams l = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        Width= l.width;
        Height = l.height;
    }
}

จากนั้นคุณต้องโทรหา ScreenParamater ก่อน getDialog.getWindow () วิธี setLayout ()

@Override
public void onResume()
{
    super.onResume();
    ScreenParameters s = new ScreenParameters();
    getDialog().getWindow().setLayout(s.Width , s.Height);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.