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?
Related
I am beginner in android and try to make an app that popup a menu when imageView is clicked. Actually it works but popup at right side and I want to be at center.
So, I searched for it on web and come across ListPopupWindow, PopupWindow classes. I tried various methods of this classes as per my knowledge/ability but I am not able to achieve this.
Guide me to do that. Here is my code
imageview setonclickListener(new View.onclickListener() {
#Override public void onClick(View view){
PopupMenu popup = new PopupMenu(Info4 Activity.this, imageview1);
Menu menu = popup.getMenu();
for (int i = 0; i < (int) (subjects.size()); i++) {
val = subjects.get((int) (i));
menu.add(val);
}
popup.show();
}
});
PopupMenu:
The popup will appear below the anchor if there is room, or above it if there is not. In your situation the anchor is imageView, so you can not center the popup in screen.
PopupWindow:
Try this:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.showAtLocation(v, Gravity.CENTER, 0, 0);// here v is any View only needed for WindowToken
}
});
Other better ways:
May be you could be think about using DialogFragment, which is customizable and flexible.
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)
I have a PopupWindow on my activity, the thing is my PopupWindow still shows even when I'm interacting with my activity (say scrolling on my list). I can scroll through my list and the PopupWindow is still there.
What I want to achieve is when I'm touching/scrolling/clicking/etc on the screen which is not the PopupWindow, I want to dismiss the PopupWindow. Just like how a menu works. If you clicked outside of the menu, the menu will be dismissed.
I've tried setOutsideTouchable(true) but it won't dismiss the window. Thanks.
Please try to set setBackgroundDrawable on PopupWindow that should close the window if you touch outside of it.
I found that none of the answers supplied worked for me, except WareNinja's comment on the accepted answer, and Marcin S.'s will probably also work. Here's the part that works for me:
myPopupWindow.setBackgroundDrawable(new BitmapDrawable());
myPopupWindow.setOutsideTouchable(true);
Alternatively:
myPopupWindow.setFocusable(true);
Not sure what the differences are, but the ListPopupWindow source code actually uses the latter when it's modality is set to true with setModal, so at least the Android developers consider this a viable approach, and it's only one line.
I met the same issues, and fixed it as below codes. It works fine for me.
// Closes the popup window when touch outside.
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setFocusable(true);
// Removes default background.
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
BTW, Don't use BitmapDrawable deprecated constructor, use this new ColorDrawable(android.R.color.transparent) to replace default background.
Have fun#.#
I know it's late but I notice that people still have an issue with the popup window. I have decided to write a fully working example where you can dismiss the popup window by touching or clicking outside of it or just touching the window itself. To do so create a new PopupWindow class and copy this code:
PopupWindow.class
public class PopupWindow extends android.widget.PopupWindow
{
Context ctx;
Button btnDismiss;
TextView lblText;
View popupView;
public PopupWindow(Context context)
{
super(context);
ctx = context;
popupView = LayoutInflater.from(context).inflate(R.layout.popup, null);
setContentView(popupView);
btnDismiss = (Button)popupView.findViewById(R.id.btn_dismiss);
lblText = (TextView)popupView.findViewById(R.id.text);
setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
// Closes the popup window when touch outside of it - when looses focus
setOutsideTouchable(true);
setFocusable(true);
// Removes default black background
setBackgroundDrawable(new BitmapDrawable());
btnDismiss.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
dismiss();
}});
// Closes the popup window when touch it
/* this.setTouchInterceptor(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
dismiss();
}
return true;
}
}); */
} // End constructor
// Attaches the view to its parent anchor-view at position x and y
public void show(View anchor, int x, int y)
{
showAtLocation(anchor, Gravity.CENTER, x, y);
}
}
Now create the layout for the popup window:
popup.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="PopupWindow Example"
android:textColor="#000000"
android:textSize="17sp"
android:textStyle="italic" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<Button
android:id="#+id/btn_dismiss"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dismiss"
android:visibility="gone" />
<TextView
android:id="#+id/lbl_dismiss"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Touch outside of this box to dismiss"
android:textColor="#ffffff"
android:textStyle="bold" />
</FrameLayout>
In your main activity create an instance of the PopupWindow class:
final PopupWindow popupWindow = new PopupWindow(this);
popupWindow.show(findViewById(R.id.YOUR_MAIN_LAYOUT), 0, -250);
where YOUR_MAIN_LAYOUT is the layout of the current activity in which popupWindow will pop up
Thanks for #LunaKong's answer and #HourGlass's confirmation. I don't want to make a duplicated comment, but only want to make it clear and concise.
// Closes the popup window when touch outside. This method was written informatively in Google's docs.
mPopupWindow.setOutsideTouchable(true);
// Set focus true to prevent a touch event to go to a below view (main layout), which works like a dialog with 'cancel' property => Try it! And you will know what I mean.
mPopupWindow.setFocusable(true);
// Removes default background.
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Mttdat.
For a ListPopupWindow set the window to be a modal when shown.
mListPopupWindow.setModal(true);
That way, clicking outside of the ListPopupWindow will dismiss it.
Notice that for canceling with popupWindow.setOutsideTouchable(true),
you need to make width and height wrap_content like below code:
PopupWindow popupWindow = new PopupWindow(
G.layoutInflater.inflate(R.layout.lay_dialog_support, null, false),
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT, true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setOutsideTouchable(true);
popupWindow.setFocusable(true);
popupWindow.showAtLocation(view, Gravity.RIGHT, 0, 0);
You can use isOutsideTouchable OR isFocusable to dissmiss popup window when touch outside
popupWindow.isOutsideTouchable = true // dismiss popupwindow when touch outside
popupWindow.isFocusable = true // dismiss popupwindow when touch outside AND when press back button
Note
Currently, after test I see setBackgroundDrawable don't help us dismiss popupwindow
If you look at the code for dismiss in PopupWindow (PopupWindow->PopupDecorView->dispatchKeyEvent and PopupWindow->PopupDecorView->onTouchEvent). You will see that when press back button, they dismiss on ACTION_UP and when touch outside they dismiss on ACTION_UP or ACTION_OUTSIDE
mPopWindow.setFocusable(true);
popupWindow.setTouchable(true);
popupWindow.setFocusable(true);
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
It will dismiss the PopupWindow when click/touch on screen.Make sure you have set focusable true before showAtLocation.
#LunaKong suggestion work's like a charm.
But setting up mPopupWindow.setFocusable(false). removes unnecessary touch required to make popup window disappear.
For example:
Let's consider there is a pop up window visible on screen, and you are about to click a button.
So in this case, (if mpopwindow.setFocusable(true))
on the first click of a button popupwindow will dismiss.
But you have to click again to make the button works.
if**(mpopwindwo.setFocusable(false)**
single click of button dismiss the popup window as well as trigger the button click.
Hope it helps.
In some cases making the popup focusable is not desirable (e.g. you may not want it to steal focus from another view).
An alternative approach is using a touch interceptor:
popupWindow.setOutsideTouchable(true);
popupWindow.setTouchInterceptor(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
popupWindow.dismiss();
}
return false;
}
});
Set the window background transparent:
PopupWindow.getBackground().setAlpha(0);
After it set your background in layout. Works fine.
If this Popup Window is another activity,and you decreased its size to the original screen
and you want to enable or disable the outside area.you can simply enable or disable the outside area by this code:
enable:
YourActivity.this.setFinishOnTouchOutside(true);
disable:
YourActivity.this.setFinishOnTouchOutside(false);
Use View popupView to dismiss the popupWindow
`popupView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
`
If you use this you can also setOnClickListener to any button inside the popupWindow
I am using a popup window to display some information and have an edit button that allows that information to be changed. I am loading all textviews, buttons and edittext fields and hiding/showing them as needed. The edittext fields are not letting me edit them. I have tried the below suggestion about setting focusable to true, but that isn't working. Any other suggestions?
Tried this: EditText On A Popup Window
EDIT: Below is part of my code. I've just included the parts for initializing the edittext and showing the popup contents since everything else is working, just not the edittext. I am using a tablelayout, and when the user clicks a row, the popup window displays. Keep in mind I'm still pretty new to Java and Android!
EDIT #2: The softkeyboard was not showing when the edittext was selected, but now it will show if I dismiss the popup once and then call it again. I then tried forcing the softkeyboard to display, and it showed behind the popup (another problem). I was able to select the number 1 since it was barely showing behind the popup window, but it didn't seem to work either. The fix was the same here: dismiss the popup window and recall it. So my remaining problem is being able to type into the edittext without having to dismiss the popup once and recall it. As such, I am changing the title of this question.
row1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final EditText pwETBrand = (EditText) vPopUp.findViewById(R.id.et_editbrand);
if (!infoClick) {
infoClick = true;
// Popup elements initialized earlier
pwInfo.showAtLocation(llInfo, Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 0, 0);
pwInfo.update(0, 0, llMain.getWidth()-50, llMain.getHeight()-100);
pwInfo.setFocusable(true);
....
// Hide some elements initially until "EDIT" button is pressed
pwETBrand.setVisibility(View.INVISIBLE);
....
// When EDIT button is pressed, hide default elements, and show edit elements
pwEdit.setOnClickListener(new OnClickListener() {
public void onClick(View v2) {
pwETBrand.setVisivility(View.VISIBLE);
// Other element settings go here
pwInfo.setFocusable(true);
}
)};
....
}
}
I have implemented a solution, though it may not be the best solution. I have set a boolean field at the class initialization that checks if the popupwindow has ever been called. If it has not yet been called, then it will immediately dismiss the popupwindow and re-open it since my problem is in the popupwindow initialization.
pwInfo.showAtLocation(llInfo, Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 0, 0);
pwInfo.update(0, 0, llMain.getWidth()-50, llMain.getHeight()-100);
pwInfo.setFocusable(true);
if (pwFirst) {
pwFirst = false;
pwInfo.dismiss();
pwInfo.showAtLocation(llInfo, Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 0, 0);
pwInfo.update(0, 0, llMain.getWidth()-50, llMain.getHeight()-100);
pwInfo.setFocusable(true);
}
Not the best solution, but it works.
Try this,
final PopupWindow popupWindow = new PopupWindow(popupView,LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,true);
works for me.
Use Below Link's Code for that, it may help you.
Popup With Edittext
Whenever you create a PopupWindow you must put true in focusable like that :
PopupWindow(View contentView, int width, int height, boolean focusable)
final PopupWindow popupWindow = new PopupWindow(popupView,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,true);
good luck
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!