Właśnie skończyłem dostosowywać jedną z moich aplikacji do nowej obsługi i bibliotek appcompat w wersji 22.1.1. Więcej informacji znajdziesz tutaj i tutaj . Kiedy przeprowadzałem testy, coś było nie tak z ActionModes, których używam.
Gdy uruchamiasz ActionMode za pomocą startSupportActionMode()
wywołania - nie ma znaczenia, czy używasz obecnie przestarzałej klasy bazowej ActionBarActivity, czy nowej klasy bazowej AppCompatActivity - onPrepareActionMode()
nie jest wywoływana.
We wcześniejszych wersjach, w tym 21.0.3 i 22.0.0, onPrepareActionMode()
był wywoływany automatycznie, gdy tryb ActionMode był początkowo tworzony przy użyciu startSupportActionMode()
.
Przetestowałem to na urządzeniu 2.2, 4.4.2 i 5.0, więc wydaje się, że nie zależy to od wersji.
Czy ktoś wie, czy jest to zamierzone zachowanie, które zostało wprowadzone w wersji 22.1.1 lub błąd?
Znalazłem ten problem , ale nie ma tu wielu opinii ...
Edycja 11 maja 2015 r .:
Jak wspomniano w narzędziu do śledzenia problemów systemu Android 159527 , problem ten dotyczy nie tylko wersji 22.1.x programu appcompat i biblioteki obsługi, ale także implementacji systemu Android 5.1.
W tej chwili możliwe są dwa rozwiązania tymczasowe, jedno ogólne:
@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;
}
i `` szybki i brudny '' (podczas tworzenia instancji ActionMode):
final ActionMode actionMode = startSupportActionMode(new MyActionMode());
if(actionMode != null) {
actionMode.invalidate();
}
Jeśli nie używać AppCompat ( ActionBarActivity
/ AppCompatActivity
) trzeba wymienić startSupportActionMode()
z startActionMode()
.
Niestety nadal nie jest jasne, czy jest to zamierzone nowe zachowanie, czy błąd. Zgodnie z dokumentacją API jest to błąd / regresja, ale kto wie ...
Odpowiedzi:
Stworzyłem demo i działa dobrze, onPrepareActionMode jest wywoływany za każdym razem, gdy wyświetlany jest tryb akcji. Zawsze wywoływana po onCreateActionMode, ale może być wywoływana wiele razy, jeśli tryb jest unieważniony. [ Proszę każdego o małą zmianę. Potrzebuję koloru paska stanu takiego samego jak pasek narzędzi, ale dynamicznie widać, że do osiągnięcia tego efektu używany jest niepotrzebny układ Drawyer, ale jeśli usunę układ szuflady, kolor paska stanu nie zmienia się w zależności od koloru paska narzędzi. W narzędziu możesz zobaczyć, że domyślnym kolorem motywu jest czerwony, pasek narzędzi początkowo ma kolor czerwony, ale pasek stanu nie, tylko i tylko wtedy, gdy usunę układ szuflady. Muszę to zrobić za pomocą stylu. ] Utwórz układ zasobów i nazwij go => 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>
Utwórz działanie, nadaj mu nazwę 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; } }
// Klasa Utils z metodą zmiany motywu // Utworzyłem ją, ponieważ muszę dynamicznie zmieniać motyw aplikacji 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-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>
źródło
Miałem podobny problem.
Po podwyższeniu wartości „compileSdkVersion” i „buildToolsVersion” build.gradle, okazało się, że onPrepareActionMode nie został wywołany.
Więc przeniosłem swój kod z (A) do (B). (patrz poniżej)
Nie jestem pewien, czy to właściwe rozwiązanie, ale działa.
Oto fragment mojego kodu.
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; }
źródło