Place a button inside DialogFragment's title - android

I show a DialogFragment from another DialogFragment. I need to set title and a button just next to it. I don't want to reimplement the theme and create a custom view inside DialogFragment's content view instead of dialog title (because it's error-prone and time wasting). Is it even possible? I tried many API functions, AlertBuilder, ActionBar, this and that, still didn't found anything that fits my needs.

Try something like this:
// Title
final int titleId = getResources().getIdentifier("alertTitle","id","android");
TextView title = (TextView) popup.findViewById(titleId);
title.setText("My new title");
// Title's parent layout
ViewGroup viewGroup = (ViewGroup) title.getRootView();
// Button
Button button = new Button(this);
button.setText("A Button");
viewGroup.addView(button);
Note: You may need to adjust the button and title objects' LayoutParams.

An update. This can be achieved by calling setCustomTitle on AlertDialog.Builder class. Available since api level 1, and do not require a bunch of code.
Example:
AlertDialog.Builder(getActivity()).setCustomTitle(getActivity().getLayoutInflater().inflate(R.layout.my_custom_view, viewGroup)).create()

Related

Is there a way to extend AlertDialog and then totally take control of its appearance?

I'm looking at the documentation here:
http://developer.android.com/guide/topics/ui/dialogs.html#PassingEvents
And all their examples seem to overlook the developer's potential desire to totally alter the appearance and/or positioning of the OK | Cancel buttons.
I feel like the solution with the DialogFragment comes close, but still there's no obvious way for me to define what View in my activity should BE the OK button, so that I can easily attach the callback to it.
What am I missing? Or is it really not possible to manipulate the appearance and position of the buttons in anything that extends AlertDialog or DialogFragment?
You can use Dialog and add your own custom layout to it and control the appearance of every view in it. Here is an example how you can do this :
final Dialog alert = new Dialog(FingerPaintActivity.this, android.R.style.Theme_Light_Panel);
alert.requestWindowFeature(Window.FEATURE_NO_TITLE); // no title
alert.getWindow().getAttributes().windowAnimations = R.style.PauseDialogAnimation; // this is used for custom animation when dialog is showing and hiding
alert.setContentView(getLayoutInflater().inflate(R.layout.stamps, null)); // here is your custom layout
alert.getWindow().setLayout(width-50, (height-100)); // set height / width
and you can use set listeners to your views (for example a button) like this :
Button myOkBtn = (Button) alert.findViewById(R.id.myOkBtn);
myOkBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});

Custom Layout for Dialog across different versions?

I have a Dialog with a custom layout (very simple). I set it up using the code below:
public static Dialog createGPSDialog(final Activity activity, boolean isLocationEnabled) {
final Dialog dialog = new Dialog(activity, R.style.Theme_Sherlock_Light_Dialog);
LinearLayout contentView = (LinearLayout) activity.getLayoutInflater().inflate(R.layout.dialog_twobutton, null);
dialog.setContentView(contentView);
return dialog;
}
There's some code I omitted, but it isn't relevant. Anyway, this is how it looks in gingerbread:
and this is how it looks on jellybean (probably ics as well):
The title area for the dialog is kept on JB, even after setting ContentView. Is there a workaround for this?
If you want to be completely custom and get rid of the title bar, try adding this line to your code:
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
The key is defining a theme for your dialog. The constructor for Dialog takes a theme resources id. Just use one of android's android.R.theme.xxx.
When using the AlertDialog.Builder you can define a new theme using the contextthemewrapper.
http://developer.android.com/reference/android/view/ContextThemeWrapper.html

Creating Custom AlertDialog ? What is the root view?

