I successfully implemented a bottom navigation drawer and had used fragments. Now i can switch fragments from the drawer menu.
My problem here is that when I open an item from the drawer menu (example; About Developer), when the user clicks the back button it closes the app. Instead i want the user to return to the Main Activity from any fragment. Help me with this, I don't have much experience.
Here is my code;
How i implement the nav drawer items using drawer adapter with a custom library(SlidingRootNav- https://github.com/yarolegovich/SlidingRootNav);
#Override
public void onItemSelected(int position) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (position == POS_DASHBOARD){
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
else if (position == POS_ABOUT_APP){
((CoordinatorLayout)findViewById(R.id.root_view)).removeAllViews();
AboutAppFragment aboutApp = new AboutAppFragment();
transaction.replace(R.id.container, aboutApp);
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
else if (position == POS_ABOUT_DEVELOPERS){
((CoordinatorLayout)findViewById(R.id.root_view)).removeAllViews();
AboutDeveloper aboutDeveloper = new AboutDeveloper();
transaction.replace(R.id.container, aboutDeveloper);
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
}
Fragment Class
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class AboutDeveloper extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_about_developer,container, false);
// Here I implemented a toolbar at the top for navigation purpose
// but on clicking on the nav icon, the app closes, instead i want to return to the main activity
Toolbar toolbar = root.findViewById(R.id.return_home);
toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24);
toolbar.setTitle("About Developer");
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
return root;
}
}
Instead of replace use add for your transaction
I think that because you have null in method addToBackStack
transaction.addToBackStack(null)
Therefore you don't get the main activity when you click on the back button.
If you want to read more about how addToBackStack works, I recommend you to read this What is the meaning of addToBackStack with null parameter?
After doing some diggings, I finally found a way around it. All I had to do was to add a tweak to my onBackPressed method from the main activity (HomeActivity.class in my case).
#Override
public void onBackPressed() {
//Return to home activity from any active fragment
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
}
//To close nav drawer
else if(slidingRootNav.isMenuOpened()){
slidingRootNav.closeMenu();
}
else {
moveTaskToBack(true);
}
}
NB addToBackStack must be used during fragment transactions to keep count of when a fragment is active.
say transaction.addToBackStack(null)
And as for the top navigation in my Fragment class, all I did was to add an Intent that calls the home activity when the toolbar nav icon is clicked.
public class AboutDeveloper extends Fragment {
Intent intent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_about_developer,container, false);
intent = new Intent(getActivity(), HomeActivity.class);
Toolbar toolbar = root.findViewById(R.id.return_home);
toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_ios_24);
toolbar.setTitle("About Developer");
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(intent);
getActivity().finish();
}
});
return root;
}
}
Thanks to those who gave their suggestions.
Related
I am working on an android application where I have three fragments I want to show the back button on the toolbar of the fragments to go back to the previous fragments now how can I achieve that?? I am new to android please guide me.
public class SecondFragment extends Fragment {
Button button2;
private PageViewModel viewModel;
EditText editTextName, editTextEmail, editTextDesc;
public SecondFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
button2 = view.findViewById(R.id.next2);
editTextName = view.findViewById(R.id.edittextName);
editTextEmail = view.findViewById(R.id.edditextEmail);
editTextDesc = view.findViewById(R.id.edittexDesc);
viewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (editTextName.getText().toString().isEmpty() || editTextEmail.getText().toString().isEmpty() || editTextDesc.getText().toString().isEmpty())
{
editTextName.setError("Enter name");
editTextEmail.setError("Enter Email");
editTextDesc.setError("Enter Description");
}else {
// viewModel.setName(editTextName.getText().toString());
enterName(editTextName.getText().toString());
enterEmail(editTextEmail.getText().toString());
enterDesc(editTextDesc.getText().toString());
// viewModel.setEmail(editTextEmail.getText().toString());
// viewModel.setDescription(editTextDesc.getText().toString());
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
Fragment NAME = new LastFragment();
fragmentTransaction.replace(R.id.container, NAME);
fragmentTransaction.commit();
}
}
});
return view;
}
this is the code of my fragment borther i have three fragments like this i need to add the back button on the toolbar of there three fragemtns
You can add a toolbar to your activity, which is the container for these fragments.
Then in your fragments you can do something like this:
private void setupToolbar() {
YourActivity yourActivity = (YourActivity) getActivity()
if(yourActivity != null) {
yourActivity.toolbar.setSkipVisibility(View.GONE) // Or View.VISIBLE
yourActivity.toolbar.setText() // Set some text
yourActivity.toolbar.setOnBackButtonClickListener{ yourActivity.onBackPressed() }
}
}
Follow the steps down below.
fragmentTransaction.replace(R.id.container, NAME);
fragmentTransaction.addToBackStack(null); //Add this line
fragmentTransaction.commit();
This will solve your issue. Thank you.
The signup page of my app is divided into three fragments. FragmentA, FragmentB and FragmentC which is attached to same activity. On clicking the next button which is present in FragmentA it will call FragmentB and same is for FragmentB and FragmentC. As I move forward the buttons of the previous fragment overlaps the current one. Below is my code. How can I avoid this situation?
MainActivity.class
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.signup_page);
init();
}
private void init() {
ViewPager2 viewPager = findViewById(R.id.signup_pager);
List<Fragment> fragmentList = new ArrayList<Fragment>();
FragmentA aFragment = new FragmentA();
FragmentB bFragment = new FragmentB();
fragmentList.add(aFragment);
fragmentList.add(bFragment);
SignupFragmentPagerAdapter signupFragmentPagerAdapter = new SignupFragmentPagerAdapter(this,fragmentList);
viewPager.setUserInputEnabled(false);
viewPager.setAdapter(signupFragmentPagerAdapter);
}
}
FragmentA.class
public class FragmentA extends Fragment {
EditText et_name;
Spinner sp_user_type;
Button bt_next;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fraga,container,false);
et_name = view.findViewById(R.id.editTextTextPersonName);
sp_user_type = view.findViewById(R.id.user_spinner);
bt_next = view.findViewById(R.id.button8);
bt_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentB bFragment = new FragmentB();
FragmentManager manager = getParentFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frag_a, bFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
FragmentB.class
public class FragmentB extends Fragment {
Button bt_next;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragb,container,false);
bt_next = view.findViewById(R.id.button9);
bt_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentC cFragment = new FragmentC();
FragmentManager manager = getParentFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frag_b, Fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
Cause of your problem:
You are making fragment transaction (from A to B) within Fragment A itself; and not through the placeholder of these fragments (which is in your case the ViewPager itself; So the MainActivity still sees that the ViewPager is at the first page and therefore shows Fragment A in the background.
You have two options to solve this:
First: Since you're disable page scrolling; I don't see any use to
the ViewPager .. so you can just have a fragment placeholder in the
main activity, and make fragment transaction on this placeholder.
Second: if you have a need to the ViewPager, instead of making
fragment transaction, you can use
viewPager.setCurrentItem(position) and set the position to the
target fragment according to the order you add them in the adapter.
You can do that from your fragment when you hit the button using:
((MainActivity)requireActivity()).myViewPager.setCurrentItem(position)
As the title says when on the "Home Fragment" when i click on an image tile I want the new activity to load but I would like to keep the navbar visible. Currently with the code below the activity starts but the navbar disappears. I would like help to write code so the activity starts but the navbar stays.
public class HomeFragment extends Fragment {
private ImageView imageCbt;
private ImageView imageDistorted;
#Nullable
#Override
public android.view.View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
// get the button view
imageCbt = getView().findViewById(R.id.whatIsCbt);
imageDistorted = getView().findViewById(R.id.distortedThinking);
// set a onclick listener for when the button gets clicked
imageCbt.setOnClickListener(new View.OnClickListener() {
// Start new list activity
public void onClick(View v) {
Intent mainIntent = new Intent(getActivity(),
IntroActivity2.class);
startActivity(mainIntent);
}
});
imageDistorted.setOnClickListener(new View.OnClickListener() {
// Start new list activity
public void onClick(View v) {
Intent mainIntent = new Intent(getActivity(),
TwelveTypesDistortedThinkingActivity.class);
startActivity(mainIntent);
}
});
}
To change the current fragment, you can replace the code inside your click listeners to this one (Replacing a fragment with another fragment inside activity group):
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Then you need to convert your activities to Fragment (maybe some refactoring will be necessary) and to change the current fragment in the onClickListener methods.
PS: When you use a navbar, fragments are a best practice in application architecture.
I'm currently trying to make a fragment come into view over everything else in the activity. Then, on a button press, the fragment should disappear and reveal everything that was there previously.
Here is my current attempt:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.replace(currentFragment.getId(), fragment);
transaction.addToBackStack(null);
transaction.commit();
and on the button press, I do:
getFragmentManager().popBackStack();
But the issue I'm having it the fragment doesn't totally inflate overtop all the other views, and the button press is not having the desired affect. Any suggestions?
EDIT: It's a bottomNavigationView that's still showing, I'd like to inflate overtop of that.
You can use Dialog fragment like:
public class PopUpDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Your title")
.setMessage("Your message")
.setPositiveButton("Button name", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Do your stuff here
dismiss();
}
});
return builder.create();
}
}
Then you call it from your activity like:
PopUpDialogFragment fragment = new PopUpDialogFragment();
fragment.show(getFragmentManager(), "popUp");
If you want a Fragment with your own custom view then you create one with onCreateView method.
public class PopUpDialogFragment extends DialogFragment {
private Button button;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup
container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.your_layout,
container, false);
button = view.findViewById(R.id.your_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do your stuff here
getDialog().dismiss();
}
});
return view;
}
}
I tried to phrase the title as I can, but Basically inside the HomeActivity I have a custom menu with a bunch for fragments.! One of the them is HomeFragment which contains a Tablelayout of 2 tabs with a viewpager..!
Everything is working correctly.! but inside the menu fragment, when the user clicks the back button on the toolbar is to return to the HomeFragment.
A fragment replacement method will do the trick which I already used it to replace between the fragments when choosing from the menu !?
But in this case, the HomeFragment opens yet the Tablayout isn't responsive! it feels like the the fragment isn't created correctly!?
I tried using a new intent of the same activity which opens HomeFragment by default, and it opens it but with the same problem..!
The Problem
The Code
HomeFragment
// code..
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
InitViews(rootView);
TabLayoutAdapter adapter = new TabLayoutAdapter(getFragmentManager());
pager.setAdapter(adapter);
tabLayout.setupWithViewPager(pager);
return rootView;
}
// code..
Menu Fragment
// code..
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.to_home:
replaceFragment(new HomeFragment());
// tried this and it's the same problem
// startActivity(new Intent(getActivity(), HomeActivity.class).setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void replaceFragment(Fragment fragment) {
android.support.v4.app.FragmentTransaction t = getFragmentManager().beginTransaction();
t.replace(R.id.Container, fragment);
t.commit();
}
// code..
Looking at the code I think you have to use getChildFragmentManager() instead of getFragmentManager() and use it for fragment Transaction.
The definition of getChildFragmentManager() is:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
And the definition of getFragmentManager() is:
Return the FragmentManager for interacting with fragments associated with this fragment's activity.
Replace this line of code having getFragmentManager() by getChildFragmentManager()
TabLayoutAdapter adapter = new TabLayoutAdapter(getChildFragmentManager());
Also in the menu Fragment
android.support.v4.app.FragmentTransaction t = getChildFragmentManager().beginTransaction();