36

我正在嘗試使用AlertDialog中的自定義視圖創建DialogFragment。這個視圖必須從xml中誇大。在我的DialogFragment I類有:在DialogFragment中爲AlertDialog充氣自定義視圖問題

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    return new AlertDialog.Builder(getActivity()) 
     .setTitle("Title") 
     .setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, null)) 
     .setPositiveButton(android.R.string.ok, this) 
     .setNegativeButton(android.R.string.cancel, null) 
     .create(); 
} 

我曾嘗試.setView()其他充氣的方法,如:

.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getView(), false)) 

.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getTargetFragment().getView(), false)) 

在作爲片段設定目標片段後顯示這個對話框。

所有這些企圖誇大以下異常我的自定義視圖結果:

E/AndroidRuntime(32352): android.util.AndroidRuntimeException: requestFeature() must be called before adding content 
E/AndroidRuntime(32352):  at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:214) 
E/AndroidRuntime(32352):  at com.android.internal.app.AlertController.installContent(AlertController.java:248) 
E/AndroidRuntime(32352):  at android.app.AlertDialog.onCreate(AlertDialog.java:314) 
E/AndroidRuntime(32352):  at android.app.Dialog.dispatchOnCreate(Dialog.java:335) 
E/AndroidRuntime(32352):  at android.app.Dialog.show(Dialog.java:248) 
E/AndroidRuntime(32352):  at android.support.v4.app.DialogFragment.onStart(DialogFragment.java:339) 
E/AndroidRuntime(32352):  at android.support.v4.app.Fragment.performStart(Fragment.java:1288) 
E/AndroidRuntime(32352):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:873) 
E/AndroidRuntime(32352):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1041) 
E/AndroidRuntime(32352):  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:625) 
E/AndroidRuntime(32352):  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1360) 
E/AndroidRuntime(32352):  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:411) 
E/AndroidRuntime(32352):  at android.os.Handler.handleCallback(Handler.java:587) 
E/AndroidRuntime(32352):  at android.os.Handler.dispatchMessage(Handler.java:92) 
E/AndroidRuntime(32352):  at android.os.Looper.loop(Looper.java:132) 
E/AndroidRuntime(32352):  at android.app.ActivityThread.main(ActivityThread.java:4028) 
E/AndroidRuntime(32352):  at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime(32352):  at java.lang.reflect.Method.invoke(Method.java:491) 
E/AndroidRuntime(32352):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 
E/AndroidRuntime(32352):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
E/AndroidRuntime(32352):  at dalvik.system.NativeStart.main(Native Method) 

而如果我嘗試使用DialogFragmentgetLayoutInflator(Bundle)這樣的:

.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null)) 

我得到一個StackOverflowError

有誰知道如何在DialogFragment中膨脹AlertDialog的自定義視圖嗎?

回答

72

第一個錯誤行給我提示,這與您如何創建對話框有關 - 而不是對話框本身。

是否自動創建對話框(可能意味着在視圖全部設置之前調用該對話框)或響應按鈕單擊?由於實例化順序,我最初遇到了碎片問題。

我使用相同的代碼來設置視圖,因爲你有我的結果。我刪除了其他設置,使其看起來更清潔,但它可以與其他設備一起使用。

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 

    View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_layout, null); 
    builder.setView(view); 

    return builder.create(); 
} 
+1

這對我有用,但我想明白爲什麼。爲什麼dialogFragment的getLayoutInflater會返回一個與Activity不同的layoutinflater? – stork

+0

每個LayoutInflater綁定到一個上下文(在Activity和片段之間有所不同),並且片斷使事情變得複雜。此外,還有一些不能遞歸工作的東西(例如對話框中的對話框)。我猜想問題在於實例化順序和遞歸之間的某處,但它可能更容易滾動,而不是進一步挖掘... – ProjectJourneyman

+15

這導致我真正的問題是你必須調用'setView()'之前(比如'setTitle()',這是我做錯了)。謝謝。 – ashughes

0

在你的代碼中調用

create(). 

show(). 
+2

'onCreateDialog()'應該返回一個'Dialog',這就是爲什麼我使用'.create()'。 'DialogFragment'由片段顯示_shown_,它通過DialogFragment.show(FragmentTransaction,String)創建並將此DialogFragment添加到其'FragmentManager'中。 – ashughes

0

替換我還沒有從XML膨脹,但我已成功一個DialogFragment進行動態視圖生成:

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    m_editText = new EditText(getActivity()); 
    return new AlertDialog.Builder(getActivity()) 
      .setView(m_editText) 
      .setPositiveButton(android.R.string.ok,null) 
      .setNegativeButton(android.R.string.cancel, null); 
      .create(); 
} 
0

你想要做的是在onCreateView方法中創建自定義視圖,就像通常那樣。如果你想做一些改變對話框標題的東西,你可以在onCreateView中做。

下面是一個例子來說明我的意思:

 @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     getDialog().setTitle("hai"); 
     View v = inflater.inflate(R.layout.fragment_dialog, container, false); 
     return v; 
    } 

然後您只要致電:

DialogFragment df = new MyDialogFragment(); 
df.show(..); 

瞧,用自己的自定義視圖的對話框。

+5

不幸的是,這不允許你設置OS標準對話框按鈕。準確地說是 –

+0

。由於您沒有對話框中的操作欄,我完全依靠AlertDialog的按鈕 – njzk2

