Why dialog position shows a small displacement? - android

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:

Related

Android: How to slide a PopupWindow between 2 points?

I want to slide a PopupWindow from the bottom of the screen to some point above it, say center.
I have the following logic so far
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
val popupView: View = inflater.inflate(R.layout.popup_window, null)
val width = LinearLayout.LayoutParams.WRAP_CONTENT
val height = LinearLayout.LayoutParams.WRAP_CONTENT
val focusable = true // lets taps outside the popup also dismiss it
val popupWindow = PopupWindow(popupView, width, height, focusable)
val slide = Slide()
slide.apply {
duration = 300
slideEdge = Gravity.BOTTOM
}
view?.doOnAttach {
popupWindow.isFocusable = true
popupWindow.enterTransition = slide
popupWindow.exitTransition = slide
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0)
}
I am able to slide the window between its width. So what this does is that the sliding happens from -w/2 where w is the width of the window and ends at w/2. Which maybe expected since the position of the window is set as 0, 0. However I want the sliding to happen between 2 specific points. Like the sliding should start from the bottom of the screen and it should continue to slide till it reaches the coordinate 0,0.
I found a workaround by expanding the width of the window to the portion below 0,0 but that cause the views below it to not be clickable. So this doesn't work in my case. Is there a way to do this sliding? Thanks!

How programmatically make a custom dialog be 100% of screen height?

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)
}

How to place a layout completely on top of keyboard in bottom sheet dialog fragment

I have a bottom sheet dialog fragment in an Activity. When the softkeyboard is shown I need to push the complete dialog fragment layout to the top of keyboard.
I have tried various ways like using GRAVITY.TOP , bottomMargin for the dialog increasing the height etc.
None of the above ways are working. I want to make the top of bottom sheet dialog fragment align with the parent i.e top of phone.
Since I am using Framelayout to add Bottom Sheet Dialog fragment in activity I am unable to set alignParentTopAttribute . Please let me know if there are any ways of doing this or suggestions to achieve this.
Please find below code that I have tried till now:
view?.viewTreeObserver?.addOnGlobalLayoutListener {
var r = Rect()
view?.getWindowVisibleDisplayFrame(r)
var screenHeight = view?.rootView?.height
var initialHeight = rootLayout.height
var keyPadHeight = screenHeight?.minus(r.bottom)
var layoutParams: Frame.LayoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
if (keyPadHeight!! > screenHeight?.times(0.15)!!) {// 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
}
var window: Window? = dialog?.window
var windowManagerLayoutParams: WindowManager.LayoutParams? = window?.attributes
//Tried this
windowManagerLayoutParams.gravity = GRAVITY.TOP
window.attributes = windowManagerLayoutParams
//Tried this
layoutParams.gravity = Gravity.TOP
rootLayout.layoutParams = layoutParams
} else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
}
}
}
I have also tried adjustResize and stateVisible in manifest. adjustResize will not push complete layout to the top of soft keyboard, there will be a scroll behind the soft keyboard, user will have to scroll to see the complete layout.
But I do not want to have the scroll, user should see the complete layout on top of the soft keyboard as soon as it is visible.

Why can’t I resize and position my dynamic dialog (with no XML associated)?

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

PopupWindow above status bar of Nexus 7 (and status bars of other devices)

