Android ActionBar options long click event - android

Android Can anyone know about Actionbar item options long click , I want to show text on LongClick on actionbar menu option like a hint on long press of actionBar long press

Do you want to capture long press on menu item on action bar? As for me, after finding 2,3 hour, I found this solution. This is perfectly work for me.
#Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
new Handler().post(new Runnable() {
#Override
public void run() {
final View v = findViewById(R.id.action_settings);
if (v != null) {
v.setOnLongClickListener(new CustomLongOnClickListener());
}
}
});
return true;
}

For me, the following approach works fine for newer Android versions - I tested it with Android 4.2 and Android 5.0.1.
The idea is that I replace the action icon view by a custom view. Here, I have to handle the single click, and I can handle the long click.
If I want the appearance to be exactly like normal action bar icons, the following works.
First, create a layout containing just an ImageButton with your icon.
<?xml version="1.0" encoding="utf-8"?>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myButton"
style="?android:attr/actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#layout/text_view_initializing"
android:src="#drawable/ic_action_plus" />
Then put this ImageButton into the action bar and attach listeners to it.
MenuItem myItem = menu.findItem(R.id.my_action);
myItem.setActionView(R.layout.my_image_button);
myItem.getActionView().setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
// here, I have to put the stuff that normally goes in onOptionItemSelected
}
});
myItem.getActionView().setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(final View v) {
// here, I put the long click stuff
}
});
Important remark: this will only work if the item appears in the action bar. So, whatever you want to do on long click will not be accessible in this way if the option appears in the menu dropdown.

user1206890, you do not need listen long click event. If you want show action hint, will be sufficient set title in menu add. Checked on 2.3 and 4.0.

If you create your own action view via android:actionLayout, you are welcome to set up listeners on your own widgets for long-click events. You do not have access to widgets in the action bar that you do not create yourself.

I think "findViewById" is the easiest way to find.
Just do
View action_example = findViewById(R.id.action_example);
if(action_example!=null)action_example.setOnLongClickListener(
new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(MainActivity.this, "action_example", Toast.LENGTH_SHORT).show();
return true;
}
}
);

This is the code of function that works with me thanks to #YeeKhin
change "main" to your menu name and "action_refresh" to your action name and "Activity" to your activity name
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
new Handler().post(new Runnable() {
#Override
public void run() {
final View v = findViewById(R.id.action_refresh);
if (v != null) {
v.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(Activity.this,"Long Press!!",Toast.LENGTH_LONG).show();
return false;
}
});
}
}
});
return true;
}

Related

How to hide ActionPopupWindow of Text Selection Handler of EditText

Actually I want to hide ActionPopupWindow (popup having SELECT ALL, CLIPBOARD options) when user click on + icon(refer to the attached image).
ActionPopupWindow appears when user click on the Text Selection Handler(bubble) (which appears when user tap on the text in the EditText).
I have tried to use setTextIsSelectable() method of EditText but it is not working consistently.
Any help or guidance will be well appreciated.
UPDATE: To hide the Popup already opened and showing on the screen, you need to clear focus of the current EditText or focus on other view when you clicked the plus button. See the
example below:
iconPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
yourEditText.clearFocus();
}
});
If you want the popup never shows up at the first place, there are many ways to do it.
The simplest way is disabling long click and selection feature:
yourEditText.setLongClickable(false);
yourEditText.setTextIsSelectable(false);
Second one is overriding action callback actions on your edittext:
yourEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
You can use them separately or together according to your case.
Also you can check other options from here

Remove CAB but preserve webview text selection