what i am trying to do:
Create a custom Alert Dialog. Buttons just like any Alert Dialog but above are two TextEdit input boxes. I don't want to create a custom Dialog but a customized Alert Dialog
Here is what I am trying #3:
http://developer.android.com/guide/topics/ui/dialogs.html
It says:
AlertDialog.Builder builder;
AlertDialog alertDialog;
Context mContext = getApplicationContext();
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.custom_dialog,
(ViewGroup) findViewById(R.id.layout_root));
TextView text = (TextView) layout.findViewById(R.id.text);
text.setText("Hello, this is a custom dialog!");
builder = new AlertDialog.Builder(mContext);
builder.setView(layout);
alertDialog = builder.create();
Documentation says:
View layout = inflater.inflate(R.layout.custom_dialog,
(ViewGroup) findViewById(R.id.layout_root));
where the first parameter is the layout resource ID and the second is the ID of the root View.
Problem is I don't know what the layout root is? this is a dialog I am going to kick of in an Activity. Should I use the layout id if the activity? Is layout_root pulled out of a hat?
Also tried:
View layout = inflater.inflate(R.layout.my_custom_layout,
(ViewGroup) findViewById(android.R.id.content).getRootView());
result null pointer.
Even though an older question, this article might be useful for others who search for this answer:
Layout Inflation as Intended:
If you’ve ever written something like the following code using
LayoutInflater in your Android application:
inflater.inflate(R.layout.my_layout, null);
PLEASE read on, because you’re doing it wrong and I want to explain to
you why.
...BUT...
Every Rule Has An Exception
There are of course instances where you can truly justify a null
parent during inflation, but they are few. One such instance occurs
when you are inflating a custom layout to be attached to an
AlertDialog. Consider the following example where we want to use our
same XML layout but set it as the dialog view:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
View content = LayoutInflater.from(context).inflate(R.layout.item_row, null);
builder.setTitle("My Dialog");
builder.setView(content);
builder.setPositiveButton("OK", null);
builder.show();
The issue here is that AlertDialog.Builder supports a custom view, but
does not provide an implementation of setView() that takes a layout
resource; so you must inflate the XML manually. However, because the
result will go into the dialog, which does not expose its root view
(in fact, it doesn’t exist yet), we do not have access to the eventual
parent of the layout, so we cannot use it for inflation. It turns out,
this is irrelevant, because AlertDialog will erase any LayoutParams on
the layout anyway and replace them with match_parent.
The article has an explanation on why you should supply a parent ViewGroup in most other cases than Dialog building.
Ok. The root view in the documentation refers to the element in the custom layout. So the custom layout will have an outermost view called the root view. You need to give this an Id and than you can pass it in as shown. So first argument is the custom view id, the second argument is id of the root layout element within the custom view.
View layout = inflater.inflate(R.layout.custom_dialog,
(ViewGroup) findViewById(R.id.layout_root));
So in this example given in the documentation above, R.id.layout_root refers to the id you give to say for example the outermost LinearLayout within the custom_dialog layout.
Have you tried this?
View layout = inflater.inflate(R.layout.custom_dialog,null);
builder.setView(layout);
layout.getRootView();
Should give LinearLayout.

Android: setText() for TextView in PopupWindow not working

