web-dev-qa-db-fra.com

onPrepareActionMode non appelé lors de la création d'ActionMode

Je viens de terminer l'adaptation de l'une de mes applications au nouveau support v22.1.1 et aux bibliothèques compatibles avec les applications, voir ici et ici pour plus de détails. Quand j'ai fait quelques tests, quelque chose n'allait pas avec les ActionModes que j'utilise.

Lorsque vous démarrez un ActionMode à l'aide d'un appel startSupportActionMode() - peu importe si vous utilisez la classe de base désormais obsolète ActionBarActivity ou la nouvelle AppCompatActivity classe de base - onPrepareActionMode() n'est pas appelée.

Dans les versions précédentes, y compris v21.0.3 et v22.0.0, onPrepareActionMode() était appelée automatiquement, lorsque l'ActionMode était initialement créé à l'aide de startSupportActionMode().

Je l'ai testé sur un appareil 2.2, 4.4.2 et 5.0, il ne semble donc pas dépendre de la version.

Est-ce que quelqu'un sait, s'il s'agit d'un comportement voulu, qui a été introduit dans la version 22.1.1, ou un bogue?

J'ai trouvé cela problème , mais il n'y a pas beaucoup de commentaires ici ...

Modifier le 11 mai 2015:

Comme mentionné dans Android issue tracker 159527 , ce problème affecte non seulement la v22.1.x de appcompat et la bibliothèque de support, mais également l'implémentation 5.1 Android Android).

Deux solutions temporaires possibles pour le moment, une générale:

@Override
public ActionMode startSupportActionMode(final ActionMode.Callback callback) {
  // Fix for bug https://code.google.com/p/Android/issues/detail?id=159527
  final ActionMode mode = super.startSupportActionMode(callback);
  if (mode != null) {
    mode.invalidate();
  }
  return mode;
}

et un "rapide et sale" (lorsque vous instanciez votre ActionMode):

final ActionMode actionMode = startSupportActionMode(new MyActionMode());
if(actionMode != null) {
    actionMode.invalidate();
}

Si vous n'utilisez pas appcompat (ActionBarActivity/AppCompatActivity), vous devez remplacer startSupportActionMode() par startActionMode().

Malheureusement, il n'est toujours pas clair s'il s'agit d'un nouveau comportement ou d'un bug. Selon le API doc c'est un bug/régression, mais qui sait ...

79
darksaga

