I have a class which extends DialogFragment. When I click on a button, the dialog shows. The first time is normal, I mean the size is the one of the layout of the dialog. However, when I dismiss the dialog and I click on the button for the second, third,... time, the dialog covers all the screen and I don't know why at all. All methods are always called, so why this happens?
Here is the implementation of the DialogFragment:
public class DialogFragmentAzione extends DialogFragment
{
private View view;
private SetVocabulary setVocabulary;
private LinkedList<String> linkedListGruppi;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(getArguments().getSerializable(Constants.codiceArgomentoDialogFragment) instanceof Set)
setVocabulary = (SetVocabulary) getArguments().getSerializable(Constants.codiceArgomentoDialogFragment);
else
linkedListGruppi = (LinkedList<String>) getArguments().getSerializable(Constants.codiceArgomentoDialogFragment);
view = inflater.inflate(R.layout.layoutdialogfragment, container);
view.findViewById(R.id.aggiungiDialog).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
EditText editText = (EditText)view.findViewById(R.id.editTextAggiungi);
String text = editText.getText().toString();
if(text.contains(" ")||text.contains(".")||text.contains(",")||text.contains(";")||text.contains("-")||text.contains("_")
||text.contains(":")||text.contains("#")||text.contains("ç")||text.contains("°")||text.contains("#")||text.contains("§")
||text.contains("{")||text.contains("}")||text.contains("[")||text.contains("]")||text.contains("(")||text.contains(")")
||text.contains("(")||text.contains("!")||text.contains("%")||text.contains("£")||text.contains("&")||text.contains("/")
||text.contains("=")||text.contains("?")||text.contains("'")||text.contains("^")||text.contains("<")||text.contains(">")
||text.contains("<")||text.contains("|")||text.contains("€")||text.contains("+")||text.contains("*"))
Toast.makeText(getActivity(),"Il testo contiene caratteri non ammessi",Toast.LENGTH_SHORT).show();
else if(text.length()<3)
Toast.makeText(getActivity(),"Il testo è troppo corto",Toast.LENGTH_SHORT).show();
else if(text.length()>15)
Toast.makeText(getActivity(),"Il testo è troppo lungo",Toast.LENGTH_SHORT).show();
else
{
if(setVocabulary!=null)
setVocabulary.add(text);
else
linkedListGruppi.add(text);
dismiss();
}
}
});
return view;
}
#Override
public void onActivityCreated(Bundle bundle)
{
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme);
super.onActivityCreated(bundle);
}
}
Here is the creation of the dialog:
dialogFragment = new DialogFragmentAzione();
bundleFragment = new Bundle();
bundleFragment.putSerializable(Constants.codiceArgomentoDialogFragment,setVocabulary);
dialogFragment.setArguments(bundleFragment);
getActivity().findViewById(R.id.floatingActionButton).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
dialogFragment.show(getActivity().getFragmentManager().beginTransaction(), "Dialog");
}
});
The first 4 lines are exectued only one time
Remove this line of code:
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme);
In this way the dialog will be always of the same size.
Related
I am new to android studio and Java. I have create custom dialog box with input textbox. I want to pass data from custom dialog to fragment layout. How can I achieve that ?
I saw this post but didn't get it. Please help me out !
Passing a data from Dialog to Fragment in android
Edited
Here's my code >>
public class IncomeFragment extends Fragment{
TextView title, textRsTotal;
Dialog dialog;
int total = 0;
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
title = view.findViewById(R.id.totalIncomeTitle);
Button button = view.findViewById(R.id.addIncomeBtn);
textRsTotal = view.findViewById(R.id.totalExpenseTitle);
dialog = new Dialog(getActivity());
if (getActivity() != null) {
if (!CheckInternet.isNetworkAvailable(getActivity())) {
//show no internet connection !
}
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.setContentView(R.layout.income_custom_dialog);
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
RadioGroup radioGroup = dialog.findViewById(R.id.radioGroup);
Button buttonAdd = dialog.findViewById(R.id.addBtn);
TextInputEditText editText = dialog.findViewById(R.id.editText);
radioGroup.clearCheck();
radioGroup.animate();
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
RadioButton radioButton = (RadioButton) radioGroup.findViewById(checkedId);
}
});
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int selectedId = radioGroup.getCheckedRadioButtonId();
if (selectedId == -1) {
Toast.makeText(getActivity(), "Please select your income type", Toast.LENGTH_SHORT).show();
} else {
RadioButton radioButton = (RadioButton) radioGroup.findViewById(selectedId);
String getIncome = editText.getText().toString();
Toast.makeText(getActivity(), radioButton.getText() + " is selected & total is Rs."+ total, Toast.LENGTH_SHORT).show();
}
}
});
dialog.show();
}
});
super.onViewCreated(view, savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_income, container, false);
// Inflate the layout for this fragment
return view;
}
}
Ok, try this :
public class IncomeFragment extends Fragment {
TextView title, textRsTotal;
Dialog dialog;
int total = 0;
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
title = view.findViewById(R.id.totalIncomeTitle);
Button button = view.findViewById(R.id.addIncomeBtn);
textRsTotal = view.findViewById(R.id.totalExpenseTitle);
dialog = new Dialog(getActivity());
if (getActivity() != null) {
if (!CheckInternet.isNetworkAvailable(getActivity())) {
//show no internet connection !
}
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showDialog(new MyCallback() {
#Override
public void setText(String text) {
textRsTotal.setText(text);
}
});
}
});
super.onViewCreated(view, savedInstanceState);
}
private void showDialog(MyCallback myCallback) {
dialog.setContentView(R.layout.income_custom_dialog);
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
RadioGroup radioGroup = dialog.findViewById(R.id.radioGroup);
Button buttonAdd = dialog.findViewById(R.id.addBtn);
TextInputEditText editText = dialog.findViewById(R.id.editText);
radioGroup.clearCheck();
radioGroup.animate();
radioGroup.setOnCheckedChangeListener((radioGroup1, checkedId) -> {
RadioButton radioButton = (RadioButton) radioGroup1.findViewById(checkedId);
});
buttonAdd.setOnClickListener(view1 -> {
int selectedId = radioGroup.getCheckedRadioButtonId();
if (selectedId == -1) {
Toast.makeText(getActivity(), "Please select your income type", Toast.LENGTH_SHORT).show();
} else {
RadioButton radioButton = (RadioButton) radioGroup.findViewById(selectedId);
String getIncome = editText.getText().toString();
myCallback.setText(getIncome);
Toast.makeText(getActivity(), radioButton.getText() + " is selected & total is Rs." + total, Toast.LENGTH_SHORT).show();
}
});
dialog.show();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_income, container, false);
return view;
}
public interface MyCallback {
void setText(String text);
}
}
There are more than one method to achieve that, the one mentioned in the url you provided is suggesting to use a simple callback to forward event and data back to the calling fragment. So the pieces you are needing are all there:
Write a callback interface: public interface Callback1{ public void onInteraction(String thingToCommunicateBack); }
In your fragment: and while building the instance of your dialog, pass an instance you've built of Callback1 to that dialog like this Callback1 mCallback = new Callback1() { public void onInteraction(String thingToCommunicateBack) { /*TODO receive data, handle and update layout*/ }; (the whole fragment could be that instance using the keyword this if you decide to implement the interface there instead, like this
class Fragment1 extends Fragment implements Callback1 and implement its method within fragment's class after the keyword override)
In your Dialog class: when the interaction (click) that should trigger the event and send data back happens, invoke callback's method like this: mCallback1.onInteraction("text from your EditText to pass")
Now, you passed some data from custom dialog back to a fragment.
I am using BottomSheetDialogFragment in my android app. I am using Java. I show the bottomsheet by:
ActionBottomDialogFragment dialogFragment = ActionBottomDialogFragment.newInstance();
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialogFragment.show(getActivity().getSupportFragmentManager(), ActionBottomDialogFragment.TAG);
}
});
What I see is it calls onCreateDialog method and then calls onViewCreated methods. For the first time this is okay.
Now I hide the bottom sheet using:
ImageButton close = view.findViewById(R.id.closeButton);
close.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
Then when I press the show button again, it calls onCreateDialog method again. I have a dynamic list of choice chips which I want the state to be just as I left it. If I left it on checking 'Choice A', it should show up selected the next time I open the bottom sheet. I need the state to be maintained.
What is happening is it rebuilds the choice chips from start, so the state is lost.
How can I just show / hide the bottom sheet without recreating?
UI will be always created again when you call show(). It's better to use a sharedViewModel in bottomSheetFragment and the parent activity/fragment. You should save the fields being selected in the viewmodel and use it the bottomSheet. This way the state will be maintained.
You can use show() & hide() of the dialog itself; this will keep the fragment alive.
So, in your case:
To show it:
ActionBottomDialogFragment dialogFragment;
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (dialogFragment == null) {
dialogFragment = ActionBottomDialogFragment.newInstance();
dialogFragment.show(getActivity().getSupportFragmentManager(), ActionBottomDialogFragment.TAG);
} else {
dialogFragment.getDialog().show();
}
}
});
And to hide it:
ImageButton close = view.findViewById(R.id.closeButton);
close.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialogFragment.getDialog().hide();
}
});
But this requires to handle the side effects when dismissing the fragments using the back button and when touching outside.
Here's a custom DialogFragment that handles that:
public class BottomSheet extends BottomSheetDialogFragment {
public BottomSheet() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_sheet_layout, container, false);
return view;
}
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
return new BottomSheetDialog(requireContext(), getTheme()) {
#Override
public void onBackPressed() {
getDialog().hide();
}
};
]
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void onStart() {
super.onStart();
setCancelable(false);
getDialog().setCanceledOnTouchOutside(false);
final View outsideView =
requireDialog().findViewById(com.google.android.material.R.id.touch_outside);
outsideView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_UP)
getDialog().hide();
return false;
});
}
}
I have two buttons in MainActivity, the first one opens a custom DialogFragment with some spinners and in the other button it resets the spinners of this DialogFragment.
When I click the reset button it calls this method that is in the DialogFragment:
public class FilterDialogFragment extends DialogFragment {
private View view;
// ...
#Nullable
#Override
public View onCreateView(#NotNull LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.dialog_filters, container, false);
// start the spinners and adapters here
return view;
}
public void resetFilters() {
if (view != null) {
categorySpinner.setSelection(0);
productSpinner.setSelection(0);
priceSpinner.setSelection(0);
}
}
// some more codes here
}
My MainActivity:
public class MainActivity extends AppCompatActivity {
private FilterDialogFragment filterDialog;
private Button button_clear;
private Button button_filter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button_clear = findViewById(R.id.button_clear);
button_filter = findViewById(R.id.button_filter);
filterDialog = new FilterDialogFragment();
button_filter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Show the dialog containing filter options
filterDialog.show(getSupportFragmentManager(), FilterDialogFragment.TAG);
}
});
button_clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//reset all filters
filterDialog.resetFilters();
}
});
//some more codes here
}
//some more methods here
}
But by clicking the button that opens the DialogFragment, the values of the Spinners remain the same instead of returning the data of position 0 of each spinner.
Would anyone know how to solve this? I've tried everything and I can not.
The simplest way I ended up finding, was to delete the resetFilters method, and instead I did so:
button_clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//reset all filters
filterDialog = new FilterDialogFragment(); }
});
I have custom DialogFragment which called from another fragment:
final CustomCalendarDialogFragment newFragment = new CustomCalendarDialogFragment("CHOOSE_WEEK");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (newFragment.isAdded()){
newFragment.getDialog().show();
} else {
newFragment.show(getFragmentManager(), "CUSTOM_CALENDAR");
}
}
});
In CustomCalendarDialogFragment when pressed "OK":
getDialog().hide();
After pressed on "OK" DialogFragment is hide, but when I unlock screen DialogFragment is displayed.
How to eliminate it?
You can track the state of showing/hiding the dialog in the tag attribute of the fragment view.
Initially set it as true (equivalent to shown) in onCreateView()
#Nullable
#org.jetbrains.annotations.Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable #org.jetbrains.annotations.Nullable ViewGroup container, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_sheet, container, false);
view.setTag(true);
return view
}
And whenever you show/hide it set it to true/false:
final CustomCalendarDialogFragment newFragment = new CustomCalendarDialogFragment("CHOOSE_WEEK");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (newFragment.isAdded()){
newFragment.getDialog().show();
} else {
newFragment.show(getFragmentManager(), "CUSTOM_CALENDAR");
newFragment.requireView().setTag(true);
}
}
});
And set newFragment.requireView().setTag(false); when you call getDialog().hide();
And when the app goes to the background, check that tag on onResume() to see if you want to keep the dialog shown or hide it:
#Override
protected void onResume() {
super.onResume();
Object tag = newFragment.requireView().getTag();
if (tag instanceof Boolean){
if ((!(boolean)tag))
newFragment.getDialog().hide();
}
}
Fragment 1:
public class homePage extends Fragment {
private OnFragmentInteractionListener mListener;
private View view;
public homePage() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_home_page, container, false);
Button btnLogin = (Button) view.findViewById(R.id.login);
Button btnRegister = (Button) view.findViewById(R.id.register);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loginView();
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
registerView();
}
});
return view;
}
public static homePage newInstance() {
homePage fragment = new homePage();
Bundle args = new Bundle();
return fragment;
}
public void registerView(){}
public void loginView(){}
public interface OnFragmentInteractionListener {
}
}
Acitivty :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
homePage homepage = new homePage();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, homepage)
.commit();
}
}
}
My fragment1 has two buttons with the id's "login" and "register". Whenever login is clicked, I want to go to my fragment_login.xml, and when register is clicked I want to go to my fragment_register.xml. Should I create these functions in my activity or in my fragment? And how should I do this? I'm fairly new to android and I'm trying to learn these basic things atm. Thanks for the help :(
Login context: "com.example.hoofdgebruiker.winkelskortrijk.login"
Register context: "com.example.hoofdgebruiker.winkelskortrijk.register"
You have to make a communication between Fragment objects via an Interface.
The Activity that make the switch between your fragments needs to implement that Interface.
So, in your case your classes must be defined as follows. This is your Interface, it helps you to tell your activity that a button has been clicked from within your Fragment:
public interface HomeClickListener {
void onLoginClick();
void onRegisterClick();
}
Your Activity needs to implement the above interface in order to be notified when a button has been clicked:
public class HomeActivity extends Activity implements HomeClickListener {
void onLoginClick() {
// Your activity code to replace your current Fragment with your Login fragment
}
void onRegisterClick() {
// Your activity code to replace your current Fragment with your Register fragment
}
}
Your fragment is hosted by an Activity, so you need to have a reference to it and notify it via an Interface:
public class LoginFragment extends Fragment {
final HomeClickListener homeClickListener
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
homeClickListener = (homeClickListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_home_page, container, false);
Button btnLogin = (Button) view.findViewById(R.id.login);
Button btnRegister = (Button) view.findViewById(R.id.register);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
homeClickListener.onLoginClick();
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
homeClickListener.onRegisterClick();
}
});
return view;
}
}
More information here.