Signup flow with advanced navigation example - android

I am currently using bottom navigation like in navigation advanced example, I am trying direct user to signup flow if user is not authenticated. I use following code in side defaultly selected fragment to direct user to sign up flow (login_nav_graph) if they are not authenticated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(!authenticated){
view.findNavController().navigate(R.id.action_frag1Fragment_to_login_nav_graph)
}
}
But there are few problems
Shows back button when user in signup flow
Bottom navigation is shown in signup flow
These problems make sense, Reasons:
since signup flow (login_nav_graph) is nested inside bottom navs first items(defaultly selected) navigation graph.
Bottom nav is on activity_main layout.
So how could I integrate signup flow into navigation advanced example and overcome above mentioned issues with a better approach?
Note:
code is very similar to navigation advanced example, I introduced separate nav graph for signup flow called login_nav_graph and above mentioned code in defautly selected fragment

Fixed the issue by doing following.
Add login_nav_graph to the nav graph which contains defaultly selected fragment as a nested nav graph.
Create an action/path from defaultly selected fragment (frag1Fragment) to the login_nav_graph and set the Pop To behavior of the action to the frag1Fragment's nav graph.
Create following two methods inside the MainActivity in order to toggle the visibility of the action bar and bottom nav.
fun toggleBottomNavVisibility(){
if(bottom_nav.visibility == View.VISIBLE){
bottom_nav.visibility = View.GONE
}else{
bottom_nav.visibility = View.VISIBLE
}
}
...
fun toggleActionBarVisibility(){
if(supportActionBar!!.isShowing){
supportActionBar?.hide()
}
else{
supportActionBar?.show()
}
}
Update the onViewCreated method of the frag1Fragment as follows
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(!authenticated){
// hide bottom navigation and action bar
val activity = activity as MainActivity
activity.toggleBottomNavVisibility()
activity.toggleActionBarVisibility()
findNavController().navigate(R.id.action_frag1Fragment_to_login_nav_graph)
}
}

Related

Problem with android toolbar using navigation drawer

List the item
I'm developing an app using a navigation drawer and navigation components and I'm facing two issues:
I settled specifically each toolbar title where it is supposed to be, but every time I change the fragments, in the toolbar, for an instant, I can see the previous name from the fragment, which is the fragment name itself. So, it quickly changes from MySpecificFragment to MyFragmentName and I would like it to not happen. I've settled the title even onCreateView or onViewCreated. It didn't matter, still happening.
How could I decide the direction in which the back button of the fragment goes? I would like to create a standard position where the back button arrow goes, always the same. But it just travels back to the previous fragment (which is not a real problem, but I would like to improve its behavior)
Sorry for the lack of code, I don't know what I am supposed to display since I'm going against the standard android behavior.
P.S.: Using android studio and kotlin
Regarding the first issue, one way to avoid the brief display of the previous fragment name in the toolbar is to set the toolbar title in the parent activity and then update it from the fragment's onResume() method. This ensures that the toolbar title is set correctly when the fragment is resumed after being pushed onto the back stack. Here's an example code snippet:
In your activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
}
fun setToolbarTitle(title: String) {
supportActionBar?.title = title
}
}
In your fragment:
class MySpecificFragment : Fragment() {
override fun onResume() {
super.onResume()
(activity as? MainActivity)?.setToolbarTitle("MySpecificFragment")
}
}
Regarding the second issue, you can customize the back button behavior by using a custom NavController.OnDestinationChangedListener. In the listener, you can set the back button icon and its behavior based on the current and previous destinations. Here's an example code snippet:
class MyNavigationController(activity: AppCompatActivity, navController: NavController) {
init {
navController.addOnDestinationChangedListener(
activity, object : NavController.OnDestinationChangedListener {
override fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
arguments: Bundle?
) {
if (destination.id == R.id.my_fragment) {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(false)
} else {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setHomeActionContentDescription(R.string.back)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setDisplayShowHomeEnabled(true)
}
}
})
}
}
Here, you can adjust the back button icon and behavior based on the current and previous destinations by setting setDisplayHomeAsUpEnabled, setHomeAsUpIndicator, and setHomeActionContentDescription.