J'ai créé une démo et son bon fonctionnement, onPrepareActionMode est appelé à chaque fois que le mode d'action est affiché. Toujours appelé après onCreateActionMode, mais peut être appelé plusieurs fois si le mode est invalidé. [Je demande à quiconque de faire une petite modification. J'ai besoin de la couleur de la barre d'état identique à celle de la barre d'outils, mais dynamiquement, vous pouvez voir que la disposition inutile de Drawyer est utilisée pour obtenir cet effet, mais si je supprime la disposition de Drawyer, la barre d'état la couleur ne change pas en fonction de la couleur de la barre d'outils. Dans l'utilitaire, vous pouvez voir par défaut la couleur du thème par défaut est rouge, la barre d'outils obtient d'abord la couleur rouge mais pas la barre d'état, seulement et seulement si je supprime la disposition de Drawyer. Je dois le faire en utilisant le style.] Créez une disposition de ressource et nommez-la => action_mode_activity

<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/my_drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true">

        <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
            xmlns:app="http://schemas.Android.com/apk/res-auto"
            xmlns:tools="http://schemas.Android.com/tools"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:fitsSystemWindows="true"
            Android:orientation="vertical"
            app:insetForeground="#4000">

            <include
                Android:id="@+id/toolbar"
                layout="@layout/toolbar" />

            <EditText
                Android:id="@+id/editTextCopy"
                Android:layout_width="fill_parent"
                Android:layout_height="40dp"
                Android:layout_marginTop="19dp"
                Android:ems="10"
                Android:inputType="textMultiLine"
                Android:text="Long click to share!">

                <requestFocus />
            </EditText>
        </LinearLayout>

</Android.support.v4.widget.DrawerLayout>

Créez une activité nommez-la ActionModeActivity

import Android.os.Build;
import Android.os.Bundle;
import Android.support.v7.app.ActionBar;
import Android.support.v7.app.AppCompatActivity;
import Android.support.v7.widget.Toolbar;
import Android.view.ActionMode;
import Android.view.Menu;
import Android.view.MenuInflater;
import Android.view.MenuItem;
import Android.view.View;
import Android.widget.EditText;
import Android.widget.Toast;

import com.example.deepakpawar.demolearning.R;
import com.example.deepakpawar.demolearning.demo.load.recycler.Utils;

/**
 * Created by Deepak Pawar on 9/24/2015.
 */
public class ActionModeActivity extends AppCompatActivity implements View.OnLongClickListener, ActionMode.Callback {

    EditText editTextCopy;
    Android.view.ActionMode mActionMode;
    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Utils.onActivityCreateSetTheme(this);
        setContentView(R.layout.action_mode_activity);

        // 1. Get the editText
        editTextCopy = (EditText) findViewById(R.id.editTextCopy);

        // 2. add long-click listener
        editTextCopy.setOnLongClickListener(this);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            ActionBar actionBar = getSupportActionBar();
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
            actionBar.setTitle("Android Students");
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {

            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        } 
    }

    @Override
    public boolean onLongClick(View view) {

        // if actionmode is null "not started"
        if (mActionMode != null) {
            return false;
        }
        // Start the CAB
        mActionMode = this.startActionMode(this);
        view.setSelected(true);
        return true;

    }

    // 4. Called when the action mode is created; startActionMode() was called
    @Override
    public boolean onCreateActionMode(Android.view.ActionMode mode, Menu menu) {

        // Inflate a menu resource providing context menu items
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.action_menu, menu);
        return true;
    }

    // 5. Called when the user click share item
    @Override
    public boolean onActionItemClicked(Android.view.ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_share:
                Toast.makeText(this, "Shared!", Toast.LENGTH_SHORT).show();

                mode.finish(); // Action picked, so close the CAB
                return true;
            default:
                return false;
        }
    }

    // 6. Called each time the action mode is shown. Always called after onCreateActionMode, but
    // may be called multiple times if the mode is invalidated.
    @Override
    public boolean onPrepareActionMode(Android.view.ActionMode mode, Menu menu) {

        Toast.makeText(ActionModeActivity.this,"onPrepareActionMode Called ",Toast.LENGTH_SHORT).show();
        return false; // Return false if nothing is done
    }

    // 7. Called when the user exits the action mode
    @Override
    public void onDestroyActionMode(Android.view.ActionMode mode) {
        mActionMode = null;
    }
}

// Classe Utils ayant une méthode pour changer de thème // Je l'ai créée parce que je dois changer dynamiquement le thème de l'application importation Android.app.Activity;

public class Utils {
    private static int sTheme;
    public final static int THEME_DEFAULT = 0;
    public final static int THEME_WHITE = 1;
    public final static int THEME_BLUE = 2;

    /**
     * Set the theme of the Activity, and restart it by creating a new Activity of the same type.
     */

    public static int getsTheme() {
        return sTheme;
    }

    public static void changeToTheme(Activity activity, int theme) {
        sTheme = theme;
        activity.recreate();
//        activity.finish();
//        activity.startActivity(new Intent(activity, activity.getClass()));
    }

    /**
     * Set the theme of the activity, according to the configuration.
     */
    public static void onActivityCreateSetTheme(Activity activity) {
        switch (sTheme) {
            default:
            case THEME_DEFAULT:
                activity.setTheme(R.style.FirstTheme);
                break;
            case THEME_WHITE:
                activity.setTheme(R.style.SecondTheme);
                break;
            case THEME_BLUE:
                activity.setTheme(R.style.Thirdheme);
                break;
        }
    }
}

v21-themes.xml

<resources>

    <style name="AppTheme" parent="AppTheme.Base">
        <item name="Android:windowContentTransitions">true</item>
        <item name="Android:windowAllowEnterTransitionOverlap">true</item>
        <item name="Android:windowAllowReturnTransitionOverlap">true</item>
        <item name="Android:windowSharedElementEnterTransition">@Android:transition/move</item>
        <item name="Android:windowSharedElementExitTransition">@Android:transition/move</item>

        <item name="Android:actionOverflowButtonStyle">@style/Widget.ActionButton.Overflow</item>
       <!-- <item name="Android:navigationBarColor">@color/PrimaryColor</item>-->

        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>

        <!-- To Make Navigation Drawer Fill Status Bar and become Transparent Too -->
        <item name="Android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="Android:statusBarColor">@Android:color/transparent</item>


