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;
});
}
}
Related
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(); }
});
In my project i use viewPager for show some fragments.
In one of fragments i want click on button.
I write below codes but when click on button not call onClickListener and not show Toast for me!
My codes in fragment :
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
list_item = getActivity().findViewById(R.id.list_item);
list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (clickFlag) {
AuctionTodayListAdapter adapter = new AuctionTodayListAdapter(getActivity(), R.layout.list_item_auction_large_new, Constants.auction.getToday());
list.setAdapter(adapter);
clickFlag = false;
list_item.setImageResource(R.drawable.list_icon);
Toast.makeText(context, ""+clickFlag, Toast.LENGTH_SHORT).show();
} else {
AuctionTodayListAdapter adapter = new AuctionTodayListAdapter(getActivity(), R.layout.list_item_auction_normal_soon, Constants.auction.getToday());
list.setAdapter(adapter);
clickFlag = true;
list_item.setImageResource(R.drawable.list);
Toast.makeText(context, ""+clickFlag, Toast.LENGTH_SHORT).show();
}
}
});
}
}, 50);
}
}
How can i fix this issue?
Why are you overriding setUserVisibleHint to set up a click listener?
UPDATE:
setUserVisibleHint has nothing to do with toolbar buttons ... that method is for you to call to let the system know the fragment is not visible. It's not normally called by the system, which is why your toast is never shown.
If the button you're trying to find is a toolbar item, you need to interact with it using the onCreateOptionsMenu and onOptionsItemSelected methods instead.
This is the sort of thing one does in onCreateView:
#Override
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = // inflate view from layout resource
list_item = getActivity().findViewById(R.id.list_item); // Get toolbar item
list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do you click stuff
}
}
}
Then, if you only want to interact with this button when this fragment is active, you can show and hide it in onStart() and onStop, respectively.
#Override
public void onStart() {
super.onStart();
list_item.setVisibility(View.VISIBLE);
}
#Override
public void onStop() {
super.onStop();
list_item.setVisibility(View.GONE);
}
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.
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();
}
}
I have a button in a fragment class that I'd like to have trigger a method in the parent activity. I've implemented an interface for this.
My issue is that the View.onClickListener is giving me the following error:
Class 'Anonymous class derived from onClickListener' must either be declared abstract or implement abstract method 'onClick(View)' in 'onClickListener'
Which is odd, because I'm implementing onClick(View).
Here is the code in my Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(com.zlaporta.chessgame.R.layout.gamedescfragment, container, false);
final Button make_move = (Button) v.findViewById(R.id.make_move);
make_move.setOnClickListener(new ***View.OnClickListener()*** {
public void OnClick(View v) {
makeMoveCallback.makeMoveMethod();
}
});
The stars indicate the portion of the code that Android Studio doesn't like.
Do it using Anonymous inner class in an object:
//declaring OnClickListener as an object
private OnClickListener btnClick = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
};
//passing listener object to button
make_move.setOnClickListener(btnClick);
Hope this will help :)
Just a typo: Replace the method name
OnClick
with
onClick
Could you try passing the OnClickListener from a method
e.g.,
private View.OnClickListener getButtonOnClickListener() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
// this is the code
}
};
}
and then using make_move.setOnClickListener(getButtonOnClickListener());
This is best way to using click event for button. using onClick listener implementing. use below code.
public class MyFragment extends Fragment implements OnClickListener {
Button mButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_layout, null);
mButton = (Button) view.findViewById(R.id.button1);
mButton.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
if (v == mButton) {
// Do something on click button
}
}
}
If using every click event separately it take more space. its better to use this code.
Add #Override above onClick method
Or you can use below method of button click Listener in OnActivityCreated() methos of Fragment.
make_move.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
makeMoveCallback.makeMoveMethod();
}
});