Display a popup at the left edge of a view - android

I am using a custom popup in a list view, this popup needs to be drawn half way through the height of triggerview and on the left side of the triggerview.
I am able to achieve the first part, second seems elusive, here is my code:
public class QuickAction implements View.OnTouchListener {
private View triggerView;
private PopupWindow window;
protected final WindowManager windowManager;
public QuickAction(View triggerView) {
this.triggerView = triggerView;
window = new PopupWindow(triggerView.getContext());
window.setTouchable(true);
window.setTouchInterceptor(this);
windowManager = (WindowManager) triggerView.getContext().getSystemService(Context.WINDOW_SERVICE);
ImageView imageView = new ImageView(triggerView.getContext());
imageView.setImageResource(R.drawable.ic_action_email);
LayoutInflater layoutInflater = (LayoutInflater) triggerView.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = layoutInflater.inflate(R.layout.quick_action_popup_layout, null, false);
window.setContentView(layout);
// window.setBackgroundDrawable(null);
window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
window.setTouchable(true);
window.setFocusable(false);
window.setOutsideTouchable(true);
}
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_OUTSIDE == event.getAction()) {
this.window.dismiss();
return true;
}
return false;
}
public void show() {
int[] location = new int[2];
triggerView.getLocationOnScreen(location);
window.showAtLocation(triggerView, Gravity.NO_GRAVITY, location[0] + (triggerView.getLeft()), location[1] + (triggerView.getHeight() / 2));
}
}
What I want is to align the right edge of my popup window to the left egde of my triggerview
Triggerview is my button where I want to generate the popup, the relevant parts of code being:
public void show() {
int[] location = new int[2];
triggerView.getLocationOnScreen(location);
window.showAtLocation(triggerView, Gravity.NO_GRAVITY, location[0] + (triggerView.getLeft()), location[1] + (triggerView.getHeight() / 2));
}
However this does nto give me the desired result. Any ideas?

Specifying a gravity of NO_GRAVITY is similar to specifying
Gravity.LEFT | Gravity.TOP.
If you want to place the popup window's right side to your specified location you need Gravity.TOP | Gravity.RIGHT instead of Gravity.NO_GRAVITY.

Related

Android : is it possible open popup look likes softkeyboard?

I hard to implement popup like softkeyboard. I mean, when you open popup in android the views under popup is disable (you can't do anything until the popup dismiss). But when then softkeyboard open, the views always above the softkeyboard.
Note : dont need trick like view.setVisibility(View.GONE) or view.setVisibility(View.VISIBLE)
EDIT
As simply, how to make layout/view up when popup display from bottom to up look like softkeyboard?
Yes, you can create Custom Dialog with two translate animation from bottom.
Check droid kid answer he is already done in your way.
Answer
For this you have to create a custom view that pop up,you have to create a different xml file for your view and define the height width of that,make height wrap content.And your views are not affected by this like other Dialog popup which disable anything in the background.
Example :- lets say you have xml for pop up named dialog_pop_up,
public void showPopUpDialog(Context context,ImageView imagebuttonPopUP) {
try {
View v = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.dialog_pop_up, null, false);
int[] location = new int[2];
//This is the button which triggers pop up
imagebuttonPopUP.getLocationOnScreen(location);
//Initialize the Point with x, and y positions
Point p = new Point();
p.x = location[0];
p.y = location[1];
int popupWidth = mActivity.getResources().getDimensionPixelOffset(R.dimen.home_screen_dialog_width);//Utility.dpToPx(mActivity,133);
int OFFSET_Y = imagebuttonPopUP.getHeight();
int OFFSET_X = imagebuttonPopUP.getWidth();
final PopupWindow window = new PopupWindow(v, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, true);
window.setWidth(popupWidth);
window.setOutsideTouchable(true);
window.setTouchable(true);
window.setFocusable(true);
window.setBackgroundDrawable(new BitmapDrawable());
//Initialize your view here.
TextView TextView1 = (TextView) v.findViewById(R.id.textview1);
TextView TextView2 = (TextView) v.findViewById(R.id.textview2);
LinearLayout Layout = (LinearLayout) v.findViewById(R.id.linearlayout2);
View dividerView = v.findViewById(R.id.view_divider);
//Click listeners of your views
TextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//your code here
//to dismiss window
window.dismiss();
}
});
TextView2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//code
}
});
window.showAtLocation(imagebuttonPopUP, Gravity.NO_GRAVITY, p.x + OFFSET_X - popupWidth, p.y + OFFSET_Y);
} catch (Exception ex) {
Logger.e(TAG, ex.getMessage());
}
}

