My app is a full screen app. It goes full width and does not show a status bar, uses CutoutMode and hides controls like (Home and Back). This also works well.
However, when I create a PopUpWindow, these settings don't seem to take effect. See the following image:
I would have expected that the quadrangles marked in red on the left and right would also be in the corresponding shade of gray.
My code to initialize the PopUp Window looks like this:
val inflater =
view.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
?: return
// Inflate a custom view using layout inflater
val popUpView = inflater.inflate(R.layout.view_change_name, null)
//popUpView.animation = AnimationUtils.loadAnimation(view.context, R.anim.fade_in_animation)
// Initialize a new instance of popup window
val popupWindow = PopupWindow(
popUpView, // Custom view to show in popup window
LinearLayout.LayoutParams.MATCH_PARENT, // Width of popup window
LinearLayout.LayoutParams.MATCH_PARENT, // Window height
true
)
popupWindow.animationStyle = R.style.PopUpWindowAnimation
popupWindow.isFocusable = true
popupWindow.isOutsideTouchable = true
popupWindow.update(
0,
0,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
//Set the location of the window on the screen
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0)
My method to get the full screen in my activity works like this.
fun Activity.fullscreen() {
with(WindowInsetsControllerCompat(window, window.decorView)) {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
hide(Type.systemBars())
}
}
So my idea was to get a decorView in the PopUpWindow. But I think the PopUpWindow has not a decorView. I'm running out of ideas. Does anyone have an approach or solution?
How stupid. After I post this question I found an answer.
Use
popupWindow.isClippingEnabled = false
Documentation
#param enabled false if the window should be allowed to extend outside of the screen
I have a relative layout that occupies 100% of the screen. I call many custom dialogs and always works well. I get positioning and correct height and width with no problems.
However, now I need a dialog that is 100% of screen height and 100% of screen width. I get 100% width but I don't get 100% height. The maximum is around 95 of height.
I've reduced my code to a minimum for better clarity:
var lay = RelativeLayout(this)
var dial = Dialog(cx)
val win = dial.window
val wlp = win.attributes
win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
wlp.apply {
gravity = Gravity.TOP or Gravity.LEFT
x = 0
y = 0
}
win.attributes = wlp
// Here are my widgets linked to lay with lay.addView(widget).
dial.setContentView( // Connection between layout and dialog
lay, ViewGroup.LayoutParams(
screen_width, // variable with screen width in pixels
screen_height )) // variable with screen heigth in pixels
I've read many questions in Stackoverflow. What I have tried:
a) I've used MATCH_PARENT as height.
b) I've tried some windows flags:
win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
win.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
c) I've tried windows attribute property:
wlp.verticalMargin = 0F
No success.
PS: I also have a strange shade border at right and bottom side of dialog that I cannot get rid of it.
Update:
Rahul Khurana solution has killed the problem.
It just use
val dial = Dialog(cx,android.R.style.Theme_Black_NoTitleBar_Fullscreen)
It also eliminates the shade in other no fullscreen dialogs
val dial = Dialog(cx,
android.R.style.Theme_DeviceDefault_Dialog_NoActionBar)
Change the constructor like this:
val dialog=Dialog(this,android.R.style.Theme_Black_NoTitleBar_Fullscreen);
Initialize and show your dialog as below in onStart
override fun onStart() {
super.onStart()
val dial = Dialog(this);
var width = ViewGroup.LayoutParams.MATCH_PARENT;
var height = ViewGroup.LayoutParams.MATCH_PARENT;
dial.getWindow().setLayout(width, height);
dial.show()
}
Use this snippet of code, it will work.
Activity activity = ...;
AlertDialog dialog = ...;
// retrieve display dimension
Rect displayRectangle = new Rect();
Window window = activity.getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(displayRectangle);
// inflate layout
LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.your_layout, null);
layout.setMinimumWidth((int)(displayRectangle.width() * 0.95f));
layout.setMinimumHeight((int)(displayRectangle.height() * 0.95f));
dialog.setView(layout);
dialog?.window?.apply {
requestFeature(Window.FEATURE_NO_TITLE); setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
}
I have studied many questions and answers in Stackoverflow, then I made a dummy function, that I run after a click in my app.
Here is the code:
fun openDialog(cx: Context) {
val alertDialog = Dialog(cx)
var linLayout = LinearLayout(cx)
linLayout.setOrientation(LinearLayout.VERTICAL);
// Set width, height and weight
linLayout.layoutParams = LinearLayout.LayoutParams(500,1000,1F)
// top and left position
linLayout.x = 0F
linLayout.y = 0F
val title = TextView(cx); // dummy view 1
title.setText("Custom Dialog 1")
title.setTextColor(Color.BLACK)
title.setTextSize(20F)
linLayout.addView(title) // add in layout
val msg = TextView(cx) // dummy view 2
msg.setText("Custom Dialog Box 2")
msg.setTextColor(Color.RED)
msg.setTextSize(10F)
linLayout.addView(msg) // add in layout
alertDialog.setContentView(linLayout) // Add the layout in Dialog
alertDialog.show(); // Show the dialog with layout
}
What I get? A proper dialog, but in the middle of the screen with width and height defined by the content. I also try to use the windows linked to the custom dialog without success.
val wlp = win.attributes
wlp.apply {
x = 0
y = 0
height = 1000
width = 500
}
win.attributes = wlp
No changes. However wlp.gravity = Gravity.BOTTOM works, but it's not enough for me. A also try to use win.setLayout(1000,500) without success
The Android documentation states:
Set the width and height layout parameters of the window. The default
for both of these is MATCH_PARENT; you can change them to WRAP_CONTENT
or an absolute value to make a window that is not full-screen.
Why can’t I resize and position the layout that I assign to my dialog?
Has somebody a hint?
The cell phone screen:
Update
I've got to change the position of dialog using
wlp.gravity = Gravity.TOP or Gravity.LEFT
wlp.x = 100 // Relative to left
wlp.y = 200 // relative to top
I keep trying to figure out how to change the width and height.
Set the layout params for the view you're inflating when you set the content :
this line :
alertDialog.setContentView(linLayout)
should be :
alertDialog.setContentView(linLayout, LinearLayout.LayoutParams(500,1000,1F))
You can also remove the explicit setting of the params for the LinearLayout
From the click on a button vi, I passed the same coordinates (vi.x and vi.y) for a popup dialog criation (dialog dial), associated a layout lay, and under it has several buttons.
When I've positioned the popup, with the same x, y of the button, it does it correctly, but with a slight right and down shift, that I can't find any explanation.
PS: I positioned exactly the same place as the button, just to make the below image clear.
Here the dummy code. (It's working in a real app, but I've reduced for clarity):
fun openDialog(xPos: Float, yPos:Float) {
...
val dial = Dialog(this) // this is the context
val win = dial.window
val wlp = win.attributes
wlp.apply {
gravity = Gravity.TOP or Gravity.LEFT
x = xPos
y = yPos
}
win.attributes = wlp
var lay = RelativeLayout(cx)
.....
dial.setContentView(
lay, ViewGroup.LayoutParams(150,500))
dial.show()
}
I've tried many things: horizontalMargin and verticalMargin in window attributes (dial.window.attributes), padding, x, y and gravity in layout lay
Nothing works!
PS 1: My main layout is full screen. Even the battery status is hidden. So the screen has the exact size of screen size.
PS 2: All my views and widgets are programatically created without XML.
Here is the scheme:
I am developing an application for Android and I am using a popup window when the user clicks a specific menu bar object(consisting of small images lined up horizontally) on the bottom of the screen.
On the click I want the popup window to be anchored to the top-left corner of the view that was clicked and be shown on top.
The only methods that seem to be relevant are showAsDropDown(View anchor, int xoff, int yoff) and showAtLocation(View parent, int gravity, int x, int y). The problem with showAsDropDown is that it is anchored to the bottom-left corner of the view.
Is there another way to implement this?
popupWindow.showAtLocation(...) actually shows the window absolutely positioned on the screen (not even the application). The anchor in that call is only used for its window token. The coordinates are offsets from the given gravity.
What you actually want to use is:
popupWindow.showAsDropDown(anchor, offsetX, offsetY, gravity);
This call is only available in API 19+, so in earlier versions you need to use:
popupWindow.showAsDropdown(anchor, offsetX, offsetY);
These calls show the popup window relative to the specified anchor view. Note that the default gravity (when calling without specified gravity) is Gravity.TOP|Gravity.START so if you are explicitly using Gravity.LEFT in various spots in your app you will have a bad time :)
I wrote a sample Kotlin code which will show a PopupWindow above the anchor view.
private fun showPopupWindow(anchor: View) {
PopupWindow(anchor.context).apply {
isOutsideTouchable = true
val inflater = LayoutInflater.from(anchor.context)
contentView = inflater.inflate(R.layout.popup_layout, null).apply {
measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
}
}.also { popupWindow ->
// Absolute location of the anchor view
val location = IntArray(2).apply {
anchor.getLocationOnScreen(this)
}
val size = Size(
popupWindow.contentView.measuredWidth,
popupWindow.contentView.measuredHeight
)
popupWindow.showAtLocation(
anchor,
Gravity.TOP or Gravity.START,
location[0] - (size.width - anchor.width) / 2,
location[1] - size.height
)
}
}
You just needed to move the popupWindow by the height of its anchor using the yoff parameter in the showAsDropDown(View anchor, int xoff, int yoff) syntax.
popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()+popupView.getHeight);
Also, be aware that if the max height allowed to anchor does not allow for the transformation, the popup might not show up properly.
popupWindow.showAtLocation(anchor, Gravity.BOTTOM, 0, anchor.getHeight());
I have this code: PopupWindow below a specific view (Gravity End) for all sdk version.
// display the popup[![enter image description here][1]][1]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mPopupWindow.showAsDropDown(v, 0, 0, Gravity.END);
} else {
mPopupWindow.showAsDropDown(v, v.getWidth() - mPopupWindow.getWidth(), 0);
}
Here View v is ImageButton Calendar.
The one you want to use is showAtLocation(...). You specify the anchor view (the one the user clicks), and position it relative to that via the gravity parameter and offsets. Think of the gravity parameter like the PopupWindow is almost like a child view and the parent view is like a container layout.
You should be able to put Gravity.LEFT | Gravity.TOP as the parameter.
you can display the popup always above the anchor by following
popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()-popupView.getHeight);
Sample example:
ScrollView scrollView = new ScrollView(context);
popupWindow.setContentView(scrollView);
scrollView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
int he=scrollView.getMeasuredHeight();
popupWindow.showAsDropDown(items,0, -items.getHeight()-he);
After using so many solutions, I got one solution to display the PopupWindow above any View in Kotlin.
To display the popup window above the view, you can use the showAsDropDown() function.
popUp.showAsDropDown(v, 0, (-0.2 * v.height).roundToInt(), Gravity.CENTER)
With:
v: View(Anchor)
0: offSetX
(-0.2 * v.height).roundToInt(): offSetY
Gravity.CENTER: Gravity
For example: https://medium.com/#bhattmeet887/popupwindow-above-the-specific-view-kotlin-ab1a199581eb
Here's using the android-x solution, which should even work in case you have a floating UI using SAW permission (System Alert Window) :
#SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
val popupWindow = PopupWindow(anchor.context)
popupWindow.isFocusable = true
popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
popupWindow.contentView = LayoutInflater.from(anchor.context).inflate(R.layout.popup_layout, null)
PopupWindowCompat.showAsDropDown(popupWindow, anchor, 0, 0, Gravity.BOTTOM)
}
This is for alignment of bottom-left.
If you need bottom-center, you could use this, for example:
#SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
val popupWindow = PopupWindow(anchor.context)
popupWindow.isFocusable = true
popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
val inflater = LayoutInflater.from(anchor.context)
val contentView = inflater.inflate(R.layout.popup_layout, null)
contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
popupWindow.contentView = contentView
PopupWindowCompat.showAsDropDown(popupWindow, anchor, (anchor.measuredWidth - contentView.measuredWidth) / 2, 0, Gravity.BOTTOM)
}
popupwindow.showAsDropDown(anchor,0, -125);
this thing work for me