Basically, I have a TextView in a layout which I use for a PopupWindow. I show this PopupWindow when a user clicks a button; I want to be able to dynamically change the text in the PopupWindow upon button click. However, findViewById(my_textview).setText() does not seem to do anything, and indeed causes the PopupWindow to no longer show when I click the button.
I can set text from the layout xml fine.
Anyone know what's up with this? Thanks-
I solved the problem. For whatever reason you need to call popup.getContentView().findViewById instead of just findViewById (where popup is your PopupWindow object). I wasn't getting a NullPointerException before so I'm not exactly sure why this fixed the issue but it did.
So the code goes something like:
PopupWindow pw = new PopupWindow(your layout and params here);
((TextView)pw.getContentView().findViewById(R.id.my_textview)).setText("hello there");
pw.showAtLocation(your params here);
You will be able to find the views with the "findViewById" only using the view you inflated the popupWindow before
like this
private View viewPopUp;
private PopupWindow windowPopUp;
//...
//form_popup is the template to the popup
viewPopUp = mContext.getLayoutInflater().inflate(R.layout.form_popup, null);
windowPopUp = new PopupWindow(viewPopUp, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
//...
viewPopUp.findViewById(R.id.popupTopTitle);
viewPopUp.findViewById(R.id.popupMiddleMsg);
//...

Android - change custom title view at run time

I am using a custom title view in my application for each activity. In one of the activities, based on button clicks I need to change the custom title view. Now this works fine every time when I make a call to setFeatureInt.
But if I try to update any items in the custom title (say change the text of a button or a text view on the title), the update does not take place.
Debugging through the code shows that the text view and button instances are not null and I can also see the custom title bar. But the text on the text view or the button is not updated. Has anyone else faced this problem?
How do I resolve it?
Thanks.
EDIT
Here's what I tried. Does not get updated even on calling postInvalidate.
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.text_title);
TextView databar = (TextView) findViewById(R.id.title_text);
databar.setText("Some Text");
databar.postInvalidate();
Button leftButton = (Button) findViewById(R.id.left_btn);
leftButton.setOnClickListener(mLeftListener);
leftButton.setText("Left Btn");
leftButton.postInvalidate();
Button rightBtn = (Button) findViewById(R.id.right_btn);
rightBtn.setOnClickListener(mRightListener);
rightBtn.postInvalidate();
The problem is that the only Window implementation (PhoneWindow) uses a LayoutInflater in its setFeatureInt method and instantiates the new layout with inflate and attachToRoot=true. Consequently, when you call setFeatureInt, the new layouts are not replaced but attached to the internal title container and thus drawn on top of each other.
You can workaround this by using the following helper method instead of setFeatureInt. The helper simply removes all views from the internal title container before the new custom title feature is set:
private void setCustomTitleFeatureInt(int value) {
try {
// retrieve value for com.android.internal.R.id.title_container(=0x1020149)
int titleContainerId = (Integer) Class.forName(
"com.android.internal.R$id").getField("title_container").get(null);
// remove all views from titleContainer
((ViewGroup) getWindow().findViewById(titleContainerId)).removeAllViews();
// add new custom title view
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, value);
} catch(Exception ex) {
// whatever you want to do here..
}
}
I'm not sure whether the current setFeatureInt behaviour is intended, but it is certainly not documented one way or the other which is why I'll take this to the android devs ;)
EDIT
As pointed out in the comments, the aforementioned workaround is not ideal. Instead of relying on the com.android.internal.R.id.title_container constant you could simply hide the old custom title whenever you set a new one.
Let's assume you have two custom title layouts:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/custom_title_1" ...
and
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/custom_title_2" ...
and you want to replace custom_title_1 with custom_title_2, you could hide former and use setFeatureInt to add the latter:
findViewById(R.id.custom_title_1).setVisibility(View.GONE);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_2);
The correct way to do this is as follows:
requestWindowFeature( Window.FEATURE_CUSTOM_TITLE );
setContentView( R.layout.my_layout );
getWindow().setFeatureInt( Window.FEATURE_CUSTOM_TITLE, R.layout.my_custom_title );
super.onCreate( savedInstanceState );
Please note that the order of these statements is very important.
If you call super.onCreate() before any of the other statements you will get a blank title bar, which the hack of finding the title bar id and removing all the Views from it will fix but is not recommended.
Are you calling invalidate or postInvalidate to redraw the view after updating the text? If it's a custom View, can you put a breakpoint in the draw code to make sure it's getting called?
If you're on the UI thread, you can call 'invalidate' if you're not, you must call 'postInvalidate' or the view won't redraw itself.
Just my 2c worth:
When working in a MapActivity, requesting a custom title resulted in no title at all being shown.
Luckily, all I wanted to do was to set the title text differently, and I soon realized that just calling setTitle() inside of onCreate() worked for me (I called it after I called setContentView())
Sorry, but I don't have time right now to debug this any more and figure out why what I was doing didn't work, and why changing it made it work. As I said, just thought this might help someone out down the road.

Categories

Resources