2012-07-11 13 views
45

Nell'app Calendario sul mio Galaxy Tab 10.1, quando si crea un nuovo evento viene visualizzata una finestra di dialogo con i pulsanti Fine e Annulla nella barra del titolo/nell'area della barra delle azioni.ActionBar in a DialogFragment

enter image description here

mi piacerebbe implementare questo nella mia app. Ho provato a utilizzare setHasOptionsMenu(true) oltre a ignorare onCreateOptionsMenu nella sottoclasse DialogFragment, ma i miei elementi di azione non vengono visualizzati. Ho anche provato a chiamare getDialog().getActionBar() dall'interno di onCreateView ma restituisce sempre null.

Sono in grado di farlo funzionare se avvio uno Activity piuttosto che mostrare una finestra di dialogo ma che occupa l'intero schermo. C'è un modo standard per farlo usando uno DialogFragment?

+5

Questa è probabilmente un'attività in stile per apparire come una finestra di dialogo invece di un "vero dialogo". – Veeti

risposta

83

utilizzando l'idea di un google group post Sono stato in grado di estrarlo dallo styling di un'attività. preferirai modificare l'altezza e la larghezza in una dimensione "dinamica" a tua scelta preferibilmente. Quindi impostare qualunque pulsanti ActionBar volete

<style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog"> 
    <item name="android:windowIsFloating">false</item> 
    <item name="android:windowContentOverlay">@null</item> 
    <item name="android:windowSoftInputMode">stateAlwaysHidden</item> 
    <item name="android:windowActionModeOverlay">true</item> 
    <item name="android:windowIsTranslucent">true</item> 
</style> 

-

public static void showAsPopup(Activity activity) { 
    //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest 
    activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); 
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, 
      WindowManager.LayoutParams.FLAG_DIM_BEHIND); 
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.height = 850; //fixed height 
    params.width = 850; //fixed width 
    params.alpha = 1.0f; 
    params.dimAmount = 0.5f; 
    activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
    setContentView(R.layout.activity_main); 
} 
+0

Hai salvato il mio giorno (i)! – softwaresupply

+3

Hai appena arricchito la mia applicazione da un sacco! –

+0

Sembra che la barra di azione della finestra di dialogo non abbia lo stile personalizzato. Ottiene lo stile predefinito. Qualche idea su come rendere la barra delle azioni abbia lo stile personalizzato? –

1

Come suggerito da Veeti, è possibile provare a implementare un'attività con un tema di dialogo. Nel manifesto Android:

<activity android:name=".YourActivity" android:theme="@android:style/Theme.Dialog </activity> 

Speriamo che questo possa essere d'aiuto.

1

Sono probabilmente non quello sperimentato in questo, ma vorrei utilizzare un'attività, aggiungere elementi della barra delle operazioni e quindi:

<activity android:name=".YourActivity" android:theme="@android:style/Theme.Holo.Light.Dialog" />

Speranza che aiuta!

+3

Questo riesce a mostrare l'attività come una finestra di dialogo, ma ancora nessuna barra di azione da vedere. Ho anche provato ad avere un tema personalizzato che eredita da 'Theme.Holo.Light.Dialog' e impostare l'attributo' android: windowActionBar' su 'true'. Fatto questo, ottengo un'eccezione 'java.lang.IllegalStateException: ActionBarImpl può essere utilizzato solo con un layout di decorazione della finestra compatibile'. –

4

Ho speso una quantità incredibile di tempo a giocare con questo. La risposta accettata lavora su un Galaxy Nexus 7 (Android 4.2), ma non riesce in un Samsung Galaxy SIII (Android 4.1) e un Samsung Galaxy Tab 10.2 (Android 4.0), con la seguente eccezione:

IllegalStateException: ActionBarView can only be used with android:layout_width="match_parent" (or fill_parent) 