NullPointer Exception in getWidth(), getHeight()

I am working on project . I need the width & Height of a LinearLayout from Activity using programming code. This Linear Layout has fixed width and Height . But when i use the following ..i am getting Nullpointer Exception
LinearLayout viewGroup = (LinearLayout) context.findViewById(R.id.popup);
Log.e("getWidth",""+viewGroup.getWidth());
Log.e("getHeight",""+viewGroup.getHeight());
I need the width and height of that layout from activity.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/popup"
android:layout_width="150dp"
android:layout_height="252dp"
android:background="#303030"
android:orientation="vertical" >
</LinearLayout>
Here is the Java code file
public class MainActivity extends Activity {
//The "x" and "y" position of the "Show Button" on screen.
Point p;
Button btn_show;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_show = (Button) findViewById(R.id.show_popup);
}
#Override
protected void onResume() {
super.onResume();
btn_show.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
//Open popup window
if (p != null)
showPopup( p);
}
});
}
// Get the x and y position after the button is draw on screen
// (It's important to note that we can't get the position in the onCreate(),
// because at that stage most probably the view isn't drawn yet, so it will return (0, 0))
#Override
public void onWindowFocusChanged(boolean hasFocus) {
int[] location = new int[2];
Button button = (Button) findViewById(R.id.show_popup);
// Get the x, y location and store it in the location[] array
// location[0] = x, location[1] = y.
button.getLocationOnScreen(location);
//Initialize the Point with x, and y positions
p = new Point();
p.x = location[0];
p.y = location[1];
}
// The method that displays the popup.
private void showPopup( Point p) {
int popupWidth = 200;
int popupHeight = 380;
// Inflate the popup_layout.xml
LinearLayout viewGroup = (LinearLayout) findViewById(R.id.popup);
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = layoutInflater.inflate(R.layout.a, viewGroup);
Log.e("getWidth",""+viewGroup.getWidth());
Log.e("getHeight",""+viewGroup.getHeight());
// Creating the PopupWindow
final PopupWindow popup = new PopupWindow(getApplicationContext());
popup.setContentView(layout);
popup.setWidth(viewGroup.getWidth());
popup.setHeight(viewGroup.getHeight());
popup.setFocusable(true);
// Some offset to align the popup a bit to the right, and a bit down, relative to button's position.
int OFFSET_X = 30;
int OFFSET_Y = 30;
// Clear the default translucent background
popup.setBackgroundDrawable(new BitmapDrawable());
// Displaying the popup at the specified location, + offsets.
popup.showAtLocation(layout, Gravity.NO_GRAVITY, p.x + OFFSET_X, p.y + OFFSET_Y);
// Getting a reference to Close button, and close the popup when clicked.
// Button close = (Button) layout.findViewById(R.id.close);
/* close.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
popup.dismiss();
}
});*/
}
}
It may be that this ViewGroup hasn't been created yet.
Check where you're trying to get the width and height of this object is actually being called after display objects such as views etc are being created. You can debug this by either placing breakpoints in the different loading methods such as onCreate, onResume or by placing NSLog's in them instead.
Only once the method View.onSizeChanged() has been called for the first can you reliably use the getHeight() and getWidth() methods. This means you will have to change the logic of your app to take into account this fact.
You are inflating the layout just to get the width and height, aren't you? If so you don't need the viewGroup. Assuming R.layout.popup_layout points to a LinearLayout that has fixed dimensions:
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = layoutInflater.inflate(R.layout.popup_layout, null);
LayoutParams params = layout.getLayoutParams();
Log.e("getWidth",""+params.width);
Log.e("getHeight",""+params.height);
After that you can set your popup:
final PopupWindow popup = new PopupWindow(getApplicationContext());
popup.setContentView(layout);
popup.setWidth(params.width);
popup.setHeight(params.height);
popup.setFocusable(true);
to wait for the views to be attached and placed in the layout you should useViewTreeObserver.OnGlobalLayoutListener.
you can register it like this:
v.getViewTreeObserver().addOnGlobalLayoutListener( new
OnGlobalLayoutListener() {
public void onGlobalLayout() {
//TODO: do your stuff here
//if you change something in the layout you have to add this
//line to avoid loops
v.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
in that callback you can be sure to have the views with a consistence position and dimension.

How to draw view on top of soft keyboard like WhatsApp?

I want to know how it's possible to add View on top of Keyboard like WhatsApp and Hangout. In chat screen, they insert emoticons view on top of the opened soft keyboard.
Does anyone know how to achieve this behavior?
Well, I have created a sample keyboard for chatting here...
Here, I use popup window for showing popup window and height of popup is calculated dynamically by height of keyboard
// Initially defining default height of keyboard which is equal to 230 dip
final float popUpheight = getResources().getDimension(
R.dimen.keyboard_height);
changeKeyboardHeight((int) popUpheight);
// Creating a pop window for emoticons keyboard
popupWindow = new PopupWindow(popUpView, LayoutParams.MATCH_PARENT,
(int) keyboardHeight, false);
and height is calculated using this function :
/**
* Checking keyboard height and keyboard visibility
*/
int previousHeightDiffrence = 0;
private void checkKeyboardHeight(final View parentLayout) {
parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
parentLayout.getWindowVisibleDisplayFrame(r);
int screenHeight = parentLayout.getRootView()
.getHeight();
int heightDifference = screenHeight - (r.bottom);
if (previousHeightDiffrence - heightDifference > 50) {
popupWindow.dismiss();
}
previousHeightDiffrence = heightDifference;
if (heightDifference > 100) {
isKeyBoardVisible = true;
changeKeyboardHeight(heightDifference);
} else {
isKeyBoardVisible = false;
}
}
});
}
Using all these stuff i am able to make a perfect overlapping keyboard....
then i inflate popup window with viewpager and gridview for emoticons.
Also, i use spannable string for showing these emoticons in listview and chat window
After a heavy time of research and try-and-error, I've found another solution similar to the one of Chirag Jain above, but using a custom Dialog.
mDialogKeyboard = new Dialog(this,android.R.style.Theme_NoTitleBar);
mDialogKeyboard.setContentView(R.layout.your_custom_layout);
mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
mDialogKeyboard.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
WindowManager.LayoutParams lp=mDialogKeyboard.getWindow().getAttributes();
lp.width=WindowManager.LayoutParams.MATCH_PARENT;
lp.height=mSoftKeyboardHeight;
lp.gravity=Gravity.BOTTOM | Gravity.LEFT;
lp.dimAmount=0;
Despite the fact that Chirag Jain answer seems to be more clean, I'll post this here for have an alternative method.
As far as I know you can draw on other applications, yes. I myself have designed such an app. As for drawing on an application such as the keyboard or any other application in specific, I guess, you'll have to define a layout with a height that's exactly that of the keyboard. So, that would vary from device to device. So, this isn't possible.
I still stick to my notion that WhatsApp merely dismisses the soft keyboard on pressing the smiley button and calls it's own fragment.
If you would still like to pursue this, here's how you draw a "window" over other applications. These should be it's layout parameters.
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
Albeit, your width will change to an absolute pixel value since you'd like the activity to be over the keyboard only.
If I've misunderstood the question, please correct me.
what my thinking is they have created their own keypad for smiles, and on click of smile icon or keypad icon they are hiding smile keypad and showing the normal keypad. there are two scenarios in whats app case 1) if you don't focus 1st time of editext then you can not see the show keypad button,and the height of smile keypad is exactly same as normal keypad,we will get the keypad height only after our view layout is changed, means only after the keypad is shown, that means they are creating their own keypad.. 2) if you focus the edittext and click of smile button then it will show the option of show keypad button Please correct me if i am not right on this
I recently had to implement a view which would be above a soft keyboard. #Chirag Jain's solution is almost right, but it does not count with the system buttons in the bottom of the screen! This will make the keyboard height incorrect on some devices like NEXUS 6. This solution should work across all devices:
1) create layout which contains your view
<RelativeLayout
android:id="#+id/keyboard_info_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="#color/C12"
android:padding="10dp"
android:visibility="invisible">
....
</RelativeLayout>
2) Bind view
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.notifications_email_settings_fragment, container, false);
ButterKnife.bind(this, rootview);
checkKeyboardHeight(rootview);
3) keyboard check and view margin settings
private void checkKeyboardHeight(final View parentLayout) {
parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
int previousHeightDiffrence = 0;
int systemBarHigh = 999999;
#Override
public void onGlobalLayout() {
Rect r = new Rect();
parentLayout.getWindowVisibleDisplayFrame(r);
int screenHeight = parentLayout.getRootView()
.getHeight();
int keyboardHeight = screenHeight - (r.bottom);
if(systemBarHigh > keyboardHeight) {
systemBarHigh = keyboardHeight;
}
if (keyboardHeight > 250) {
int keyboardHightWithoutSystemBar = keyboardHeight - systemBarHigh;
// no need to update when the keyboard goes down
if (previousHeightDiffrence != keyboardHightWithoutSystemBar) { // if (Math.abs(previousHeightDiffrence - keyboardHeight) > 10) {
adjustKeyboard(keyboardHightWithoutSystemBar);
}
keyboardInfoContainer.setVisibility(View.VISIBLE);
isKeyBoardVisible = true;
previousHeightDiffrence = keyboardHightWithoutSystemBar;
} else {
isKeyBoardVisible = false;
if (keyboardInfoContainer != null) {
keyboardInfoContainer.setVisibility(View.INVISIBLE);
}
}
}
});
}
private void adjustKeyboard(int keyboardHeight) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) keyboardInfoContainer.getLayoutParams();
lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
lp.bottomMargin = keyboardHeight;
keyboardInfoContainer.requestLayout();
}
#jirkarrr, Why don't you add the keyboardInfoContainer like this:
WindowManager wm = getWindowManager();
WindowManager.LayoutParams lps = new WindowManager.LayoutParams();
lps.x = 0; lps.y = keyboardHeight;
wm.addView(keyboardInfoContainer, lps);
I do as your code, but it cannot show out the keyboardInfoContainer.
I use a popup to put view over the keyboard:
public void showPopUpKeyboard() {
mIsPopupVisible = true;
// Initialize a new instance of LayoutInflater service
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
// Inflate the custom layout/view
View customView = inflater.inflate(R.layout.popup_in_keyboard, null);
mScrollView = (ScrollView) customView.findViewById(R.id.keyboard_layout_view);
// Initialize a new instance of popup window
mPopupWindow = new PopupWindow(
customView,
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
);
setSizeForSoftKeyboard();
// Get a reference for the custom view close button
Button closeButton = (Button) customView.findViewById(R.id.ib_close);
// Set a click listener for the popup window close button
closeButton.setOnClickListener((View view) -> {
// Dismiss the popup window
mIsPopupVisible = false;
mPopupWindow.dismiss();
});
mPopupWindow.showAtLocation(mParentLayout, Gravity.CENTER, 0, 0);
}
Then I try to know keyboard's height:
mParentLayout.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
Rect r = new Rect();
mParentLayout.getWindowVisibleDisplayFrame(r);
int heightDiff = mParentLayout.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) {
//enter your code here
if (mIsPopupVisible) {
keepKeyboard();
mIsPopupVisible = false;
mPopupWindow.dismiss();
}
} else {
//enter code for hid
}
});
You can check this tutorial and this example in GitHub