<!--//if darker status bar needed-->
       <!-- <item name="Android:windowTranslucentStatus">true</item>-->
    </style>


    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/PrimaryColor</item>
        <item name="colorPrimaryDark">@color/PrimaryDarkColor</item>
        <item name="colorAccent">@color/AccentColor</item>
        <item name="Android:textColorPrimary">@color/TextPrimaryColor</item>
        <item name="Android:windowBackground">@color/WindowBackground</item>
    </style>

    <style name="Widget.ActionButton.Overflow" parent="@Android:style/Widget.Holo.ActionButton.Overflow">
        <item name="Android:contentDescription">@string/accessibility_overflow</item>
    </style>


    <!-- style for the tool bar backgrounds -->
    <style name="ToolBarStyle" parent="ToolBarStyle.Base" />

    <style name="ToolBarStyle.Base" parent="">
        <item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
        <item name="theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
    </style>

    <style name="ToolBarStyle.Event" parent="ToolBarStyle">
        <item name="titleTextAppearance">@style/TextAppearance.Widget.Event.Toolbar.Title</item>
    </style>

    <style name="TextAppearance.Widget.Event.Toolbar.Title" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
        <!--Any text styling can be done here-->
        <item name="Android:textStyle">normal</item>
        <item name="Android:textSize">18sp</item>
        <item name="Android:textColor">#000000</item>
    </style>

    <!-- Customize your theme example here. -->

    <style name="FirstTheme">
        <item name="Android:textColor">#FF0000</item>
        <item name="colorPrimary">#FF0000</item>
        <item name="colorPrimaryDark">#ff0000</item>
        <item name="colorAccent">#ff0087</item>
        <item name="Android:shadowColor">#00ccff</item>
        <item name="Android:shadowRadius">1.5</item>
        <item name="Android:shadowDy">1</item>
    </style>

    <style name="SecondTheme">
        <item name="Android:textColor">#00FF00</item>
        <item name="colorPrimary">#00FF00</item>
        <item name="colorPrimaryDark">#00FF00</item>
        <item name="colorAccent">#00FF90</item>
        <item name="Android:shadowColor">#00ccff</item>
        <item name="Android:shadowRadius">1.5</item>
        <item name="Android:shadowDy">1</item>
    </style>

    <style name="Thirdheme">
        <item name="Android:textColor">#0000F0</item>
        <item name="colorPrimary">#0000F0</item>
        <item name="colorPrimaryDark">#0000F0</item>
        <item name="colorAccent">#0090F0</item>
        <item name="Android:shadowColor">#00ccff</item>
        <item name="Android:shadowRadius">1.5</item>
        <item name="Android:shadowDy">1</item>
    </style>


    <style name="AppCompatAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
        <item name="colorAccent">#FFCC00</item>
        <item name="Android:textColorPrimary">#FFFFFF</item>
        <item name="Android:background">#5fa3d0</item>
    </style>

</resources>
1
DeepakPanwar

J'avais un problème similaire.

Après avoir augmenté la valeur de "compileSdkVersion" et "buildToolsVersion" de build.gradle, j'ai découvert que onPrepareActionMode n'était pas appelé.

  • compileSdkVersion: 21 à 26
  • buildToolsVersion: 21.1.2 à 26.0.2

J'ai donc déplacé mon code de (A) vers (B). (voir ci-dessous)

Je ne sais pas si c'est la bonne solution, mais cela fonctionne.

Voici l'extrait de mon code.

list1 = findViewById(R.id.listView1);

list1.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        //(A)
        //MenuItem menuItem1 = menu.findItem(R.id.menu_item1);
        //menuItem1.setVisible(false);
        return false;
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_action_mode, menu);

        //(B)
        MenuItem menuItem1 = menu.findItem(R.id.menu_item1);
        menuItem1.setVisible(false);

        return true;
    }
0
Sankame