I have a PopupWindow which opens after I click an ImageButton:
// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);
// Inflate the tag_popup.xml
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.tagPopupLayout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.tag_popup, viewGroup);
// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
myPopupWindow.setFocusable(true);
myPopupWindow.setOutsideTouchable(false);
// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));
// Set the content of the TextViews, EditTexts and Buttons of the PopupWindow
setPopupContent(...);
// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);
because of the Gravity.NO_GRAVITY, the PopupWindow will be displayed within the borders of the Window. Everything works as intended on my Emulator, but when I run it on my Nexus 7 Tablet, it is partly covered by the Device's bottom status bar.
How can I fix this? Should I somehow get the current PopupWindow's location after the Gravity.NO_GRAVITY took place, then change the y-location to add the Device's Statusbar's height, and then re-draw it? (Will try this, but I think that having the right location to start with instead of re-drawing it is a better solution..)
This is what I came up with:
What we have:
The [x, y]-position we gave to the PopupWindow's showAtLocation-method (we only need the y-position in this, which I named oldY)
What we calculate:
The Popup height
The Status Bar height
The max possible height to be within Window boundaries (screenHeight - statusBarHeight - popupHeight)
What we then check:
We check if the oldY is larger than the maxY
If this is the case, the newY will be the maxY and we re-draw the PopupWindow. If this isn't the case it means we do nothing and just use the oldY as the correct Y-postition.
NOTE 1: I made the code for this, but during debugging it turned out the Status Bar's Height is 0 on both my Emulator and my Nexus Tablet, so just using the screenHeight - popupHeight was enough for me. Still, I included the code to calculate the Bottom Status Bar Height with a boolean in my Config-file to enable/disable this, in case the app is installed on another tablet in the future.
Here it is in code, I just added the description above to make it clear which approach I used to tackle this problem:
// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);
// Inflate the popup.xml
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.popup_layout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.popup, viewGroup);
// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
... // Some more stuff with the PopupWindow's content
// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));
// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);
// Because the PopupWindow is displayed below the Status Bar on some Device's,
// we recalculate it's height:
// Wait until the PopupWindow is done loading by using an OnGlobalLayoutListener:
final int[] finalLoc = loc;
if(layout.getViewTreeObserver().isAlive()){
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
// This will be called once the layout is finished, prior to displaying it
// So we can change the y-position of the PopupWindow just before that
#Override
public void onGlobalLayout() {
// Get the PopupWindow's height
int popupHeight = layout.getHeight();
// Get the Status Bar's height
int statusBarHeight = 0;
// Enable/Disable this in the Config-file
// This isn't needed for the Emulator, nor the Nexus 7 tablet
// Since the calculated Status Bar Height is 0 with both of them
// and the PopupWindow is displayed at its correct position
if(D.WITH_STATUS_BAR_CHECK){
// Check whether the Status bar is at the top or bottom
Rect r = new Rect();
Window w = ChecklistActivity.this.getWindow();
w.getDecorView().getWindowVisibleDisplayFrame(r);
int barHeightCheck = r.top;
// If the barHeightCheck is 0, it means our Status Bar is
// displayed at the bottom and we need to get it's height
// (If the Status Bar is displayed at the top, we use 0 as Status Bar Height)
if(barHeightCheck == 0){
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}
}
// Get the Screen's height:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenHeight = dm.heightPixels;
// Get the old Y-position
int oldY = finalLoc[1];
// Get the max Y-position to be within Window boundaries
int maxY = screenHeight - statusBarHeight - popupHeight;
// Check if the old Y-position is outside the Window boundary
if(oldY > maxY){
// If it is, use the max Y-position as new Y-position,
// and re-draw the PopupWindow
myPopupWindow.dismiss();
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, maxY);
}
// Since we don't want onGlobalLayout to continue forever, we remove the Listener here again
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
NOTE 2: I've set the tag_popup itself to width = match_parent; height = wrap_content on this line:
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
and the main layout of this Popup to width = match_parent; height = match_parent:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xml>
<!-- The DOCTYPE above is added to get rid of the following warning:
"No grammar constraints (DTD or XML schema) detected for the document." -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/popup_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#layout/tag_shape"
android:padding="#dimen/default_margin">
... <!-- Popup's Content (EditTexts, Spinner, TextViews, Button, etc.) -->
</RelativeLayout>
NOTE 3: My app is forced to stay in Portrait mode. I haven't test this in Landscape mode, but I assume some modifications should be made (not sure though). EDIT: Tested and it also works in Landscape mode on my two devices. I don't know if this also works in Landscape Mode with the Bottom Bar Height enabled.
Took me some time, but it works now. Hopefully they will fix PopupWindow's Gravity in the future, so it will never be below a Status bar, unless the programmer wants this themselves and change the PopupWindow's settings. Makes things a lot easier..

Categories

Resources