How to restore the popup window's position when changes the orientation in android?

I am trying to show popup windows wherever user touchs the screen. I am able to display popup windows at desired location. But problem is when popup window is in portrait mode if i changes the orientation in landscape mode that popup window is displaying in same position , because of that popup window is overlapping with views in landscape mode and same problem occurs when we change orientation landscape to portrait . My requirements are below
1. Dont want to dismiss popup window when changes the orientation.
2. change the positions of the all popup windows dynamically, whenever orientation changes so that views are not overlapped(popup window doesnt overlaps with image). Example when i change the orientation portrait to landscape popup windows position will move to bit upwards.
private void showPopup(final Activity context, Point p) {
int popupWidth = 200;
int popupHeight = 150;
boolean showEditText = true;
// Inflate the popup_layout.xml
LinearLayout viewGroup = (LinearLayout) context
.findViewById(R.id.popup);
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = layoutInflater.inflate(R.layout.popup_layout, viewGroup);
// Creating the PopupWindow
final PopupWindow popup = new PopupWindow(context);
popup.setContentView(layout);
popup.setWidth(popupWidth);
popup.setHeight(popupHeight);
popup.setFocusable(false);
popup.setOutsideTouchable(false);
// Some offset to align the popup a bit to the right, and a bit down,
// relative to button's position.
int OFFSET_X = 5;
int OFFSET_Y = 5;
// Clear the default translucent background
popup.setBackgroundDrawable(new BitmapDrawable());
// Displaying the popup at the specified location, + offsets.
popup.showAtLocation(layout, Gravity.NO_GRAVITY, p.x + OFFSET_X, p.y
+ OFFSET_Y);
final Button addname = (Button) layout.findViewById(R.id.addName);
}
I know it's not a good solution but we can do it like this
make popup as class level object
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
showPopup(...);
}
}
},500);
}

