How to show PopupWindow above keyboard? - android

I want to show a PopupWindow above virtual keyboard like Google Keep did when creating a reminder:

I believe, what you are looking for is combination of:
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
It's basically how native SearchView works:
https://android.googlesource.com/platform/frameworks/support/+/android-6.0.1_r31/v7/appcompat/src/android/support/v7/widget/SearchView.java#1695
which basically calls AutocompleteTextView.ensureImeVisible()
public void ensureImeVisible(boolean visible) {
mPopup.setInputMethodMode(visible
? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) {
showDropDown();
}
}
This would resize Popup window to be shown exactly between Anchor and Keyboard.

use the following code. Change the location of the popup window in the method "showAtLocation".
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup_layout, null, false), ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT, true);
findViewById(R.id.activity_layout).post(new Runnable() {
#Override
public void run() {
pw.showAtLocation(findViewById(R.id.activity_layout), Gravity.CENTER, 0, 0); //set location here
}
});

To make a PopupWindow display above (on top of, or in front of) the on-screen keyboard, and make it dismiss when clicked outside, use this:
popupWindow = new PopupWindow(context);
popupWindow.setFocusable(true);
popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
Sample code: https://github.com/lorensiuswlt/NewQuickAction3D
To make a ListPopupWindow display in front of the keyboard, and make it automatically close when clicked outside, use this:
listPopupWindow = new ListPopupWindow(context);
listPopupWindow.setModal(true);
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
Sample code: Custom PopupMenu (layout)

Related

ListPopupWindow closes soft keyboard

Working on a lockscreen app I see a very strange behaviour: showing a ListPopupWindow forces the soft keyboard to close. This happens only on a "lockscreen" activity (activity window flags are set to FLAG_SHOW_WHEN_LOCKED|FLAG_DISMISS_KEYGUARD) and only if keyguard pin/password is set.
Here is a code example:
editText.setOnFocusChangeListener((v, hasFocus) -> {
ListPopupWindow popupWindow = new ListPopupWindow(getContext());
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
popupWindow.setAdapter(new ArrayAdapter(
getContext(), android.R.layout.simple_dropdown_item_1line, Arrays.asList("aaa", "bbb", "ccc")));
popupWindow.setAnchorView(editText);
popupWindow.show();
});
When popup list appears the keyboards immediately disappears.
Note that at the same time PopupWindow works ok:
editText.setOnFocusChangeListener((v, hasFocus) -> {
PopupWindow popupWindow = new PopupWindow(getContext());
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
popupWindow.setContentView(new TextClock(getContext()));
popupWindow.showAsDropDown(editText);
});
Both the popup window and the keyboard are visible.
Any idea of how to avoid this keyboard disappearance? Finally I need a SearchView (it displays suggestions in a ListPopupWindow) to work properly on a lockscreen.
I found that the keyboard is not closed if the popup window input method mode is
INPUT_METHOD_FROM_FOCUSABLE.
SearchView contains AutoCompleteTextView that changes its suggestions popup input method mode to INPUT_METHOD_NEEDED or INPUT_METHOD_NOT_NEEDED. So the workaround is to keep PopupWindow.mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE.
I solved this by creating a custom PopupWindow with setInputMethodMode() overridden:
public class SearchSuggestionPopupWindow extends PopupWindow {
SearchSuggestionPopupWindow(final Context context, final PopupWindow original) {
super(context);
setElevation(original.getElevation());
setAnimationStyle(original.getAnimationStyle());
setBackgroundDrawable(original.getBackground());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setOverlapAnchor(original.getOverlapAnchor());
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setEnterTransition(original.getEnterTransition());
setExitTransition(original.getExitTransition());
}
}
#Override
public void setInputMethodMode(final int mode) {
super.setInputMethodMode(PopupWindow.INPUT_METHOD_FROM_FOCUSABLE);
}
}
Then it's necessary to get AutoCompleteTextView from SearchView:
final AutoCompleteTextView textView = searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
and to substitute the custom popup window:
final Field listPopupField = AutoCompleteTextView.class.getDeclaredField("mPopup");
listPopupField.setAccessible(true);
final ListPopupWindow listPopup = (ListPopupWindow) listPopupField.get(textView);
final Field popupField = ListPopupWindow.class.getDeclaredField("mPopup");
popupField.setAccessible(true);
final PopupWindow popup = (PopupWindow) popupField.get(listPopup);
final PopupWindow customPopup = new SearchSuggestionPopupWindow(textView.getContext(), popup);
popupField.set(listPopup, customPopup);

