In my application I'm displaying an image inside a dialog. If the user presses the button the dialog appears and takes 80% of the whole screen. The background will be dimmed because that is the default behavior of the Android Dialog.
Dialog dialog = new Dialog(ActQuiz.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
//nothing;
}
});
int width = (int) (getResources().getDisplayMetrics().widthPixels * 0.80);
int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.80);
dialog.getWindow().setLayout(width, height);
ImageView imageView = new ImageView(ActQuiz.this);
String uri = "#drawable/" + info.getInfopicture();
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
Drawable myDrawable = ContextCompat.getDrawable(ActQuiz.this, imageResource);
imageView.setImageDrawable(myDrawable);
new PhotoViewAttacher(imageView);
dialog.addContentView(imageView, new RelativeLayout.LayoutParams(width, height));
dialog.show();
So what I want to achieve is to disable the dimming for a Button, which is visible behind the dialog.
Is this possible or can I only remove the dimming for the whole background?
Is this possible or can I only remove the dimming for the whole background?
It's not possible to instruct Dialog to dim everything except some view, or some region. There is no such an API to do that.
What you can do, is to provide your custom drawable as a background to Dialog's window. That drawable would be given a Rect with coordinates of Button and a Rect of the screen. It will draw a dim (basically a semitransparent black color) everywhere except the provided rectangle. Looks like xfermode SrcOut is the mode that should be applied.
Related
I have an ImageView inside a ConstraintLayout in my Activity. I want to show a custom Dialog (with a custom layout) right on top of this ImageView whenever I click on it.
I have achieved this on my device by tweaking the LayoutParams "x" and "y", but, of course, it fails when I test it on a device with another density (as it also would on a different screen size, I guess). The position is wrong.
How can I make sure my dialog always shows up right above and centered on this ImageView? I'm having a hard time figuring out positions and sizes of views in Android.
priority.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showCustomDialog();
}
});
private void showCustomDialog() {
dialog = new MyDialog(MainActivity.this);
Window window = dialog.getWindow();
WindowManager.LayoutParams param = window.getAttributes();
//any ideas?
dialog.show();
}
I'm creating an AlertDialog with customized view and window background. Setting a ColorDrawable works as expected, but setting a BitmapDrawable from resources makes the dialog appear right at the top of the screen (instead of centered). (Note: I'm talking of the background behind the dialog (normally a transparent grey, not the dialog's background itself!)
Dialog background (#drawable/dialog_bg):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/white" />
<corners android:radius="10dp" />
</shape>
Dialog layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/dialog_bg"
android:orientation="vertical">
<!-- dialog contents -->
</LinearLayout>
Code to show dialog with ColorDrawable: -> works
private void showDialog() {
final AlertDialog dialog;
#SuppressLint("InflateParams") final ViewGroup dialogView = (ViewGroup) activity.getLayoutInflater().inflate(R.layout.my_dialog, null);
dialog = new AlertDialog.Builder(activity).setView(dialogView).create();
// this works:
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.show();
}
Code to show dialog with BitmapDrawable from resources (loading a simple PNG): -> removes centering
private void showDialog() {
final AlertDialog dialog;
#SuppressLint("InflateParams") final ViewGroup dialogView = (ViewGroup) activity.getLayoutInflater().inflate(R.layout.my_dialog, null);
dialog = new AlertDialog.Builder(activity).setView(dialogView).create();
// this sets the background, but un-centers the dialog:
BitmapDrawable drawable = (BitmapDrawable) ResourcesCompat.getDrawable(activity.getResources(), R.drawable.my_bg, null);
dialog.getWindow().setBackgroundDrawable(drawable);
dialog.show();
}
Setting a ColorDrawable works as expected: The background behind the Dialog is colored and the dialog is still centered on screen.
Setting a BitmapDrawable does not work: The background is set but the dialog is moved to the top of the screen.
Things that also didn't work:
loading the drawable with ContextCompat.getDrawable() (which is the same as ResourcesCompat.getDrawable() with the current theme instead of null)
using DisplayMetrics and dialog.getWindow().getAttributes().y (and .x respectively) to calculate margins myself: (height - y) / 2 -> just returns the "normal" dialog margin
setting the gravity to CENTER on either dialog.getWindow().setGravity() or dialog.getWindow().getAttributes().gravity -> this just doesn't change anything
setting the gravity to FILL on either dialog.getWindow().setGravity() or dialog.getWindow().getAttributes().gravity -> this removes dialog margins, but still at the top (even further at the top and left, as margins are removed)
So, does anybody know how to set a background from PNG behind the dialog and keeping its centering on the screen?
We had WindowManger for Dialog to Specify custom window attributes:
The layout params you give here should generally be from values previously retrieved with {#link #getAttributes()}; you probably do not want to blindly create and apply your own, since this will blow away any values set by the framework that you are not interested in.
Just add these property according to your requirement :
/**
* Retrieve the current window attributes associated with this panel.
*
* #return WindowManager.LayoutParams Either the existing window
* attributes object, or a freshly created one if there is none.
*/
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.gravity = Gravity.TOP;
/**
* 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.
*
* #param width The desired layout width of the window.
* #param height The desired layout height of the window.
*
* #see ViewGroup.LayoutParams#height
* #see ViewGroup.LayoutParams#width
*/
dialog.getWindow().setLayout((int) (getScreenWidth(activity)), ViewGroup.LayoutParams.MATCH_PARENT);
dialog.getWindow().setBackgroundDrawableResource(R.drawable.message_email_selected);
/**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously
* retrieved with {#link #getAttributes()}; you probably do not want to
* blindly create and apply your own, since this will blow away any values
* set by the framework that you are not interested in.
*
* #param a The new window attributes, which will completely override any
* current values.
*/
dialog.getWindow().setAttributes(params);
As Example :
final Dialog dialog = new Dialog(getActivity());
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_view);
// dialog.getWindow().setBackgroundDrawable(null);
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
dialog.getWindow().setLayout(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
dialog.getWindow().setAttributes(params);
dialog.show();
//Access dialog views
TextView txt_cancel = (TextView) dialog.findViewById(R.id.txt_cancel);
So I just solved this issue, although I have to admit it's a bit hacky.
First, I disabled fading behind the dialog
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
and manually "faded" the activity by adding a view to it, overlaying the activity with semi-transparent black:
final ViewGroup dimBackgroundView = new FrameLayout(activity);
float dimAlpha = 0.5f;
dimBackgroundView.setBackgroundColor(Color.BLACK);
dimBackgroundView.setAlpha(dimAlpha);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
activityLayout.addView(dimBackgroundView, params);
This also requires me to manually darken the statusbar on supporting devices (SDK 21+):
final int statusBarColor;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
statusBarColor = activity.getWindow().getStatusBarColor();
activity.getWindow().setStatusBarColor(
Color.rgb((int) (Color.red(statusBarColor) + 255 * dimAlpha),
(int) (Color.green(statusBarColor) + 255 * dimAlpha),
(int) (Color.blue(statusBarColor) + 255 * dimAlpha)));
} else {
statusBarColor = Color.BLACK;
}
Afterwards, I added the intended background to the activity (dialogBgView on top of the semi-transparent black view) and went on adding the dialog as normal.
Since I now added all these views to the activity, I need to remove them on dialog dismissal:
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
// remove dim
activityLayout.removeView(dimBackgroundView);
// restore original statusbar color
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().setStatusBarColor(statusBarColor);
}
// remove background image
activityLayout.removeView(dialogBgView);
}
});
It works, but it's really not a nice solution. So if anyone discovers a better way, please feel free to post it here.
I want to achieve the following design: A dialog with custom layout, created programatically. It will contain an EditText and a Button. I want the soft keyboard to pop up when the dialog appears, and I want the dialog to fill the screen horizontally and to be placed right above the keyboard.
Here is what I've done right now:
final AlertDialog obsDialog = new AlertDialog.Builder(ProdutoDetalheActivity.this).create();
final View obsLayout = View.inflate(getApplicationContext(), R.layout.observation_layout, null);
Button obsButton = (Button) obsLayout.findViewById(R.id.observation_button);
obsEdit = (EditText) obsLayout.findViewById(R.id.observation_edit);
obsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
text.setText(String.valueOf(obsEdit.getText()));
obsDialog.dismiss();
}
});
obsDialog.setView(obsLayout);
obsDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
obsDialog.show();
obsEdit.requestFocus();
But this doesn't makes the dialog full width, nor calls the soft keyboard. And I still wonder how can I align the dialog with the keyboard.
I've tried these answers with no success.
Thanks in advance for any help!
[EDIT] I've brought the keyboard up by using the following code:
obsDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
obsDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
[EDIT] Below is a printscreen of the design I want to achieve:
As far as I know, you have to adjust the dialog size/position in the code if you do not want the default size/position.
In you case specifically, you can fist declare adjustResize for the activity's windowSoftInputMode in the AndroidManifest.xml.
After that, you can set your dialog gravity at bottom and set the width in the onStart of the dialog fragment:
...
getDialog().getWindow().setLayout(mWidth, mHeight);
WindowManager.LayoutParams lp = getDialog().getWindow().getAttributes();
lp.gravity = Gravity.BOTTOM;
lp.x = 0; lp.y = 0;
getDialog().getWindow().setAttributes(lp);
...
the mWidth and mHeight are initialized in onCreate, but I think you can do it in the onStart as well. To get the width, I used below code:
Point size = new Point();
WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getSize(size);
mWidth = size.x;
Hope this can meet your requirement. I used this to create a similar dialog, but I do not have a edit in the dialog. And I need it to be at the bottom of the screen.
I want to implement a help overlay for my app.
It should look like this: How do I create a help overlay like you see in a few Android apps and ICS?
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.coach_mark);
dialog.setCanceledOnTouchOutside(true);
//for dismissing anywhere you touch
View masterView = dialog.findViewById(R.id.coach_mark_master_view);
masterView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
This works very well. The RelativeLayout of coach_mark.xml is displayed over my existing layout which was set via setContentView().
Now I want to align the views of coach_mark.xml near the according views of the existing layout, in order to react dynammically to the resolution and screen size. This is what I have tried:
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.BELOW,R.id.view_of_main_layout);
view_of_the_overlay.setLayoutParams(lp);
But the view is displayed just in the middle of the screen.
The only thing I could archieve is to align the view to bottom of screen, but that is not what I want to do.
Thanks for your help.
You can use PopupWindow :
PopupWindow popup=new PopupWindow(this);
popup.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
popup.setWindowLayoutMode(FrameLayout.LayoutParams.WRAP_CONTENT,FrameLayout.LayoutParams.WRAP_CONTENT);
popup.setContentView(R.layout.coach_mark);
View view=findById(R.id.view_of_main_layout);
int[] viewLocation=new int[2];
view.getLocationInWindow(viewLocation)
popup.showAtLocation(view, Gravity.TOP|Gravity.LEFT, viewLocation[0],viewLocation[1]);
you can also adjust to popup location with the last two variables which are the X and Y offest. Their values can also be negative.
My app's main activity is set in the manifest to always be in portrait view. This works fine when I load the app onto the tablet.
However, when I use my menu button and click "Setup", which opens an AlertDialog that inflates an xml layout, the tablet will display the left 2/3 or so of the entire dialog. The rest of it goes offscreen to the right. This case only occurs if I install my app on the tablet while holding it in landscape mode or if I turn the tablet to landscape mode while the app is not running (even if I go back to Portrait and click on the app). The dialog even calls this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); to make sure it stays in portrait (even though the problem persists with this call or not).
In other words, the way the AlertDialog is being displayed in portrait view is that it is blowing up a landscape view (and thus some of it goes offscreen), even though the actual orientation of the AlertDialog is portrait, like it should be.
(I apologize if the wording above was confusing - ask me to clarify anything if needed.)
So why would the tablet do this? I've tested it on a few android mobile phones and this doesn't happen, so I don't understand why the tablet will do this.
SIDE NOTES:
This isn't even occurring for just this AlertDialog either.. my EULA that displays at the start of the app (another AlertDialog) also appears this way if I start the app in landscape mode.
I've even allowed the usability of landscape by getting rid of all calls to specify portrait/landscape mode, and the tablet is still expending the dialog off-screen when held in portrait view on just the tablet, but not the phones.
EDIT:
This code works well on the phone, but the tablet problem still persists. If I uncomment dialog.show(); below, the tablet and phone display the dimensions I want, but on blackness instead of the dimmed main screen. Any ideas?
Calling function does this:
showDialog(EXAMPLE_CASE);
Function that gets called by the calling function:
protected Dialog onCreateDialog(final int id) {
Dialog dialog;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Display display = getWindowManager().getDefaultDisplay();
int mwidth = display.getWidth();
int mheight = display.getHeight();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
switch(id) {
// Example of what all my cases look like (there were way too many to copy)
case EXAMPLE_CASE:
builder.setTitle("Example")
.setMessage("Example message")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialoginterface,int i) {
dialoginterface.dismiss();
showDialog(DIALOG_CHOICE);
}
})
.setCancelable(false);
dialog = builder.create();
break;
}
if (dialog != null) {
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = mwidth;
lp.height = mheight;
lp.x = mwidth;
//lp.y = mheight;
lp.dimAmount=0.0f;
//dialog.show();
dialog.getWindow().setAttributes(lp);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
dialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
removeDialog(id);
}
});
}
return dialog;
}
You could try getting the screen dimensions like this:
Display display = getWindowManager().getDefaultDisplay();
int mwidth = display.getWidth();
int mheight = display.getHeight();
And then alter the Dialog like this:
AlertDialog.Builder adb = new AlertDialog.Builder(this);
Dialog d = adb.setView(new View(this)).create();
// (That new View is just there to have something inside the dialog that can grow big enough to cover the whole screen.)
d.show();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(d.getWindow().getAttributes());
lp.width = mwidth;
lp.height = myheight;
//change position of window on screen
lp.x = mwidth/2; //set these values to what work for you; probably like I have here at
lp.y = mheight/2; //half the screen width and height so it is in center
//set the dim level of the background
lp.dimAmount=0.1f; //change this value for more or less dimming
d.getWindow().setAttributes(lp);
//add a blur/dim flags
d.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND | WindowManager.LayoutParams.FLAG_DIM_BEHIND);
Also, you say you are inflating a custom layout. Have you tried tinkering with the layout_height and layout_width of the views in that layout to see if that makes a difference?