How to show PopupWindow at special location?

I need to show PopupWindow under one Views shown on the screen.
How can I calculate coordinates of needed View and place PopupWindow under it? Code example are more than welcome. Thanks.
Locating an already displayed view is fairly easy - here's what I use in my code:
public static Rect locateView(View v)
{
int[] loc_int = new int[2];
if (v == null) return null;
try
{
v.getLocationOnScreen(loc_int);
} catch (NullPointerException npe)
{
//Happens when the view doesn't exist on screen anymore.
return null;
}
Rect location = new Rect();
location.left = loc_int[0];
location.top = loc_int[1];
location.right = location.left + v.getWidth();
location.bottom = location.top + v.getHeight();
return location;
}
You could then use code similar to what Ernesta suggested to stick the popup in the relevant location:
popup.showAtLocation(parent, Gravity.TOP|Gravity.LEFT, location.left, location.bottom);
This would show the popup directly under the original view - no guarantee that there would be enough room to display the view though.
you have getLeft() and getBottom() to get the exact position of the view in the layout. You also have getWidth() and getHeight() to know the exact space occupied by the view. If you want to position your popup window below a view.
You setLeft() and setTop() methods of the view to position the new popup Window.
To get size of the main application screen without stuff like title and notification bars, override the following method in the class generating the screen in question (sizes are measured in pixels):
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
}
To get the bottom coordinate of the view under which you want to show the popup:
View upperView = ...
int coordinate = upperView.getBottom();
Now as long as height - coordinate is large enough for your popup view, you can simply place the popup like this:
PopupWindow popup = new PopupWindow();
Button button = new Button(this);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
popup.showAtLocation(parent, Gravity.CENTER, 0, coordinate);
}
});
Here, showAtLocation() takes the parent view as an argument together with gravity and location offsets.

Categories

Resources