20

我對這些問題的答案驚訝,因爲他們沒有解決問題。

DialogFragment允許您在對話框中重複使用相同的UI,並將其作爲片段集成到其他應用程序中。相當有用的功能。根據谷歌的文檔,你可以通過覆蓋onCreateDialog和onCreateView來實現。 http://developer.android.com/reference/android/app/DialogFragment.html

有三種情況在這裏:

  1. 只重寫onCreateDialog - 作品的對話,但不能 別處集成。
  2. 僅覆蓋onCreateView - 不能用作對話框,但可以在其他位置集成 。
  3. 覆蓋兩個 - 作爲對話框工作,並可以在其他地方集成 。

解決方案: 的AlertDialog類調用另一個類調用requestFeature。要解決這個問題..不要使用AlertDialog,而應使用普通的Dialog或任何super.onCreateDialog返回的值。這個我找到的解決方案效果最好。

警告: 其他對話框如DatePickerDialog,ProgressDialog,TimePickerDialog都會從AlertDialog繼承,並且可能會導致相同的錯誤。

底線: 如果您需要創建非常需要在多個位置使用的定製界面,DialogFragment非常好。它似乎不能重用現有的android對話框。

+0

從實驗中,這個問題只發生在某些Android版本上。已經看到它在21日和22日失敗,而它在23日和24日工作。 –

10

避免請求功能部件的碰撞,並使用相同的佈局:

public class MyCombinedFragment extends DialogFragment 
{ 
    private boolean isModal = false; 

    public static MyCombinedFragment newInstance() 
    { 
     MyCombinedFragment frag = new MyCombinedFragment(); 
     frag.isModal = true; // WHEN FRAGMENT IS CALLED AS A DIALOG SET FLAG 
     return frag; 
    } 

    public MyCombinedFragment() 
    { 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    { 
     if(isModal) // AVOID REQUEST FEATURE CRASH 
     { 
     return super.onCreateView(inflater, container, savedInstanceState); 
     } 
     else 
     { 
     View view = inflater.inflate(R.layout.fragment_layout, container, false); 
     setupUI(view); 
     return view; 
     } 
    } 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) 
    { 
     AlertDialog.Builder alertDialogBuilder = null; 
     alertDialogBuilder = new AlertDialog.Builder(getActivity()); 
     View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_layout, null); 
     alertDialogBuilder.setView(view); 
     alertDialogBuilder.setTitle(「Modal Dialog「); 
     alertDialogBuilder.setPositiveButton("Cancel", new DialogInterface.OnClickListener() 
     { 
      @Override 
      public void onClick(DialogInterface dialog, int which) 
      { 
       dialog.dismiss(); 
      } 
     }); 
     setupUI(view); 
     return alertDialogBuilder.create(); 
    } 
} 
+1

這是我見過的最好的解決方案。 –

+2

僅供參考,您可以使用'getShowsDialog()'來知道您的片段是否顯示爲模態。但看@vangorra答案。 – Neige

2

我有同樣的問題。在我的情況下,這是因爲Android Studio創建了一個onCreateView模板,用於重新填充新視圖,而不是返回在onCreateDialog中創建的視圖。 onCreateView是在onCreateDialog之後調用的,因此解決方案是簡單地重新生成片段視圖。

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    return this.getView(); 
} 
+0

這解決了我的問題! –

1

面對同樣的問題,並且花了很多時間擺脫錯誤。最後傳遞資源ID到setView()方法解決了這個問題。添加設置如下圖:

.setView(R.layout.dialog)

+0

請使用代碼標記來提高可讀性。 –

0

因爲我需要很長的時間來解決同樣的問題(彈出一個簡單的文本對話框),我決定分享我的解決方案:

的layoutfile connectivity_dialog.xml包含一個簡單的TextView與消息文本:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:gravity="center" 
       android:layout_gravity="center"> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginStart="20dp" 
     android:layout_marginEnd="20dp" 
     android:layout_marginTop="20dp" 
     android:layout_marginBottom="20dp" 
     android:text="Connectivity was lost" 
     android:textSize="34sp" 
     android:gravity="center" 
     /> 
</RelativeLayout> 

表示「對話」活動實現內部類(如DialogFragment是片段,而不是一個對話;進一步信息參見https://stackoverflow.com/a/5607560/6355541)。該活動可以通過兩個功能激活和停用DialogFragment。如果您使用的是android.support。V4,你可能想改變getSupportFragmentManager():

public static class ConnDialogFragment extends DialogFragment { 
    public static ConnDialogFragment newInstance() { 
     ConnDialogFragment cdf = new ConnDialogFragment(); 
     cdf.setRetainInstance(true); 
     cdf.setCancelable(false); 
     return cdf; 
    } 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.connectivity, container, false); 
    } 
} 

private void dismissConn() { 
    DialogFragment df = (DialogFragment) getFragmentManager().findFragmentByTag("conn"); 
    if (df != null) df.dismiss(); 
} 

private void showConn() { 
    FragmentTransaction ft = getFragmentManager().beginTransaction(); 
    Fragment prev = getFragmentManager().findFragmentByTag("conn"); 
    if (prev != null) ft.remove(prev); 
    ft.addToBackStack(null); 
    ConnDialogFragment cdf = ConnDialogFragment.newInstance(); 
    cdf.show(ft, "conn"); 
} 
相關問題