Android Navigation - Removing Action Bar Back Button When Popping Back Stack

What I'm trying to do
I am using Android Navigation component to handle navigation in my app. In this example, I have two screens, screen A and screen B.
I want the user to be able to click a button in screen A and be able to navigate to screen B; and then be prevented from going back to the previous screen (screen A).
The problem
When the user navigates to screen B from screen A, the back button on the action bar still allows the user to go back to the previous screen, however when clicking on the back button in the bottom bar it exits the app so this part works OK.
What do I need to do in order to remove the back button in the Action Bar?
What I've read so far
I have followed the guidance within these three articles but I think they might be ignoring the ActionBar's back button:
Stackoverflow - How to clear navigation Stack after navigating to
another fragment in Android
Android Developer Guide - Conditional navigation
Android Developer Guide - Navigate to a destination
My Code
Navigation Graph - nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/nav_graph"
app:startDestination="#id/screen_a">
<fragment
android:id="#+id/screen_a"
android:name="com.example.conditionalnavigation.AFragment"
android:label="screen A">
<action
android:id="#+id/action_AFragment_to_BFragment"
app:destination="#id/screen_b"
app:launchSingleTop="true"
app:popUpTo="#id/screen_a"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/screen_b"
android:name="com.example.conditionalnavigation.BFragment"
android:label="screen B" />
</navigation>
MainActivity - This acts as my Single Activity navhost.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navController.navigateUp()
}
}
In your activity class add the following member (in Kotlin):
private lateinit var appBarConfiguration: AppBarConfiguration
Inside the onCreate method add the following lines:
....
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
...
...
appBarConfiguration = AppBarConfiguration(
setOf([**ID of the fragment layout you want without back button**],
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
....
In this way your fragment will be a root fragment and the back button is removed. Hope it helps.
Try to disable home button at the creation of screen b fragment:
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var rootView = inflater?.inflate(R.layout.fragment_screen_b, container, false)
(activity as AppCompatActivity).supportActionBar!!.setDisplayHomeAsUpEnabled(false)
return rootView
}
If it didn't work, then try it in onViewCreated() method.
If not worked, try to add below as well:
setHasOptionsMenu(false)

why my progress bar from my activity doesn't show in my fragment after I press hardware back button?

so I am using navigation controller component in Android. I have a progress bar in my MainActivity that will be used in all my fragments when the user need to wait while fetching data from server.
in my onCreate MainActivity it will be declared like this:
progressBar = findViewById(R.id.progressBar_main_activity)
and in my FragmentA, it will be declared like this :
lateinit var mActivity : FragmentActivity
lateinit var progressBar : ProgressBar
override fun onAttach(context: Context) {
super.onAttach(context)
activity?.let {
mActivity = it
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
fragmentView = inflater.inflate(R.layout.fragment_user_control, container, false)
progressBar = mActivity.progressBar_main_activity
return fragmentView
}
override fun onResume() {
super.onResume()
progressBar.visibility = View.VISIBLE
}
let say I have 2 fragments
I navigate from FragmentA to FragmentB. using the code below
val eventDetailDestination = UserControlFragmentDirections.actionGlobalDestinationEventDetail(selectedEvent)
Navigation.findNavController(fragmentView).navigate(eventDetailDestination)
in FragmentB, after the user do some actions in FragmentB, then they need to go back to FragmentA
here is the problem ....
if the user goes back from FragmentB to FragmentA using back button in the top left corner in action bar/toolbar, the progress bar in FragmentA will show up.
but if the user goes back using hardware back button in the bottom right, the progress bar in FragmentA will never show. even though I am sure progressBar.visibility = View.VISIBLE has been executed in FragmentA ?
I have tried to read the difference between back button in toolbar and hardware back button. but I have no Idea why this happened. please help :)
That happens because fragmentA is getting deleted and recreated from scratch when using the hardware back button which is the expected result. You can override the default behaviour like below:
In MainActivity
override fun onSupportNavigateUp(): Boolean {
//Use component backstack pop
return Navigation.findNavController(fragmentView).navigateUp()
}
Sheding some more light
Up vs. Back
The Up button is used to navigate within an app based on the
hierarchical relationships between screens. For instance, if screen A
displays a list of items, and selecting an item leads to screen B
(which presents that item in more detail), then screen B should offer
an Up button that returns to screen A.
If a screen is the topmost one in an app (that is, the app's home), it
should not present an Up button.
..
The system Back button is used to navigate, in reverse chronological
order, through the history of screens the user has recently worked
with. It is generally based on the temporal relationships between
screens, rather than the app's hierarchy.
When the previously viewed screen is also the hierarchical parent of
the current screen, pressing the Back button has the same result as
pressing an Up button—this is a common occurrence. However, unlike the
Up button, which ensures the user remains within your app, the Back
button can return the user to the Home screen, or even to a different
app.
Reference:
Android Navigation with Back and Up

Login - Navigation Architecture Component

I implemented conditional navigation to my LoginFragment, with android navigation architecture component. The problem I facing now, is that I would like to hide the up button on the toolbar, and the disable any in-app navigation while the user is not logged in.
I would like to be able to implement this with a one-activity approach, where the Activity sets up the in app navigation UI and the navController like in the android sunflower demo, and the navigation destinations are Fragments.
I implemented the conditional navigation as discribed here:
Navigation Architecture Component - Login screen
How can I properly implement hiding the navigation and the up button on the login screen, with Navigation Architecture Component?
I don't know exactly what you mean by hiding navigation, but I will assume you mean hiding a drawer layout. To hide the up button and lock the drawer add the following to your MainActivity's onCreate. I'm using Kotlin.
myNavController.addOnDestinationChangedListener { _, destination ->
if (destination.id == R.id.loginFragment) {
myDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
myToolbar.setVisibility(View.GONE)
} else {
myDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
myToolbar.setVisibility(View.VISIBLE)
}
To make just the up button go away use myToolbar.setNavigationIcon(null) and to make it come back use myToolbar.setNavigationIcon(R.id.my_icon)
My method is adding the login page to the root set
val navController = findNavController(R.id.main_nav_host)
val appBarConfiguration = AppBarConfiguration(setOf(R.id.home_dest,
R.id.user_dest,R.id.login_dest))
toolbar.setupWithNavController(navController, appBarConfiguration)
So when you are on the login page, there is no back button.
System back button can override onBackPressed()
override fun onBackPressed() {
if (findNavController(R.id.main_nav_host).currentDestination?.id != R.id.next_dest)
super.onBackPressed()
}
}
Sorry for my English

Hide status bar in only one fragment and display it on the others

I have 3 fragments in my activity and I want to make one fragment full screen by hiding the status bar. When I exit that fragment, the status bar should reappear. How can I do that?
Its always better to define a function in your parent activity which will have the code to hide the status bar and calling that in your target fragment will hide the status bar for that fragment and when you are exiting the fragment in its stop method you can show the status bar again.
Let this be your method in activity,
public void hideStatusBar()
{
// your code depending upon what you have implemented
}
public void showStatusBar()
{
// your code depending upon what you have implemented
}
and then on fragment resume you can call this method like this,
((ParentActivity)getActivity()).hideStatusBar();
and to show it again for other fragment you can override the onStop of fragment,
((ParentActivity)getActivity()).showStatusBar();
Visit https://developer.android.com/training/system-ui/status.html
and
https://developer.android.com/training/system-ui/visibility.html
clearly explained how to hide and show statusbar in different android versions.
If you want to programmatically clear flags set with setSystemUiVisibility(), you can do so as follows:
activity?.window?.decorView?.systemUiVisibility = 0
https://developer.android.com/training/system-ui/dim
Kotlin version of show/hide-ing status bar from fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).supportActionBar?.hide()
}

Categories

Resources