I've been playing around with alert dialogs. I want to show a dialog that shows particular information about a list item in listview. Just like the android's file manager's detail dialog.
Picture: https://dl.dropbox.com/u/20856352/detailsbox.jpg
Interesting thing about this Details dialog is that it shows list items which are very similar to Preference item in a Preferences Screen. They can be clicked upon, they're showing a very nicely laid out two-line item listitem.
I need to create a similar dialog box but I've no clue how to accomplish this. I've played around a bit. Preference XML cannot be used as alertdialog's layout. And I'm unable to develop a layout that looks similar to the above pic. Need help / guideline how to achieve this.
Faraz Azhar
You probably don't want to use a custom dialog because it will be difficult to replicate the look of the AlertDialog. An AlertDialog can display a list of items using AlertDialog.setListAdapter. You can customize the list of items to show two rows of text per item by using a custom implementation of ListAdapter. The attached screenshot was produced by the below code and xml.
public class Temp extends Activity
{
private String[] listItemsFirstRow = {"item 1", "item 2", "item 3"};
private String[] listItemsSecondRow = {"item 1", "item 2", "item 3"};
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setAdapter(new MyAdapter(), null);
builder.setTitle("Title");
builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
class MyAdapter extends BaseAdapter
{
#Override
public int getCount()
{
return listItemsFirstRow.length;
}
#Override
public Object getItem(int position)
{
//this isn't great
return listItemsFirstRow[position];
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
convertView = getLayoutInflater().inflate(R.layout.main, null);
}
((TextView)convertView.findViewById(R.id.text1)).setText( listItemsFirstRow[position]);
((TextView)convertView.findViewById(R.id.text2)).setText( listItemsSecondRow[position]);
return convertView;
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:minHeight=![enter image description here][2]"?android:attr/listPreferredItemHeight"
android:orientation="vertical"
android:gravity="center_vertical"
android:paddingLeft="15dip"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Just made your xml file same as regular screen/page
then put this code on your onCreate()
AlertDialog.Builder builder;
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_info,
(ViewGroup) findViewById(R.id.toast_layout_root));
builder = new AlertDialog.Builder(this);
builder.setView(layout);
alertDialog = builder.create();
which r.layout.toast_info is your xml file
and r.id.toast_layout_root is your root xml id (eg. '<'linearlayout android:id="+#id...."'>' )
and when you want to show it just write this line
alertDialog.show();
My suggestion would be to use an Activity as a dialog. This way it is pretty easy to create a custom dialog. Here is a small example which I think you can build upon.
**Activity**
public class CustomDialogEx extends Activity implements OnClickListener {
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(this);
}
#Override
public void onClick(View v) { // pass your string data via this intent to the custom view
// show the custom dialog
Intent i = new Intent();
// i.putExtra(<your key/value pairs here>
i.setClass(this, DialogActivity.class);
startActivity(i);
}
}
****************************************************************************
**Custom Dialog**
// The Activity will serve as the Dialog
public class DialogActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.your_dialog_layout);
Intent i = new Intent();
Bundle b = getIntent().getExtras();
b.getString(<your key>)
}
}
*****************************************************************************
**AndroidManifest**
<activity
android:name="DialogActivity"
android:configChanges="keyboardHidden|orientation"
android:theme="#android:style/Theme.Dialog" >
</activity>
this may also help you
public class ShareDialog extends Dialog implements android.view.View.OnClickListener{
Context mcontContext;
Button btnok;
Listview lstview;
public ShareDialog(Context context) {
super(context);
mcontContext= context;
//pls replace with your dialog.xml file
setContentView(R.layout.sharedialog);
bindComponent();
addListener();
}
private void bindComponent() {
// TODO Auto-generated method stub
lstview=(Listview) findViewById(R.id.lstdetail);
btnok=(Button) findViewById(R.id.btnok);
//bind here listview with your adpter
}
private void addListener()
{
btnshareviwifi.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnok:
dismiss();
break;
default:
break;
}
}
}
and where you want to show
ShareDialog shobje=new ShareDialog (context);
shobje.show()
Related
In my app I have implemented this custom dialog (which has a fairly complex layout) by extending DialogFragment. I expect this dialog to pop up when I click a button in my layout. (Which I have successfully achieved). But the problem is that the dialog shows up in a janky manner.
My custom dialog class:
public class CustomizeDialog extends DialogFragment implements AdapterView.OnItemSelectedListener {
// field declarations go here
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.customize_dialog, null);
builder.setView(view)
.setTitle("Customize")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Let's go!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("fromDialog");
intent.putExtra("ratio",getRatio(paperSizeSpinner.getSelectedItem().toString()));
if(isOrientationSpinnerVisible){
intent.putExtra("isCustom",false);
intent.putExtra("orientation",orientationSpinner.getSelectedItem().toString());
} else {
intent.putExtra("isCustom",true);
}
intentProvider.getIntent(intent);
}
});
widthEditText = view.findViewById(R.id.width_et);
heightEditText = view.findViewById(R.id.height_et);
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
paperSizeSpinner = view.findViewById(R.id.paper_size_spinner);
orientationSpinner = view.findViewById(R.id.orientation_spinner);
// ArrayList for populating paperSize spinner via paperSizeAdapter
ArrayList<String> paperSizes = new ArrayList<>();
paperSizes.add("A0");
paperSizes.add("A1");
paperSizes.add("A2");
paperSizes.add("A3");
paperSizes.add("A4");
paperSizes.add("A5");
paperSizes.add("Custom");
// ArrayList for populating orientation spinner via orientationAdapter
ArrayList<String> orientation = new ArrayList<>();
orientation.add("Portrait");
orientation.add("Landscape");
// arrayAdapters containing arraylists to populate spinners
ArrayAdapter paperSizeAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, paperSizes);
ArrayAdapter orientationAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, orientation);
paperSizeSpinner.setAdapter(paperSizeAdapter);
orientationSpinner.setAdapter(orientationAdapter);
paperSizeSpinner.setSelection(4);
paperSizeSpinner.setOnItemSelectedListener(this);
orientationSpinner.setOnItemSelectedListener(this);
return builder.create();
}
// These are some important complex ui functionalities
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.paper_size_spinner) {
if (position == 6) {
widthEditText.setEnabled(true);
heightEditText.setEnabled(true);
orientationSpinner.setEnabled(false);
isOrientationSpinnerVisible = false;
} else {
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
orientationSpinner.setEnabled(true);
isOrientationSpinnerVisible = true;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
// interface used to communicate with the parent activity
public interface IntentProvider {
// this method is used to provide the intent to the parent activity
void getIntent(Intent intent);
}
// instantiating the interface object and throwing error if parent activity does not implement this interface
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
intentProvider = (IntentProvider) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement IntentProvider");
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity implements CustomizeDialog.IntentProvider {
// field declarations go here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image);
// instantiating the dialog
final CustomizeDialog dialog = new CustomizeDialog();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// showing the dialog on click
dialog.show(getSupportFragmentManager(),"");
}
});
}
// via this method I receive the intent from the dialog
// I know intent might not be the best option for this function but let's let it be here for now
#Override
public void getIntent(Intent intent) {
ratio = intent.getFloatExtra("ratio",3);
isCustom = intent.getBooleanExtra("isCustom",false);
orientation = intent.getStringExtra("orientation");
launchChooser();
}
}
Let me know in the comments if you want the layout code for the dialog.
What I tried:
Implementing threading so that my dialog is ready in a background thread and show it onButtonClick. But this is not allowed in general as any other thread except UI thread aren't supposed to touch UI related events.
Using onCreateView instead of onCreateDialog to inflate the layout directly.
Making the dialog a global variable, initialized it in onCreate and then show the dialog onButtonClick.
Switched to CONSTRAINT LAYOUT
Using an activity as a dialog by setting the dialog theme to the activity in the manifest file.
Launched my app in a device with better hardware than mine.
BUT NOTHING WORKED
What I want:
Why is my dialog janky? and what I need to do to make the dialog pop up faster?
In case anybody wants here's the link to my app repo on github.
AlertDialog and DialogFragment frameworks are slow because they need to some time to do calculations and fragment stuffs. So a solution to this problem is, using the Dialog framework straight away.
Use the Dialog framework's constructor to initialize a Dialog object like this:
Dialog dialog = new Dialog(context, R.style.Theme_AppCompat_Dialog);
// the second parameter is not compulsory and you can use other themes as well
Define the layout and then use dialog.setContentView(R.layout.name_of_layout).
Use dialog.findViewById(R.id.name_of_view) to reference views from the dialog's layout file
And then implement the logic just like anyone would do in an activity class. Find out the best implementation for your use case by reading the official documentation.
I found some similar questions here, but all of their were either really confusing for such a newbie like me or didn't help to solve my problem:
I have a TextView tv. By click on it I want to display a custom AlertDialog with EditText + Cancel- and Update-Buttons. By click on Update-Button of my Dialog I want to replace the text of the same TextView (tv) with the value of EditText from Dialog. Here is one of my attepmts:
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv̶̶C̶̶l̶̶i̶̶c̶̶k̶̶e̶̶d̶ = (TextView) findViewById(R.id.tv_id);
tv.setText("Initial value");
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UpdateDialogFragment updDiag = new UpdateDialogFragment();
updDiag.show(getFragmentManager(), "dialog");
tv.setText(updDiag.value); // I try to get the value of EditText like this, but it doesn't work
}
});
}
public class UpdateDialogFragment extends DialogFragment {
String value; // I try to get the value of EditText like this, but it doesn't work
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
builder.setView(inflater.inflate(R.layout.edit_tv, null))
.setPositiveButton("Update", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
EditText et = (EditText) UpdateDialogFragment.this.getDialog().findViewById(R.id.et_tv);
value = et.getText().toString(); // I try to get the value of EditText like this, but it doesn't work
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
UpdateDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
}
}
And my edit_tv.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/et_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:layout_marginTop="40dp"
android:hint="Enter text ..."
android:layout_gravity="center_horizontal">
<requestFocus />
</EditText>
</LinearLayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.yev.tabletasting.MainActivity">
<TextView
android:id="#+id/tv_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
In my case the Text of tv will be setted to "" (probably null) after click on "Update".
I would be thankful for every advice, thanking you in anticipation!
This is what you should have in your TextView onClickListener:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Write new value for TextView");
final EditText editText = new EditText(this);
builder.setView(editText);
builder.setPositiveButton("Update", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog dialog = builder.create();
dialog.show();
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newValue = editText.getText().toString();
if(newValue.lenght() == 0)
Toast.makeText(this, "You need to type something in the editText", Toast.LENGTH_LONG).show();
}else{
tv.setText(newValue);
dialog.dismiss();
}
});
Maybe some minor changes need to be done because I wrote the code down in here. Hope it helps. Wish you luck :)
LE: you don't need the extra Fragment and xml files for the dialog editText.
Okay, so you haven't really mentioned as to why you prefer to use the DialogFragment rather than just an AlertDialog as what Victor Holotescu answered. But here goes, I tried out your code and managed to receive a NullPointerException when I try to click the Update Button. So I looked at it and modified the code, here it is:
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.tv_id);
tv.setText("Initial value");
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UpdateDialogFragment updDiag = new UpdateDialogFragment().newInstance(tv); // Passed the TextView here
updDiag.show(getFragmentManager(), "dialog");
}
});
}
public static class UpdateDialogFragment extends DialogFragment {
String value; // I try to get the value of EditText like this, but it doesn't work
TextView tvToEdit;
public UpdateDialogFragment newInstance(TextView tvToEdit){
UpdateDialogFragment udf = new UpdateDialogFragment();
udf.tvToEdit = tvToEdit;
return udf;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
builder.setView(inflater.inflate(R.layout.edit_tv, null))
.setPositiveButton("Update", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
EditText et = (EditText) UpdateDialogFragment.this.getDialog().findViewById(R.id.et_tv);
value = et.getText().toString();
tvToEdit.setText(value);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
UpdateDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
}
}
}
I added some TODO comments (labeled with Read comments below. :)) inside the code, check them out. I tested it and it runs properly. Hope this was able to help you in some way. For more information regarding AlertDialogs and DialogFragments, here's a good post -- DialogFragment advantages over AlertDialog.
EDIT
Okay. So I edited it where you just pass a TextView to the UpdateDialogFragment by creating a newInstance method -- referenced it here SetText of TextView in DialogFragment from Calling Activity -- Hope this helps. :)
I created a alertDialog with a list, but for me keeps indoors.
public class Day extends ListFragment{
private final int IDD_LIST_TIMES = 1;
AlertDialog.Builder builder;
String[] times = { "09:00", "15:00", "19:00", "20:00", "23:00" };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TimeAdapter myListAdapter = new TimeAdapter(getActivity(), R.layout.text_fragment, times);
setListAdapter(myListAdapter);
myListAdapter.notifyDataSetChanged();}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView =inflater.inflate(R.layout.listview, container, false);
ListView lv = (ListView)rootView.findViewById(android.R.id.list);
lv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) { case android.R.id.list:
showDialog(IDD_LIST_TIMES);
break;
}}
});
return rootView;
}
protected Dialog onCreateDialog(int id) {
switch (id) { case IDD_LIST_TIMES:
final String[] mTimes = {"for 5 minutes", "for 10 minutes", "for 15 minutes"};
builder = new AlertDialog.Builder(this);
builder.setTitle("Alarm clock");
builder.setItems(mTimes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int item) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
"Alarm clock " + mTimes[item],
Toast.LENGTH_SHORT).show();
}});
builder.setCancelable(false);
return builder.create();
default:
return null;
}
}
}
but an error appears constantly for me, where red line "new AlertDialog.Builder(this)"
Why? Prompt me, how to write.
If you want to display a spinner as dialog you can use below code in XML:
<Spinner android:spinnerMode="dropdown" ... />
OR
if you are doing programatically then use:
Spinner sp = new Spinner(this, Spinner.MODE_DIALOG);
OR
If you want to display an ListActivity as Dialog the put this code in your Manifest file:
<activity android:theme="#android:style/Theme.Dialog" />
You are trying to use wrong context object i.e. 'this' which is not applicable for "new AlertDialog.Builder(this)"
First, get the application context in onCreate method and store it into local variable. Use local variable instead of "this" in "new AlertDialog.Builder(this)"
Declare variable
private Context mContext = null;
initialize it in your OnCreate method
#Override
public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mContext = getActivity().getApplicationContext();
Use it in your method
"new AlertDialog.Builder(mContext)"
Hope this will solve your problem.
I am trying to display 'WebView' in 'AlertDialog'.
For that I referred one of the question posted here: Displaying WebView in AlertDialog
It successfully opens the dialog window. But I dont know some how its not showing the web content.
This is my 'print_webview' file, which I am inflating in AlertDialog window:
'<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/root">
<WebView
android:id="#+id/dialog_webview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>'
This is my Java file:
'public class CloudPrintTest extends Activity {
static final int GOOGLE_CLOUD_PRINT_DIALOG = 1; //dialog ID for google cloud print
/** Called when the activity is first created. */
Button printButton;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
printButton = (Button)findViewById(R.id.button1);
printButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//startActivity(new Intent(CloudPrintTest.this,PrintDialog.class));
showDialog(GOOGLE_CLOUD_PRINT_DIALOG);
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
// TODO Auto-generated method stub
switch(id){
case GOOGLE_CLOUD_PRINT_DIALOG:
//LayoutInflater layoutInflator = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//final View dialogLayout = layoutInflator.inflate(R.layout.print_webview, null);
LayoutInflater inflater = LayoutInflater.from(CloudPrintTest.this);
View alertDialogView = inflater.inflate(R.layout.print_webview, null);
WebView myWebView = (WebView)alertDialogView.findViewById(R.id.dialog_webview);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.setWebViewClient(new PrintTestWebViewClient());
myWebView.loadUrl("http://www.google.com/");
AlertDialog.Builder builder = new AlertDialog.Builder(CloudPrintTest.this);
builder.setView(alertDialogView);
builder.setTitle("Google Cloud Print");
builder.setCancelable(true);
AlertDialog printDialog = builder.create();
return printDialog;
}
return null;
}
private class PrintTestWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}'
I have tried all the possible ways, but didnt get the result.
Please help.
Regards
What i would suggest is you creating an activity.
And when you register it in your manifest. Give it the Dialog look with
<activity android:theme="#android:style/Theme.Dialog">
I have some fragments that need to show a regular dialog. On these dialogs the user can choose a yes/no answer, and then the fragment should behave accordingly.
Now, the Fragment class doesn't have an onCreateDialog() method to override, so I guess I have to implement the dialogs outside, in the containing Activity. It's ok, but then the Activity needs to report back the chosen answer somehow to the fragment. I could of course use a callback pattern here, so the fragment registers itself at the Activity with a listener class, and the Activity would report back the answer thru that, or something like that.
But this seems to be quite a big mess for a simple task as displaying a "simple" yes-no dialog in a fragment. Also, this way my Fragment would be less self-contained.
Is there some cleaner way to do this?
Edit:
The answer to this question doesn't really explain in detail how one should use DialogFragments to display dialogs from Fragments. So AFAIK, the way to go is:
Display a Fragment.
When needed, instantiate a DialogFragment.
Set the original Fragment as the target of this DialogFragment, with .setTargetFragment().
Show the DialogFragment with .show() from the original Fragment.
When the user chooses some option on this DialogFragment, notify the original Fragment about this selection (e.g. the user clicked 'yes'), you can get the reference of the original Fragment with .getTarget().
Dismiss the DialogFragment.
I must cautiously doubt the previously accepted answer that using a DialogFragment is the best option. The intended (primary) purpose of the DialogFragment seems to be to display fragments that are dialogs themselves, not to display fragments that have dialogs to display.
I believe that using the fragment's activity to mediate between the dialog and the fragment is the preferable option.
You should use a DialogFragment instead.
Here is a full example of a yes/no DialogFragment:
The class:
public class SomeDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle("Title")
.setMessage("Sure you wanna do this!")
.setNegativeButton(android.R.string.no, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do nothing (will close dialog)
}
})
.setPositiveButton(android.R.string.yes, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do something
}
})
.create();
}
}
To start dialog:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Create and show the dialog.
SomeDialog newFragment = new SomeDialog ();
newFragment.show(ft, "dialog");
You could also let the class implement onClickListener and use that instead of embedded listeners.
Callback to Activity
If you want to implement callback this is how it is done
In your activity:
YourActivity extends Activity implements OnFragmentClickListener
and
#Override
public void onFragmentClick(int action, Object object) {
switch(action) {
case SOME_ACTION:
//Do your action here
break;
}
}
The callback class:
public interface OnFragmentClickListener {
public void onFragmentClick(int action, Object object);
}
Then to perform a callback from a fragment you need to make sure the listener is attached like this:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentClickListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement listeners!");
}
}
And a callback is performed like this:
mListener.onFragmentClick(SOME_ACTION, null); // null or some important object as second parameter.
For me, it was the following-
MyFragment:
public class MyFragment extends Fragment implements MyDialog.Callback
{
ShowDialog activity_showDialog;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
activity_showDialog = (ShowDialog)activity;
}
catch(ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "ShowDialog interface needs to be implemented by Activity.", e);
throw e;
}
}
#Override
public void onClick(View view)
{
...
MyDialog dialog = new MyDialog();
dialog.setTargetFragment(this, 1); //request code
activity_showDialog.showDialog(dialog);
...
}
#Override
public void accept()
{
//accept
}
#Override
public void decline()
{
//decline
}
#Override
public void cancel()
{
//cancel
}
}
MyDialog:
public class MyDialog extends DialogFragment implements View.OnClickListener
{
private EditText mEditText;
private Button acceptButton;
private Button rejectButton;
private Button cancelButton;
public static interface Callback
{
public void accept();
public void decline();
public void cancel();
}
public MyDialog()
{
// Empty constructor required for DialogFragment
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.dialogfragment, container);
acceptButton = (Button) view.findViewById(R.id.dialogfragment_acceptbtn);
rejectButton = (Button) view.findViewById(R.id.dialogfragment_rejectbtn);
cancelButton = (Button) view.findViewById(R.id.dialogfragment_cancelbtn);
acceptButton.setOnClickListener(this);
rejectButton.setOnClickListener(this);
cancelButton.setOnClickListener(this);
getDialog().setTitle(R.string.dialog_title);
return view;
}
#Override
public void onClick(View v)
{
Callback callback = null;
try
{
callback = (Callback) getTargetFragment();
}
catch (ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "Callback of this class must be implemented by target fragment!", e);
throw e;
}
if (callback != null)
{
if (v == acceptButton)
{
callback.accept();
this.dismiss();
}
else if (v == rejectButton)
{
callback.decline();
this.dismiss();
}
else if (v == cancelButton)
{
callback.cancel();
this.dismiss();
}
}
}
}
Activity:
public class MyActivity extends ActionBarActivity implements ShowDialog
{
..
#Override
public void showDialog(DialogFragment dialogFragment)
{
FragmentManager fragmentManager = getSupportFragmentManager();
dialogFragment.show(fragmentManager, "dialog");
}
}
DialogFragment layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/dialogfragment_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:text="#string/example"/>
<Button
android:id="#+id/dialogfragment_acceptbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true"
android:layout_below="#+id/dialogfragment_textview"
android:text="#string/accept"
/>
<Button
android:id="#+id/dialogfragment_rejectbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_alignLeft="#+id/dialogfragment_acceptbtn"
android:layout_below="#+id/dialogfragment_acceptbtn"
android:text="#string/decline" />
<Button
android:id="#+id/dialogfragment_cancelbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:layout_alignLeft="#+id/dialogfragment_rejectbtn"
android:layout_below="#+id/dialogfragment_rejectbtn"
android:text="#string/cancel" />
<Button
android:id="#+id/dialogfragment_heightfixhiddenbtn"
android:layout_width="200dp"
android:layout_height="20dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:layout_alignLeft="#+id/dialogfragment_cancelbtn"
android:layout_below="#+id/dialogfragment_cancelbtn"
android:background="#android:color/transparent"
android:enabled="false"
android:text=" " />
</RelativeLayout>
As the name dialogfragment_heightfixhiddenbtn shows, I just couldn't figure out a way to fix that the bottom button's height was cut in half despite saying wrap_content, so I added a hidden button to be "cut" in half instead. Sorry for the hack.
I am a beginner myself and I honestly couldn't find a satisfactory answer that I could understand or implement.
So here's an external link that I really helped me achieved what I wanted. It's very straight forward and easy to follow as well.
http://www.helloandroid.com/tutorials/how-display-custom-dialog-your-android-application
THIS WHAT I TRIED TO ACHIEVE WITH THE CODE:
I have a MainActivity that hosts a Fragment. I wanted a dialog to appear on top of the layout to ask for user input and then process the input accordingly.
See a screenshot
Here's what the onCreateView of my fragment looks
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home_activity, container, false);
Button addTransactionBtn = rootView.findViewById(R.id.addTransactionBtn);
addTransactionBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.dialog_trans);
dialog.setTitle("Add an Expense");
dialog.setCancelable(true);
dialog.show();
}
});
I hope it will help you
Let me know if there's any confusion. :)
public void showAlert(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View alertDialogView = inflater.inflate(R.layout.test_dialog, null);
alertDialog.setView(alertDialogView);
TextView textDialog = (TextView) alertDialogView.findViewById(R.id.text_testDialogMsg);
textDialog.setText(questionMissing);
alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
where .test_dialog is of xml custom
public static void OpenDialog (Activity activity, DialogFragment fragment){
final FragmentManager fm = ((FragmentActivity)activity).getSupportFragmentManager();
fragment.show(fm, "tag");
}