onPrepareActionMode wird beim Erstellen von ActionMode nicht aufgerufen


79

Ich habe gerade eine meiner Apps an die neuen v22.1.1-Support- und Appcompat-Bibliotheken angepasst. Weitere Informationen finden Sie hier und hier . Als ich einige Tests durchgeführt habe, war mit den von mir verwendeten ActionModes etwas nicht in Ordnung .

Wenn Sie einen ActionMode mit einem startSupportActionMode()Aufruf starten - es spielt keine Rolle, ob Sie die jetzt veraltete ActionBarActivity- Basisklasse oder die neue AppCompatActivity- Basisklasse verwenden - onPrepareActionMode()wird dieser nicht aufgerufen.

In früheren Versionen, einschließlich v21.0.3 und v22.0.0, onPrepareActionMode()wurde automatisch aufgerufen, als der ActionMode ursprünglich mit erstellt wurde startSupportActionMode().

Ich habe es auf einem 2.2-, 4.4.2- und 5.0-Gerät getestet, daher scheint es nicht versionabhängig zu sein.

Weiß jemand, ob dies beabsichtigtes Verhalten ist, das in Version 22.1.1 eingeführt wurde, oder ein Fehler?

Ich habe dieses Problem gefunden , aber hier gibt es nicht viel Feedback ...

Bearbeiten 11. Mai 2015:

Wie im Android Issue Tracker 159527 erwähnt , betrifft dieses Problem nicht nur die Version 22.1.x von Appcompat und die Support-Bibliothek, sondern auch die 5.1-Android-Implementierung.

Derzeit zwei mögliche vorübergehende Lösungen, eine allgemeine:

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

und eine "schnelle und schmutzige" (wenn Sie Ihren ActionMode instanziieren):

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

Wenn Sie nicht appcompat verwenden ( ActionBarActivity/ AppCompatActivity) müssen Sie ersetzen startSupportActionMode()mit startActionMode().

Leider ist immer noch nicht klar, ob dies ein neues Verhalten oder ein Fehler ist. Laut API-Dokument handelt es sich um einen Fehler / eine Regression, aber wer weiß ...


Ich stimme dir zu - das ist ein Fehler. Ich bin nur darauf gestoßen und habe einige Zeit mit dem Debuggen verbracht, nur um herauszufinden, dass onPrepare ... nicht mehr aufgerufen wird. In meinem Fall denke ich, dass es funktionieren wird, einfach meinen gesamten onPrepare ... Code auf onCreate zu portieren ...
Peri Hartman

10
@darksaga: Sie sollten Ihre Bearbeitung in eine Antwort umwandeln und akzeptieren :)
Vicky Chijwani

Antworten:


1

Ich habe eine Demo erstellt und sie funktioniert einwandfrei. OnPrepareActionMode wird jedes Mal aufgerufen, wenn der Aktionsmodus angezeigt wird. Wird immer nach onCreateActionMode aufgerufen, kann jedoch mehrmals aufgerufen werden, wenn der Modus ungültig ist. [ Ich fordere jemanden auf, eine kleine Änderung vorzunehmen. Ich benötige die Farbe der Statusleiste wie die der Symbolleiste, aber dynamisch kann man sehen, dass unnötiges Schubladenlayout verwendet wird, um diesen Effekt zu erzielen. Wenn ich jedoch das Schubladenlayout entferne, ändert sich die Farbe der Statusleiste nicht entsprechend der Symbolleistenfarbe. Im Dienstprogramm wird standardmäßig angezeigt, dass die Designfarbe rot ist. Die Symbolleiste erhält zunächst die rote Farbe, die Statusleiste jedoch nicht, nur und nur, wenn ich das Schubladenlayout entferne. Ich muss das mit Stil machen. ] Erstellen Sie ein Ressourcenlayout und nennen Sie es => 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>

Erstellen Sie eine Aktivität mit dem Namen 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;
    }
}

// Utils-Klasse mit Methode zum Ändern des Themas // Ich habe sie erstellt, weil das App-Design dynamisch geändert werden muss. Import 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-theme.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>

0

Ich hatte ein ähnliches Problem.

Nachdem ich den Wert von "compileSdkVersion" und "buildToolsVersion" von build.gradle erhöht hatte, stellte ich fest, dass onPrepareActionMode nicht aufgerufen wurde.

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

Also habe ich meinen Code von (A) nach (B) verschoben. (siehe unten)

Ich bin nicht sicher, ob es die richtige Lösung ist, aber es funktioniert.

Hier ist der Auszug meines Codes.

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;
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.