Questo è causato dal codice in ActionBarView.onMeasure(int, int) che verifica che il layout sia impostato su match_parent. La soluzione corretta è invece impostare la larghezza della finestra tramite setLayout invece di utilizzare setAttributes.

Questa è una versione fissa di showAsPopup(), che funziona su tutti i dispositivi Ho testato sotto:

private void showAsPopup(Activity activity) { 
    //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest 
    activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); 
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, 
      WindowManager.LayoutParams.FLAG_DIM_BEHIND); 
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.alpha = 1.0f; 
    params.dimAmount = 0f; 
    activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 

    // This sets the window size, while working around the IllegalStateException thrown by ActionBarView 
    activity.getWindow().setLayout(850,850); 
} 

Per completezza, ecco la PopupTheme ancora:

<style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog"> 
    <item name="android:windowIsFloating">false</item> 
    <item name="android:windowContentOverlay">@null</item> 
    <item name="android:windowSoftInputMode">stateAlwaysHidden</item> 
    <item name="android:windowActionModeOverlay">true</item> 
    <item name="android:windowIsTranslucent">true</item> 
</style> 
14

Se sei utilizzando ActionBarSherlock, dichiarare il tema come riportato di seguito:

<style name="PopupTheme" parent="Theme.Sherlock"> 
    <item name="android:windowFrame">@null</item> 
    <item name="android:windowIsFloating">false</item> 
    <item name="android:windowContentOverlay">@null</item> 
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> 
    <item name="android:windowSoftInputMode">stateAlwaysHidden</item> 
    <item name="android:windowActionModeOverlay">true</item> 
    <item name="android:colorBackgroundCacheHint">@null</item> 
    <item name="android:windowCloseOnTouchOutside">true</item> 
    <item name="android:windowIsTranslucent">true</item> 
    <item name="windowContentOverlay">@null</item> 
</style> 

E, inizializzare uno SherlockActivity con PopupTheme in base a Luke Sleeman's answer.

private void showAsPopup(SherlockActivity activity) { 
    //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest 
    //activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); // NO NEED to call this line. 
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, 
      WindowManager.LayoutParams.FLAG_DIM_BEHIND); 
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.alpha = 1.0f; 
    params.dimAmount = 0.5f; 
    activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 

    // This sets the window size, while working around the IllegalStateException thrown by ActionBarView 
    activity.getWindow().setLayout(width,height); 
} 

Risultato:

enter image description here

11

avuto qualche difficoltà a attuare le soluzioni proposte da StrikeForceZero e Luca Sleeman, così ho voluto contribuire la mia esperienza. Sono sicuro che c'è qualcosa che mi manca, quindi il feedback sarebbe molto apprezzato.

Quello che ho fatto è stato il seguente:

  1. creare uno stile utilizzando l'apposita PopupTheme, copia diretta/incolla:

    <style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog"> 
        <item name="android:windowIsFloating">false</item> 
        <item name="android:windowContentOverlay">@null</item> 
        <item name="android:windowSoftInputMode">stateAlwaysHidden</item> 
        <item name="android:windowActionModeOverlay">true</item> 
        <item name="android:windowIsTranslucent">true</item> 
    </style> 
    
  2. aggiungere il metodo showAsPopup() come metodo nella frammento che aprirebbe il finto frammento di dialogo, copia/incolla diretta:

    private void showAsPopup(Activity activity) { 
        //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest 
        activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); 
        activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, 
         WindowManager.LayoutParams.FLAG_DIM_BEHIND); 
        LayoutParams params = activity.getWindow().getAttributes(); 
        params.alpha = 1.0f; 
        params.dimAmount = 0f; 
        activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
    
        // This sets the window size, while working around the IllegalStateException thrown by ActionBarView 
        activity.getWindow().setLayout(850,850); 
    } 
    
  3. Creare un'istanza della nuova attività con una nuova chiamata semplice(), e poi passarlo al showAsPopup() Metodo:

    DialogTestActivity test = new DialogTestActivity(); 
    showAsPopup(test); 
    
  4. Ai fini del test (Stavo solo cercando di confermare che ho potrebbe aprire un'attività che viene presentata come una finestra di dialogo con una barra delle azioni) Ho usato un test estremamente semplice, rubato direttamente dal pulsante view api demo (per il file di layout, vedere buttons_1.xml nelle demo api):

    public class DialogTestActivity extends Activity { 
    
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState); 
         setContentView(R.layout.buttons_test); 
        } 
    } 
    

