web-dev-qa-db-fra.com

ActionBar dans un DialogFragment

Dans l'application Calendrier de ma Galaxy Tab 10.1, lors de la création d'un nouvel événement, une boîte de dialogue apparaît avec les boutons Terminé et Annuler dans la zone de barre de titre/barre d'action.

enter image description here

J'aimerais implémenter cela dans mon application. J'ai essayé d'utiliser setHasOptionsMenu(true) en plus de remplacer onCreateOptionsMenu dans ma sous-classe DialogFragment, mais mes éléments d'action n'apparaissent pas. J'ai également essayé d'appeler getDialog().getActionBar() depuis onCreateView mais il renvoie toujours null.

Je suis capable de faire fonctionner cela si je démarre un Activity plutôt que d'afficher une boîte de dialogue mais qui occupe tout l'écran. Existe-t-il un moyen standard de le faire en utilisant un DialogFragment?

46
Paul Blessing

en utilisant l'idée d'un message du groupe Google J'ai pu le retirer en stylisant une activité. vous voudriez modifier la hauteur et la largeur à une taille "dynamique" de votre choix de préférence. Ensuite, définissez les boutons ActionBar que vous souhaitez

<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);
}
86
StrikeForceZero

Si vous utilisez ActionBarSherlock, déclarez le thème comme ci-dessous:

<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>

Et, initialisez un SherlockActivity avec PopupTheme selon réponse de Luke Sleeman .

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);
}

Résultat:

enter image description here

14
nagoya0

J'ai eu du mal à implémenter les solutions suggérées par StrikeForceZero et Luke Sleeman, alors je voulais apporter mon expérience. Je suis sûr qu'il manque quelque chose, donc les commentaires seraient très appréciés.

Ce que j'ai fait était le suivant:

  1. Créez un style à l'aide du PopupTheme fourni, copiez/collez directement:

    <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. Ajoutez la méthode showAsPopup () en tant que méthode dans le fragment qui ouvrirait le faux fragment de dialogue, copier/coller simple:

    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. Créez une instance de la nouvelle activité à l'aide d'un simple appel new (), puis passez-la à la méthode showAsPopup ():

    DialogTestActivity test = new DialogTestActivity();
    showAsPopup(test);
    
  4. Aux fins du test (j'essayais simplement de confirmer que je pouvais ouvrir une activité présentée sous forme de dialogue avec une barre d'action), j'ai utilisé un test extrêmement simple, volé directement dans la démo de l'API de la vue des boutons (pour le fichier de mise en page , voir buttons_1.xml dans les démos api):

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

Malheureusement, chaque fois que j'essaye, j'obtiens une exception de pointeur nul non spécifié lors du tout premier appel, 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)

Comme vous pouvez le voir sur la trace de la pile, le comportement prévu est d'ouvrir la fenêtre en appuyant longuement sur une instance de GoogleMap (en utilisant les MapFragments de l'API 2). Donc, ma première pensée a été qu'il y avait un problème en essayant d'ouvrir à partir d'un fragment, alors j'ai renvoyé l'appel à l'activité propriétaire. Même erreur, même aucune information supplémentaire.

Ma meilleure supposition à ce stade était qu'un nouvel appel () n'a pas suffisamment instancié la classe/vue pour effectuer des appels afin de modifier sa vue. Il s'avère que cela semble être au moins quelque peu vrai, car la migration du code de modification de la vue dans l'activité et l'ouverture simple de l'activité de la manière normale fonctionnent:

Activité d'appel:

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

Nouveau code de 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);
        }
    }

Donc, je suppose que le but de moi de poster tout cela est de clarifier que si vous voulez faire ce que les affiches ci-dessus suggèrent, vous ne pouvez pas simplement new () une activité et appeler showAsPopup (). Cela peut être mon inexpérience avec Android montrant à travers, mais bien que cela semble un peu évident, il semble également naturel d'interpréter showAsPopup () comme étant appelé par la vue actuelle, pas la vue en cours de création, lorsque vous passez dans l'instance d'activité (qui serait juste ceci si cela devait être fait dans onCreate () comme je l'ai fini par faire) .

Donc, si l'intention est d'appeler showAsPopup () dans l'activité créant et non pas créé activité, il n'est pas évident de savoir comment obtenir l'instance Activity qui est modifiable avant d'appeler onCreate (). Le problème étant que vous ne pouvez pas appeler des choses comme requestWindowFeature () après que setContentView () soit appelé ( exemple ), ce qui est un problème car il est généralement appelé dans onCreate ().

Encore une fois, s'il existe un moyen facile/meilleur de le faire, j'apprécierais beaucoup les commentaires. J'espère que cela sera utile pour les personnes qui souhaitent utiliser cette approche.

11
user1475907

J'ai passé un temps incroyable à jouer avec ça. La réponse acceptée fonctionne sur un Galaxy Nexus 7 (Android 4.2), mais échoue sur un Samsung Galaxy SIII (Android 4.1) et un onglet Samsung Galaxy 10.2 (Android 4.0), à l'exception suivante:

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

Cela est dû au code dans ActionBarView.onMeasure (int, int) qui vérifie que la disposition est définie sur match_parent. La solution correcte consiste à définir la largeur de la fenêtre via setLayout au lieu d'utiliser setAttributes.

Il s'agit d'une version fixe de showAsPopup () qui fonctionne sur tous les appareils sous lesquels j'ai testé:

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);
}

Par souci d'exhaustivité, voici à nouveau le PopupTheme:

<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>
4
Luke Sleeman

Je ne suis probablement pas très expérimenté dans ce domaine, mais j'utiliserais une activité, ajouterais des éléments de barre d'action et ensuite:

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

J'espère que cela pourra aider!

1
Maxwell Weru

Comme Veeti l'a laissé entendre, vous pouvez essayer d'implémenter une activité avec un thème de dialogue. Dans le Android Manifest:

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

J'espère que cela vous aidera.

1
Swifty McSwifterton

J'ai trouvé une belle façon de le faire, en utilisant setCustomTitle sur le constructeur de alertDialog pour DialogFragment (également possible sur alertDialog lui-même).

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();
    }

Et le résultat (de mon application ):

enter image description here

enter image description here

Si vous ne souhaitez pas utiliser AlertDialog, vous pouvez toujours simplement mettre une barre d'outils dans votre disposition de la boîte de dialogue et l'utiliser.

1
android developer

Je sais que ce n'est pas une vraie réponse, mais les solutions ci-dessus semblent si inélégantes que l'on pourrait penser qu'il serait plus facile d'éviter la barre d'action, comme hériter votre thème de dialogue de quelque chose avec .noActionBar, puis créer une vue en haut de votre panneau qui imite la barre d'action, au moins de cette façon, tout reste en xlm.

0
mariubog