I want to implement my own custom view (not inflating a menu item), I'm planning to use a toolbar to appear each time contextMenu starts, and hide it when finished.
the problem is: there are only answer showing HOW to clear/inflate another menu over the default actionMode menu
what i`ve tried so far:
-> Use a custom contextual action bar for WebView text selection
Overriding the callback at the WebView
#Override
public ActionMode startActionMode(ActionMode.Callback callback) {
callback2 = new customCallBack();
return super.startActionMode(callback2);
}
public class customCallBack implements ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
}
changing the return false to true, doesn't result in the desired behavior i.e. hide the cab
Overriding the OnLongClick is not a option too, since it disable the current selection.
This answer solves the problem:
android webview: prevent text selection actionMode actionBar
not the most elegant solution ever, but I just tested it in an app I'm building and it works like a charm.
The Only way that worked for me (only on on Android L+) is clearing all the menu items from context actionbar from the activity
#Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
}
Toast.makeText(this, "onActionModeStarted", Toast.LENGTH_SHORT).show();
super.onActionModeStarted(mode);
}
#Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
Toast.makeText(this, "onActionModeFinished", Toast.LENGTH_SHORT).show();
super.onActionModeFinished(mode);
}
inspired by Use a custom contextual action bar for WebView text selection
Also I wasn't able to implement the custom menu usin popupWindow or dialogs or dialog fragments.
So simply put it with the webView in a frame layout and play with its visability and margin

setOnLongClickListener on framelayout not working as expected

Bellow mentioned is the code where i am registering framelayout for long click listener event.
private void createActivityLayout(Fragment fragment)
{
FrameLayout frameLayout = (FrameLayout)getLayoutInflater().inflate(R.layout.professional_pa_frame_layout, null, false);
frameLayout.setClickable(true);
frameLayout.setOnLongClickListener(new View.OnLongClickListener()
{
public boolean onLongClick(View view)
{
if (actionMode == null)
{
return false;
}
actionMode = view.startActionMode(actionModelCallback);
view.setSelected(true);
return false;
}
});
getFragmentManager().beginTransaction().add(id, fragment, tag).commit();
}
The fragment internally contains a series of edittext instances or a single imageview instances.
Whenever a long click is performed on framelayout, i guess the contextual action bar for edittext is displayed. I think the event is captured by editext and different contextual action bar is displayed. PFA image of the contextual action bar displayed whenever i get a long click event inside framelayout.
How can i capture long click event on my framelayout as a whole without displaying contextual action bar for its internal views. xml code written below is of the contextual action bar that i want to be displayed for my framelayout.
<item android:id="#+id/action_discard_notes"
android:icon="#drawable/discard_note"
android:title="#string/action_discard_notes"
android:showAsAction="always"
android:orderInCategory="1"/>
You need to set ActionModeCallback of Edittext so CAB aborted and call Framelayout long click like below code...
m_editText.setCustomSelectionActionModeCallback(new Callback()
{
#Override
public boolean onCreateActionMode(android.view.ActionMode p_mode, Menu p_menu)
{
return false;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode p_mode, Menu p_menu)
{
return false;
}
#Override
public void onDestroyActionMode(android.view.ActionMode p_mode)
{
}
#Override
public boolean onActionItemClicked(android.view.ActionMode p_mode, MenuItem p_item)
{
return false;
}
});
You need to return false in onCreateActionMode for abort CAB(contextual action bar).

Use a custom contextual action bar for WebView text selection

I have used this guide from Google and this tutorial to produce my own contextual action bar.
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.annotation_menu, menu);
return true;
}
// 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(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.custom_button:
// do some stuff
break;
case R.id.custom_button2:
// do some other stuff
break;
default:
// This essentially acts as a catch statement
// If none of the other cases are true, return false
// because the action was not handled
return false;
}
finish(); // An action was handled, so close the CAB
return true;
}
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
This menu is designed to appear when the user selects text, so it overrides the native copy/paste menu. Now I get to my issue.
Because I am overriding functions for text selection, I also added a LongClickListener to a WebView and implemented the onLongClick(View v) method so I can detect when users make the selection.
myWebView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActionMode != null) {
return false;
}
mActionMode = startActionMode(mActionModeCallback);
v.setSelected(true);
return true;
}
});
When I long click, I see my custom menu appear, but no text is highlighted.I need to have the text selection functionality; without it, my menu is pointless.
How do I override onLongClick(View v), but maintain the text selection provided by Android?If that is not possible, can I make the call to startActionMode(mActionModeCallback) somewhere else so that text will be selected as normal, but my custom menu will also appear?If neither of those are possible... help.
THERE IS AN EASIER WAY! See update below :D
For the sake of completeness, here is how I fixed the problem:
I followed the suggestion according to this answer, with a little more tweaking to more closely match the overridden code:
public class MyWebView extends WebView {
private ActionMode mActionMode;
private mActionMode.Callback mActionModeCallback;
#Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
Essentially, this forces your customized CAB to appear instead of the Android CAB. Now you have to modify your callback so that the text highlight will go away along with the CAB:
public class MyWebView extends WebView {
...
private class CustomActionModeCallback implements ActionMode.Callback {
...
// Everything up to this point is the same as in the question
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus(); // This is the new code to remove the text highlight
mActionMode = null;
}
}
}
That's all there is to it. Be aware that as long as you are using MyWebView with the overridden startActionMode there is NO WAY to get the native CAB (the copy/paste menu, in the case of a WebView). It may be possible to implement that sort of behavior, but that is not the way this code works.
UPDATE: There is a much easier way to do this! The above solution works well, but here is an alternative, easier way.
This solution provides less control over the ActionMode, but it requires far less code than the above solution.
public class MyActivity extends Activity {
private ActionMode mActionMode = null;
#Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.getMenuInflater().inflate(R.menu.my_custom_menu, menu);
}
super.onActionModeStarted(mode);
}
// This method is what you should set as your item's onClick
// <item android:onClick="onContextualMenuItemClicked" />
public void onContextualMenuItemClicked(MenuItem item) {
switch (item.getItemId()) {
case R.id.example_item_1:
// do some stuff
break;
case R.id.example_item_2:
// do some different stuff
break;
default:
// ...
break;
}
// This will likely always be true, but check it anyway, just in case
if (mActionMode != null) {
mActionMode.finish();
}
}
#Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
super.onActionModeFinished(mode);
}
}
Here is an example Menu to get you started:
<!-- my_custom_menu.xml -->
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/example_item_1"
android:icon="#drawable/ic_menu_example_1"
android:showAsAction="always"
android:onClick="onContextualMenuItemClicked"
android:title="#string/example_1">
</item>
<item
android:id="#+id/example_item_2"
android:icon="#drawable/ic_menu_example_2"
android:showAsAction="ifRoom"
android:onClick="onContextualMenuItemClicked"
android:title="#string/example_2">
</item>
</menu>
That's it! You're done! Now your custom menu will show up, you don't have to worry about the selection, and you barely have to concern yourself with the ActionMode lifecycle.
This works nearly flawlessly with a WebView that occupies its entire parent Activity. I am not sure how well it will work if there are multiple Views within your Activity at one time. It will likely require some tweaking in that case.
The way I did something similar was to only override the onTouchListener and to invoke a GestureDetector to detect when the WebView was long-pressed and do what I wanted from there. Here's some sample code that allows you to catch long-press events without sacrificing text-selection in the WebView. Hopefully this helps.
#Override
protected void onCreate(Bundle savedInstanceState) {
WebView mWebView = (WebView) findViewById(R.id.myWebView);
GestureDetector mGestureDetector = new GestureDetector(this, new CustomGestureListener());
mWebView.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View view, MotionEvent arg1) {
//Suggestion #1 - this just lets the touch to be handled by the system but allows you to detect long presses
mGestureDetector.onTouchEvent(arg1);
return false;
//Suggestion #2 - this code will only let the touch be handled by the system if you don't detect a long press
return mGestureDetector.onTouchEvent(arg1);
}
});
}
private class CustomGestureListener extends SimpleOnGestureListener {
#Override
public void onLongPress(MotionEvent e) {
//do stuff
}
}

Progressbar in Action bar not clickable

I have an item in my actionbar that shows a progressbar when clicked. However, when the user clicks the progressbar, I want the progress bar to stop, and show the normal "refresh" button again. Currently the progressbar become unclickable. Here's my code:
case R.id.id_Refresh:;
menuItem = item;
if(btnRefreshPressed == true){
menuItem.setActionView(R.layout.progressbar);
menuItem.expandActionView();
btnRefreshPressed = false;
mUpdateMap.run();
return true;
}else if(btnRefreshPressed == false){
menuItem.collapseActionView();
menuItem.setActionView(null);
mHandler.removeCallbacks(mUpdateMap);
btnRefreshPressed = true;
return true;
}
progressbar.xml:
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/progressbar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true" >
</ProgressBar>
when you use your own actionView, you need to handle the clicking on the view itself:
menuItem.getActionView().setOnClickListener(...);
also, instead of having 2 modes , one with actionView and another without, you can use viewSwitcher as the actionView , and just toggle it when you want , by using showNext().
EDIT: for easiest way to support clicking on action bar items, no matter if they contain an actionView or not, you can use this code:
public static void setOnMenuItemSelected(final MenuItem menuItem, final Runnable runnable) {
final View view = menuItem.getActionView();
if (view != null)
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
runnable.run();
}
});
else
menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(final MenuItem item) {
runnable.run();
return true;
}
});
}
You are not passing in the ID:
findViewById(com.example.androidbasic12.R.layout.progressbar);
it should be R.id.YourID not R.layout.progressbar
That's why you get a NullPointerException

Categories

Resources