how to create popup in oncreate method of service class

I am trying to create popup window on home screen when an floating image is clicked (using windowmanager).
so while using layoutinflater , I am not able to set a viewgroup in the second argument as findviewbyId is not recognised. so I kept null. like below.
LayoutInflater inflater = (LayoutInflater) Floater.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.popup_for_floating_img,
null);
pwindo = new PopupWindow(layout, 300, 370, true);
pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
But when i click the floating image on home screen , it is giving below error message.
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
so please suggest me the way forward to get the popup on click.
I am trying for popup like if we enable floating widget in CLEAN MASTER app and click on floating broom image will give popup.
Try this in your showPopup(...) function:
layout.post(new Runnable()
{
public void run()
{
popup.showAtLocation(layout, Gravity.NO_GRAVITY, OFFSET_X, OFFSET_Y);
}
});
where the layout is your popup. This is because you trying to show the popup before you even created the activity.

Issue dismissing popup window

I have a popup menu implemented , which shows up on click of a button. This is my onclick method.
public void showOverflow(View view) {
boolean click = true;
Button action = (Button) findViewById(R.id.btbAction);
LayoutInflater inflater = (LayoutInflater) main.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupView = inflater.inflate(R.layout.overflow_layout, null);
final PopupWindow pw = new PopupWindow(popupView,
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
pw.setOutsideTouchable(true);
if (click) {
pw.showAsDropDown(action, 0, 0);
click = false;
} else {
pw.dismiss();
click = true;
}
}
The popup window shows up when the button is clicked. Now, the problem is that the window is not dismissed when i touch outside the popup window.
I tried setting this property to the popup window
pw.setOutsideTouchable(true);
Things remain the same. Please help me fix this
You should change the setOutsideTouchable call's parameter to true:
pw.setOutsideTouchable(false);
Controls whether the pop-up will be informed of touch events outside
of its window. This only makes sense for pop-ups that are touchable
but not focusable, which means touches outside of the window will be
delivered to the window behind. The default is false.
If the popup is showing, calling this method will take effect only the
next time the popup is shown or through a manual call to one of the
update() methods.
Parameters: touchable true if the popup should receive outside touch
events, false otherwise
On the other hand, what is the click local variable supposed to do? It is set to true, so it will always force the pw to pop up, whenever the showOverflow method is called, and for no reason it is set to false later, because it's life cycle ends as you leave that method.
Your code should look something like this:
private LayoutInflater inflater;
private Button action;
private PopupWindow pw;
private View popupView;
/*
* (non-Javadoc)
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
popupView = inflater.inflate(R.layout.overflow_layout, null, false);
action = (Button) findViewById(R.id.action);
action.setOnClickListener(this);
}
public void showOverflow()
{
pw = new PopupWindow(getApplicationContext());
pw.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
pw.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
pw.setOutsideTouchable(true);
pw.setContentView(popupView);
pw.showAsDropDown(action, 0, 0);
}
The getApplicationContext() shoud be used in case you are inside an Activity class. Otherwise you should get the Context as a parameter.
change pw.setOutsideTouchable(true); to pw.setOutsideTouchable(false);
I know this is an old question but this is what I have done to fix it
The problem is:
You are creating a new instance of popupwindow everytime you call showOverFlow() thats why after you close the popupwindow another popup window will show
What will you do is initialize popupview in OnCreate
Then call popupwindow.showAsDropDown(view) in showOverFlow() method
And lastly you can check whether is it showing below code
Put this code in your button onclick
if(popupwindow.isShowing()){
popup.dismiss() }
else{
ShowOverflow()}

Modeless PopupWindow as Keyboard

I'm trying to emulate a software keyboard for a domain specific input. I'm using a PopupWindow to gather the input and transfer it to the underlying EditText. Unfortunately, the PopupWindow is modal, so the user cannot switch from one EditText to another as they can with the usual software keyboard. I've looked into setting the FLAG_NOT_TOUCH_MODAL flag, but I'm not sure when or to what it should be applied to get the behavior I'm looking for.
My code for launching the PopupWindow looks like:
myEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
pw = myKeyboard.getPopupWindow((EditText) v);
pw.showAtLocation(Main.this.findViewById(R.id.main), Gravity.BOTTOM, 0, 0);
}
});
I tried changing it to the following, but this only resulted in the runtime exception: java.lang.RuntimeException: view android.widget.LinearLayout#40526268 being added, but it already has a parent
myEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
pw = myKeyboard.getPopupWindow((EditText) v);
WindowManager.LayoutParams wlp = getWindow().getAttributes();
wlp.gravity = Gravity.BOTTOM;
wlp.flags = wlp.flags | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
getWindow().addContentView(pw.getContentView(), wlp);
pw.showAtLocation(Main.this.findViewById(R.id.main), Gravity.BOTTOM, 0, 0);
}
});
I'm also looking into setOutsideTouchable, but so far I haven't gotten anywhere.
Any pointers on how I can create a modeless PopupWindow? I would be willing to use some other modeless widget.
A PopupWindow seems a bit heavy for what you're trying to do, and as you're finding out you're having to fight against it to do what you want. Why not just implement your keyboard as a View and stick it in your layout, then hide/show it?

Android- Making Toast clickable

I want to make toast click able or a UI element which will have clickable button but behaves like toast.
It should not run on UI thread like toast.
It should not halt or overlay current user activity, message should come like toast with clickable button and vanish but as toast user should be able to access background ongoing UI item.
If any one has any idea about how to achieve this pls share with me.
Little trick. Tested working Android 4.4
toast = new Toast(context);
try {
Class<?> clazz = Class.forName("android.widget.Toast");
Method method = clazz.getDeclaredMethod("getWindowParams");
WindowManager.LayoutParams param = (WindowManager.LayoutParams) method.invoke(toast);
param.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
} catch (Exception e) {
e.printStackTrace();
}
The Gmail undo bar is the best suitable for you, its just like a toast with a button.
Here is a code implementation for it.
http://code.google.com/p/romannurik-code/source/browse/misc/undobar/src/com/example/android/undobar/UndoBarController.java
I had a similar requirement that I solved using a PopupWindow. Basically, I had an about window with a clickable link that I wanted displayed like a toast. The popup window can accomplish this as follows:
In the parent class, I use the following flag:
private boolean durationExpired = false;
Then, when I invoke what would have been the toast, I do the following instead:
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.about_hiittimer,
(ViewGroup) findViewById(R.id.about_hiittimer));
TextView url = (TextView) layout.findViewById(R.id.url);
url.setMovementMethod(LinkMovementMethod.getInstance());
final PopupWindow popupWindow = new PopupWindow(layout, 280, 160, false);
popupWindow.showAtLocation(layout, 17, 0, 0);
popupWindow.setTouchable(true);
popupWindow.setOutsideTouchable(true);
final Handler popupHandler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
if (!durationExpired) {
durationExpired = true;
popupHandler.postDelayed(this, 2000);
} else {
popupWindow.dismiss();
popupHandler.removeCallbacks(this);
durationExpired = false;
}
}
});
Put your main layout inside a FrameLayout. Write a layout for your toast, with the button and all, insert it into the FrameLayout (below your main layout) and set its visibility to GONE.
When you show it (setting visibility to VISIBLE) start a new thread that counts down the seconds till its dismissed. Set it back to invisible from the thread via a Handler (cause all UI elements can only be managed from the main thread).
cheers!

Categories

Resources