I want to detect whether the DialogFragment is opened from an Activity or Fragment. Because the calling Activity or Fragment will have an Interface attached for a listener.
if Activity is used to show the dialog:
(inside DialogFragment I will write)
listener = (MyListener) getActivity();
else if Fragment is calling the dialog:
listener = (MyListener) getParentFragment;
So, I need to detect who is calling the dialog fragment!
If you ask me to edit your code then do this.
void showDialog() {
DialogFragment newFragment = new MyAlertDialogFragment();
newFragment.setFromActivity(true); pass here.
newFragment.show(getFragmentManager(), "dialog");
}
In your DialogFragment
public static class MyAlertDialogFragment extends DialogFragment {
boolean isFromActivity;
public void setFromActivity(boolean isFromActivity){
this.isFromActivity = isFromActivity;
}
}
If you ask me a suggestion - Pass listener instead of checking from Activity or Fragment.
You should do common code by using setters, so that in future you can just pass listener.
DialogFragment newFragment = new MyAlertDialogFragment();
newFragment.setListener(this); // or use anonymous deriving like new Listener()...
I am using the below style for my question, posting as an answer because it might help someone.
public MyDialog extends DialogFragment{
private MyListener listener;
public static MyDialog newInstance(MyListener callback){
MyDialog dialog = new MyDialog();
dialog.listener = callback;
return dialog;
}
//rest of the Dialog code such as onCreate() etc..
}
And calling from Any Activity or Fragment
ACTIVITY
public MyActivity extends AppCompatActivity implements MyListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
MyDialog dialog = MyDialog.newInstance(this);
dialog.show(getSupportFragmentManager, "TAG");
}
}
FRAGMENT
public MyFragment extends Fragment implements MyListener{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.my_frag_layout, container, false);
MyDialog dialog = MyDialog.newInstance(this);
dialog.show(getChildFragmentManager, "TAG");
return view;
}
}
Please comment if there is any possiblity of error or conditions where it can crash. Thank you!
Related
In my application i am using some fragments, in a viewpager.
I want to show a dialog in a fragment like this:
final Dialog dialog = new Dialog(activity, R.style.DialogTheme);
dialog.show();
The activity is set in the onCreateView like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
activity = getActivity();
}
This is working perfectly, but in some cases like if the app goes in background, and the user comes back to the app, i got an error "Fragment not attached to activity" in the line "dialog.show()".
So to prevent this error i use this:
if(!activity.isFinishing())
dialog.show();
else
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show();
I think this is definitly not the best way...
Is there maybe a solution like reloading the app if the activity isFinishing or even a better solution?
override onAttach method
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof YourActiivty) {
//here is your code
} else {
}
}
public class MyFragment extends Fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
...
}
}
Try to use DialogFragment rather than showing dialog by Dialog class, it will give you more stable view ,just extend your class by "DialogFragment"
public class DemoDialogFragment extends DialogFragment{
public DemoDialogFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_demo_dialog, container, false);
-----------
return rootView;
}
and make function in you activity for calling it
public void showDialogFrag(DialogFragment dialogFragment, String tag) {
dialogFragment.show(getSupportFragmentManager(), tag);
}
Then call this function by this from any fragment
((MainActivity) getActivity()).showDialogFrag(new DemoDialogFragment(), Constant.FragmentTags.DemoDialogFragment);
i am just working with fragments for the 1st time, i have a checkbox inside a fragment and a submit button inside my main activity. what i want to do is when i press submit button i want to toast a message whether the checkbox item is checked or not?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Spinner Dspinner;
private Button Subbtn;
ArrayAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Subbtn = (Button)findViewById(R.id.button);
adapter = ArrayAdapter.createFromResource(this, R.array.spinner_options, android.R.layout.simple_spinner_item);
spinnerListner();
}
public void spinnerListner(){
Dspinner = (Spinner)findViewById(R.id.spinner);
Dspinner.setAdapter(adapter);
Dspinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
getSupportFragmentManager().beginTransaction().replace(R.id.frag, BlankFragment.newInstance()).addToBackStack(null).commit();
break;
case 1:
getSupportFragmentManager().beginTransaction().replace(R.id.frag, BlankFragment2.newInstance()).addToBackStack(null).commit();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
);
}
}
BlankFragment.java
public class BlankFragment extends Fragment {
public BlankFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
public static Fragment newInstance() {
BlankFragment fragment = new BlankFragment();
return fragment;
}
}
BlankFragment2.java
public class BlankFragment2 extends Fragment {
public BlankFragment2(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank_2, container, false);
}
public static Fragment newInstance() {
BlankFragment2 fragment = new BlankFragment2();
return fragment;
}
}
You can use interface to communicate back to MainActivity.
Create a interface and implement it on MainActivity.
Pass the implemented interface to fragment and store it in the fragment
Then When your checkbox state change check that the stored interface is null or not if not null then call the implemented method
of the interface, which is actually implemented in MainActivity.
This way you can communicate back to MainActivity. In MainActivity store your checkbox state and do what you want to do in button press.
Interface
public interface OnStateChanged {
public void onChange(int state);
}
Implement it on MainActivity like
MainActivity implements OnStateChanged {
#Override
public void onChange(int state){
// store your data here
}
Create a variable for OnStateChanged interface and function in Fragment that will pass the interface
In Fragment:
OnStateChanged mListener;
public void setOnStateChangeListener(OnStateChanged listener){
mLinstener = listener;
}
When checkbox state change call the interface function
In Fragment:
//...if state change...
if(mListener!= null) {
mListener.onChange(/*your value*/);
}
Pass the implemented interface instance in MainActivity to fragment
In MainActivity:
fragment.setOnStateChangeListener(this);
There are several ways to realize this function. The easiest way is Defining an interface in your Activity, and let the Fragment implements it.(Or you can define a interface individually and let the Activity implements it, it's the similar solution)
For more solutions you can Google "Fragment and Activity Interaction".
I just can offer you some fragmentary code since I cannot find specific variable names.
First, defining a Interface in your Activity like this:
public static class MainActivity extends AppCompatActivity{
...
//Container Activity must implement this interface
public interface CheckBoxStateCallback{
public Boolean getTheState();
}
...
Second, let your fragments implements it:
public class BlankFragment extends Fragment implements CheckBoxStateCallback{
public BlankFragment(){
}
#Override
public Boolean getTheState(){
//return your checkbox state
}
...
Last, you need to add a click listener onto your Button in Activity:
...
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Boolean b = BlankFragment.newInstance().getTheState();
//then you can make a toast
}
});
...
In MainActivity you would implement an interface CheckboxStatusObserver which we define with a method checkBoxChanged.
public class MainActivity extends AppCompatActivity implements CheckboxStatusObserver{
// other methods
void checkBoxChanged(boolean checkedStatus){
Toast.makeText(getContext(), "status " + checkedStatus, Toast.LENGTH_LONG).show();
}
public interface CheckboxStatusObserver{
void checkBoxChanged(boolean checkedStatus);
}
}
In the Fragment, we would get a reference to the CheckboxStatusObserver as the parent Activity. Then while inflating the contents of the Fragment, we can set up a listener to detect the on change of the checkbox(s). Then we would call the observer.checkBoxChanged(checkedStatus); and pass it the checked status of the checkbox.
public class BlankFragment extends Fragment {
private CheckboxStatusObserver observer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
observer = (CheckboxStatusObserver) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
// Find the checkbox instace using view.findViewById();
// Setup change listener on checkbox instance and notify the observer
{
observer.checkBoxChanged(checkedStatus);
}
return view;
}
}
Whenever the checkbox status changes, the method in the MainActivity will get invoked.
See below links for more information:
https://stackoverflow.com/a/25392549/592025
https://developer.android.com/training/basics/fragments/communicating.html
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Create an Interface in Your MainActivity and click listeners as below
try {
((OnClick) this).onSubmitClicked();
} catch (ClassCastException cce) {
cce.printStackTrace();
}
public interface OnClick {
public void onSubmitClicked();
}
Now implement listeners in your Fragment thus you will get onSubmitClicked implemented method as below Enjoy!
public class BlankFragment extends Fragment implements MainActivity.OnClick{
#Override
public void onSubmitClicked() {
//do something here
}
}
This is yet another way different from what i commented that day this might meet your need
In Main Activty
Blank1Fragment fragment1 = new Blank1Fragment();
Blank2Fragment fragment2 = new Blank2Fragment();
Subbtn..setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(position==0)
fragment1.function();
else if(position==1)
fragment2.function();
}
);
in OnitemClick of spinner
switch (position){
case 0:
position=0;
getSupportFragmentManager().beginTransaction().replace(R.id.frag, fragment1).addToBackStack(null).commit();
break;
case 1:
position=1;
getSupportFragmentManager().beginTransaction().replace(R.id.frag, fragment2).addToBackStack(null).commit();
break;
}
}
Each fragment will have
public class Blank1Fragment extends Fragment {
....
public void function(){
//check which checkbox selected and toast;
}
}
public class Blank2Fragment extends Fragment {
....
public void function(){
//check which checkbox selected and toast;
}
}
I am using a dialog fragment inside a fragment . Now i want to switch from my root fragment to dialog fragment on button click. how is it possible.
Please help me...
dialog fragment code is...
public class MyDialogFragment extends DialogFragment implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.MY_DIALOG);
}
#Override
public void onStart() {
super.onStart();
Dialog d = getDialog();
if (d!=null){
int width = ViewGroup.LayoutParams.MATCH_PARENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
d.getWindow().setLayout(width, height);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.my_fragment, container, false);
return root;
}
on your button click you can use myDialogFragment.show(), just posting a code snippet :
MyDialogFragment myDialogFragment = new MyDialogFragment();
// You cannot access `getFragmentManager()` directly inside fragment so use getActivity()
myDialogFragment.show(getActivity().getFragmentManager(), "DialogFragment");
you should use getFragmentManager() or getSupportFragmentManager depending on which Fragment subclass you are using
Write following code in your button click :
MyDialogFragment myDialogFragment = new MyDialogFragment();
myDialogFragment.show(getFragmentManager(), "myDialogFragment");
If you are displaying the DialogFragment from another fragment. You could try calling getChildFragmentManager() instead of getFragmentManager()
so your code would look like
MyDialogFragment mdf = new MyDialogFragment();
mdf.show(getChildFragmentManager(), "tag");
I have an Activity1 that shows a custom dialogfragment- ExampleDialog. I have implemented a listener, SubmitDialogListener for the dialogfragment to communicate with the activity using onSubmit(). In onSubmit(), I am showing some other dialogfragment. My question is, if I show the same ExampleDialog Fragment from Activity2, should Activity2 implement the SubmitDialogListener interface and implement the onSubmit() method in Activity2 again? Or is there a better way to define the onSubmit() method?
import android.support.v4.app.DialogFragment;
// ...
public class Activity1 extends ActionBarActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
......
showDialog();
}
private void showDialog() {
FragmentManager fm = getSupportFragmentManager();
ExampleDialog exDialog = ExampleDialog.newInstance("Some Title");
exDialog.show(fm, "fragment_edit_name");
}
#Override
public void onSubmit() {
//open new fragments
}
}
public class ExampleDialog extends DialogFragment implements SubmitDialogListener {
public interface SubmitDialogListener {
void onSubmit();
}
public ExampleDialog() {
// Empty constructor required for DialogFragment
}
public static ExampleDialog newInstance(String title) {
ExampleDialog frag = new ExampleDialog();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_name, container);
.........
Button button = (Button) v.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
SubmitDialogListener listener = (SubmitDialogListener) getActivity();
listener.onSubmit();
dismiss();
}
});
return view;
}
}
In this case the Activity should implement the SubmitDialogListener not the Dialog Fragment, like this:
public class Activity1 extends ActionBarActivity implements SubmitDialogListener {
#Override
public void onSubmit() {
//open new fragments
}
}
And if you want to use the same dialog fragment in multiple activities, it's generally best to create it in a separate class file.
Was trying to reuse a complex DialogFragment as a Fragment in an activity layout. I don't want to have to re-write this whole DialogFragment class as it is quite complex. In one spot only does the designers want this layout not as a popup but in a page. Is there a way to get around the DialogFragment from throwing this (From DialogFragment.java):
if (view != null) {
if (view.getParent() != null) {
throw new IllegalStateException("DialogFragment can not be attached to a container view");
}
mDialog.setContentView(view);
}
I went so far as to null out the creation of Dialog in the OnCreateDialog() overridden method and added the overridden method onCreateView(). But still view is not null and throws the IllegalStateException. I have the fragment embedded in the activity layout
<fragment
android:id="#+id/fragment_mine"
android:name="com.test.MyDialogFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible" />
So question is, is there anyway to re-use a DialogFragment as a Fragment in an Activity's layout?
Cant you just use your DialogFragment as a regular fragment ?.
Like so:
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
final int FRAGMENT_ID = 100;
LinearLayout contentView = new LinearLayout(this);
contentView.setOrientation(LinearLayout.VERTICAL);
Button showButton = new Button(this);
showButton.setText("Show Dialog");
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//using TestDialogFragment as a dialog
new TestDialogFragment().show(getSupportFragmentManager(), "dialog");
}
});
contentView.addView(showButton);
final LinearLayout fragmentContainer = new LinearLayout(this);
fragmentContainer.setId(FRAGMENT_ID);
contentView.addView(fragmentContainer);
setContentView(contentView);
//using TestDialogFragment as a Fragment
getSupportFragmentManager().beginTransaction()
.replace(FRAGMENT_ID, new TestDialogFragment()).commit();
}
public static class TestDialogFragment extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView view = new TextView(getActivity());
view.setText("Test Fragment");
return view;
}
}
}