-
Notifications
You must be signed in to change notification settings - Fork 554
5.x | ActionModeHelper
- Introduction
- Configuration & Initialization
- Simple selection (IDLE)
- Single selection (SINGLE)
- Multi selection (MULTI)
- Handling rotation
selectAll()
andclearSelection()
This Helper incredibly simplifies the development of the ActionMode
. With this helper it has never been so easy to start and manage the ActionMode
.
From Android®️ suggestion I decided to use view Activation state instead of view Selection state as others libraries mistakenly apply:
A view can be activated or not. Note that activation is not the same as selection. Selection is a transient property, representing the view (hierarchy) the user is currently interacting with.
Activation is a longer-term state that the user can move views in and out of. For example, in a list view with single or multiple selection enabled, the views in the current selection set are activated. (Um, yeah, we are deeply sorry about the terminology here.) The activated state is propagated down to children of the view it is set on.
eu.davidea.flexibleadapter.helpers
|_ ActionModeHelper
No XML configuration option is recommended.
You can now call the new DrawableUtils
static methods to compose dynamic backgrounds, see wiki page Utils. You don't need XML anymore.
From the Activity, initialize the ActionMode
as following:
public class MainActivity extends AppCompatActivity implements
ActionMode.Callback,
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener {
private FlexibleAdapter<IFlexible> mAdapter;
private ActionModeHelper mActionModeHelper;
private void initializeActionModeHelper(@Mode int mode) {
//this = ActionMode.Callback instance
mActionModeHelper = new ActionModeHelper(mAdapter, R.menu.menu_context, this) {
// Override to customize the title
@Override
public void updateContextTitle(int count) {
// You can use the internal mActionMode instance
if (mActionMode != null) {
mActionMode.setTitle(count == 1 ?
getString(R.string.action_selected_one, count) :
getString(R.string.action_selected_many, count));
}
}
}.withDefaultMode(mode);
}
}
The ActionMode.Callback
has to continue to be implemented in the Activity:
// Change the status bar color when ActionMode is starting and ending
public boolean onCreateActionMode(ActionMode mode, Menu menu);
public void onDestroyActionMode(ActionMode mode);
// Adjust and handle the Context menu
public boolean onPrepareActionMode(ActionMode mode, Menu menu);
public boolean onActionItemClicked(ActionMode mode, MenuItem item);
ℹ️ Note: Check the code @ MainActivity#908
ℹ️ Note: Make sure the
onItemClick
&onItemLongClick
are triggered by adding the overriden methods to the listener
mAdapter.addListener(this);
Mode IDLE is the default value at the start up. However to switch from another mode to IDLE, write the following statements and change the default mode as well:
// from SINGLE to IDLE
import eu.davidea.flexibleadapter.SelectableAdapter.Mode;
mAdapter.setMode(Mode.IDLE);
mActionModeHelper.withDefaultMode(Mode.IDLE);
When you need to switch mode from IDLE to SINGLE and change the default mode as well:
// from IDLE to SINGLE
import eu.davidea.flexibleadapter.SelectableAdapter.Mode;
mAdapter.setMode(Mode.SINGLE);
mActionModeHelper.withDefaultMode(Mode.SINGLE);
Single selection can work in conjunction with ActionMode
for Multi selection. See Multi selection (MULTI) below here to know how they can work together.
In the method mActionModeHelper.onClick()
the modes SINGLE and MULTI are handled automatically! 👍
@Override
public boolean onItemClick(int position) {
// Action on elements are allowed if Mode is IDLE, otherwise selection has priority
if (mAdapter.getMode() != Mode.IDLE && mActionModeHelper != null) {
boolean activate = mActionModeHelper.onClick(position);
// Last activated position is now available
Log.d(TAG, "Last activated position " + mActionModeHelper.getActivatedPosition());
return activate;
} else {
// Handle the item click listener
...
// We don't need to activate anything
return false;
}
}
@Override
public void onItemLongClick(int position) {
mActionModeHelper.onLongClick(this, position);
}
When it is needed, the following methods are very useful. For example, after items have been deleted OR a restoration is performing OR the button back has been pressed (onBackPressed()
).
// To restore the selection after a restoration
if (mAdapter.isRestoreWithSelection()) {
mActionModeHelper.restoreSelection(this);
}
// Finish the action mode
mActionModeHelper.destroyActionModeIfCan();
// New title for context
mActionModeHelper.updateContextTitle(mAdapter.getSelectedItemCount());
ℹ️ Note: With version 5.x the ViewHolder automatically handles the view activation. Check the wiki page ViewHolders for more details.
Optionally, you can now set View Elevation for the activation, API compatibility is maintained.
/**
* Allows to set elevation while the view is activated.
* Override to return desired value of elevation on this itemView.
*
* @return never elevate, returns 0dp if not overridden
*/
public float getActivationElevation() {
return 0f;
}
ℹ️ Note: Also the binding of the selection status (when user scrolls) is automatically handled by the Adapter, you don't have to call any view activation. This is an extract of the pre-implemented
onBindViewHolder()
:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {
//When user scrolls, this line binds the correct selection status
holder.itemView.setActivated(isSelected(position));
...
}
Preserve the current selection state, together with other flags:
@Override
public void onSaveInstanceState(Bundle outState) {
mAdapter.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
Restore the previous selection state:
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore previous state
if (savedInstanceState != null && mAdapter != null) {
//Selection
mAdapter.onRestoreInstanceState(savedInstanceState);
mActionModeHelper.restoreSelection(this);
}
}
⚠️ Note: Pay attention to re-initialize the adapter with previous elements, before restoring the selection! More details in issue #581.
No more notifyItemRangeChanged()
in selectAll()
and clearSelection()
methods: This means no more item binding!
Now, bound selectable ViewHolders will have the StateListDrawable
background switching status (activated/normal) when invoking internally FlexibleViewHolder.toggleSelection()
, so that, all inner views can complete animations with no interruptions.
ℹ️ Note:
- The cached ViewHolders are removed when they are recycled by the RecyclerView.
- The ViewHolders must extend
FlexibleViewHolder
, otherwise, item binding still occurs.
- Update Data Set
- Selection modes
- Headers and Sections
- Scrollable Headers and Footers
- Expandable items
- Drag&Drop and Swipe
- EndlessScroll / On Load More
- Search Filter
- FastScroller
- Adapter Animations
- Third party Layout Managers
- Payload
- Smooth Layout Managers
- Flexible Item Decoration
- Utils
- ActionModeHelper
- AnimatorHelper
- EmptyViewHelper
- UndoHelper
* = Under revision!