Sfortunatamente, ogni volta che ho provato questo, ottengo un unspecifi ed eccezione del puntatore null alla prima chiamata, activity.requestWindowFeature (Window.FEATURE_ACTION_BAR);

04-29 16:39:05.361: W/System.err(15134): java.lang.NullPointerException 
04-29 16:39:05.361: W/System.err(15134): at android.app.Activity.requestWindowFeature(Activity.java:3244) 
04-29 16:39:05.371: W/System.err(15134): at packagenameremovedforlegalreasons.classname.showAsPopup(classname.java:602) 
04-29 16:39:05.371: W/System.err(15134): at packagenameremovedforlegalreasons.classname.onMapLongClick(classname.java:595) 
04-29 16:39:05.371: W/System.err(15134): at com.google.android.gms.maps.GoogleMap$5.onMapLongClick(Unknown Source) 
04-29 16:39:05.371: W/System.err(15134): at com.google.android.gms.internal.k$a.onTransact(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at android.os.Binder.transact(Binder.java:310) 
04-29 16:39:05.381: W/System.err(15134): at com.google.android.gms.maps.internal.IOnMapLongClickListener$Stub$Proxy.onMapLongClick(IOnMapLongClickListener.java:93) 
04-29 16:39:05.381: W/System.err(15134): at maps.i.s.a(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.y.v.d(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.y.bf.onLongPress(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.d.v.onLongPress(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.d.h.c(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.d.h.c(Unknown Source) 
04-29 16:39:05.381: W/System.err(15134): at maps.d.j.handleMessage(Unknown Source) 
04-29 16:39:05.391: W/System.err(15134): at android.os.Handler.dispatchMessage(Handler.java:99) 
04-29 16:39:05.391: W/System.err(15134): at android.os.Looper.loop(Looper.java:137) 
04-29 16:39:05.391: W/System.err(15134): at android.app.ActivityThread.main(ActivityThread.java:5041) 
04-29 16:39:05.391: W/System.err(15134): at java.lang.reflect.Method.invokeNative(Native Method) 
04-29 16:39:05.391: W/System.err(15134): at java.lang.reflect.Method.invoke(Method.java:511) 
04-29 16:39:05.391: W/System.err(15134): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
04-29 16:39:05.391: W/System.err(15134): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
04-29 16:39:05.391: W/System.err(15134): at dalvik.system.NativeStart.main(Native Method) 

Come si può vedere dalla analisi dello stack, il comportamento previsto è aprire la finestra su una lunga pressione su un'istanza GoogleMap (utilizzando i MapFragments da API 2). Quindi il mio primo pensiero è stato che c'era un problema nel provare ad aprire da un frammento, quindi ho passato la chiamata alla Owning Activity. Stesso errore, stesso senza informazioni aggiuntive.

La mia ipotesi migliore a questo punto era che una nuova() chiamata non creava un'istanza sufficiente della classe/vista per fare chiamate a modificare la sua vista.Risulta che questo sembra essere almeno un po 'vero, come la migrazione del codice di modifica vista nell'attività e semplicemente aprendo l'attività in modo normale funziona: l'attività

Calling:

public void openMapDialog() 
    { 
     Intent intent = new Intent(this, DialogTestActivity.class); 
     startActivity(intent); 
    } 

Nuovo codice della classe:

public class DialogTestActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // From: https://stackoverflow.com/questions/11425020/actionbar-in-a-dialogfragment 
     this.requestWindowFeature(Window.FEATURE_ACTION_BAR); 
     this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND); 
     LayoutParams params = this.getWindow().getAttributes(); 
     params.alpha = 1.0f; 
     params.dimAmount = 0f; 
     this.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 

     // This sets the window size, while working around the IllegalStateException thrown by ActionBarView 
     this.getWindow().setLayout(600,600); 

     setContentView(R.layout.buttons_test); 
     } 
    } 

quindi credo che il punto di distacco me tutto questo è di chiarire che se si vuole fare ciò che i manifesti di cui sopra suggeriscono, non si può semplicemente new() un'attività e chiamano showAsPopup(). Questa potrebbe essere la mia inesperienza con Android che mostra attraverso, ma mentre questo sembra un po 'ovvio, sembra anche naturale interpretare showAsPopup() come chiamato dalla vista corrente, non dalla vista che si sta creando, mentre passi nell'istanza di attività (che sarebbe solo questo se doveva essere fatto in onCreate() come ho finito per fare).

Quindi, se l'intenzione è quella di chiamare showAsPopup() nell'attività creando e non l'attività creato, non è ovvio come ottenere l'istanza di attività che è modificabile prima onCreate() di essere chiamato. Il problema è che non è possibile chiamare cose come requestWindowFeature() dopo che viene chiamato setContentView() (example), che è un problema poiché viene generalmente chiamato onCreate().

Ancora una volta, se c'è un modo facile/migliore per farlo, apprezzerei molto il feedback. Speriamo che questo sia utile per le persone che vogliono usare questo approccio.

+0

Grazie, mi ha aiutato. Il mio modo di affrontare il problema è stato quello di cambiare il metodo 'showAsPopup (Activity activity)' in un metodo "statico pubblico" e poi chiamarlo da 'onCreate 'prima di qualsiasi altra cosa (eccetto' super.onCreate'. – loudev

+0

Grazie per aver spiegato dove la risposta originale fallisce.Nota che non c'è bisogno che il tuo metodo sia statico –

+1

Grande spiegazione! Due cose che possono ancora essere confuse: nel punto 2 stai scrivendo su FRAMMENTI. Dovrebbe essere chiaro che una ATTIVITÀ mostra un'altra ATTIVITÀ Non ci sono frammenti coinvolti.Inoltre il tema del DialogTestActivity deve essere impostato su @ style/PopupTheme nel manifest di App. Altrimenti il ​​Dialog/Popup non verrà mostrato correttamente –

0

So che non è una risposta reale, ma soprattutto le soluzioni sembrano così poco eleganti che si potrebbe pensare che sarebbe più semplice evitare la barra di azione, come ereditare il tema di dialogo da qualcosa con .noActionBar e quindi creare la vista sul parte superiore del pannello che imita la barra delle azioni, almeno in questo modo rimane tutto in xlm.

+0

Se per inelegante, vuoi dire troppo hardcoded, eccoti : 'DisplayMetrics metrics = new DisplayMetrics(); \t \t getWindowManager(). GetDefaultDisplay(). GetMetrics() metrica); \t \t getWindow(). SetLayout (metrics.widthPixels - 80, metrics.heightPixels - 80); ' – LoungeKatt

0

Ho trovato un buon modo per farlo, utilizzando setCustomTitle sul builder della finestra di dialogo di avviso per il DialogFragment (possibile anche sul segnalatore di avvisi stesso).

public Dialog onCreateDialog(final Bundle savedInstanceState) { 
    final AlertDialog.Builder builder = new AlertDialog.Builder(activity,...); 
    final Toolbar toolbar = (Toolbar) inflater.inflate(R.layout.dialog_app_filter_toolbar, null, false); 
    // <= prepare toolbar and dialog here 
    return builder.create(); 
    } 

E il risultato (da my app):

enter image description here

enter image description here

Se non si desidera utilizzare AlertDialog, è ancora possibile solo mettere una barra degli strumenti nel layout di il dialogo e usalo.