I have an activity with three different fragments that are switched to via a bottom navigation view. The middle fragment, TutorialFragment, has a viewpager that switches between two other fragments.
The problem is that if I switch from TutorialFragment to a different fragment and then back to TutorialFragment via the bottom navigation view, the fragments inside TutorialFragment's viewpager won't display.
Here's an example (notice how after I switch to "feedback" from "tutorial" and then back to "tutorial", the "Use Keyboard Fragment" and "Enable Keyboard Fragment" strings in the top right of the app no longer show):
Here is the code for TutorialFragment:
class TutorialFragment : Fragment() {
private lateinit var tutorialView : View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
tutorialView = inflater.inflate(R.layout.fragment_tutorial, container, false )
tutorialView.tutorialViewPager.adapter = TutorialFragmentPagerAdapter(fragmentManager!!)
tutorialView.circleIndicator.setViewPager(tutorialView.tutorialViewPager)
return tutorialView
}
The solution turned out to be replacing
tutorialView.tutorialViewPager.adapter = TutorialFragmentPagerAdapter(fragmentManager!!)
with
tutorialView.tutorialViewPager.adapter = TutorialFragmentPagerAdapter(childFragmentManager)
Related
I have a fragment which uses recycle view inside it. The context that holds this fragment contains a bottom navigation bar.
When using recycle view of the fragment, it inherits the bottom navigation bar which causes two duplicated bottom navigation bars as the below picture. How do I fix this, so the fragment does not have the bottom navigation bar?
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var view = inflater.inflate(R.layout.fragment_article, container, false)
view.rcvArticle.layoutManager = LinearLayoutManager(view.context)
view.rcvArticle.adapter = ArticleAdapter(Article.articles.shuffled())
return view
}
I'm trying to use Bottom Navigation in my app. Most explanations online are about using Bottom Navigation to navigate a fragment container from WITHIN the MainActivity. However, I am trying to use the Bottom Navigation from within a fragment and not an activity. Can anybody help me? This is the code I have thus far, the line in bold represents the problem saying:
"Too many arguments for public fun Fragment.findNavController(): NavController defined in androidx.navigation.fragment"
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomePageBinding.inflate(inflater, container, false)
val bottomNavigationView = binding.bottomNavigation
val navController = findNavController(**R.id.homeScreenFragment**)
bottomNavigationView.setupWithNavController(navController)
return binding.root
}
}
I have a fragment with a RecyclerView in it. When clicking on an item, I'm navigating (with navigation component) to a detail fragment.
Inside the detail fragment, I want to implement the AppBarLayout. But I have already a Toolbar on activity level.
How can I achieve something like this? You can find the video here on Google design guidelines. Not sure if they are starting a new activity. Bottom navigation is also part of my activity and should be visible when navigating to detail fragment with AppBarLayout.
Inside the detail fragment, I want to implement the AppBarLayout. But I have already a Toolbar on activity level.
So, now the activity has a toolbar, and you want to set another toolBar in the DetailFragment. And as you're using navigation components, you are likely making the toolbar managed by the navController
Well, this requires you to move the activity level toolBar to be in the main fragment; that is hosted by navHostFragment.
The reason: because setting another toolbar from the fragment level will duplicate it as the activity level toolbar always persist. Check this answer for that.
And therefore you need to setup the toolBar in the fragments instead; and normally when you move from a fragment to another though the navigation components, no duplication will occur, and now you can have different toolbar as you'd like to.
Here is a schematic demo:
Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun setupActionBar(toolbar: Toolbar) {
setSupportActionBar(toolbar)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
val appBarConfiguration = AppBarConfiguration.Builder(
R.id.fragment, R.id.fragment_b
) .build()
NavigationUI.setupActionBarWithNavController(
this,
mNavController,
navController
)
}
}
FragmentA
class FragmentA : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_a, container, false)
(requireActivity() as MainActivity).setupActionBar(view.findViewById(R.id.fragment_toolbar))
return view
}
}
FragmentB: Similar to FragmentA, but has its own toolBar
class FragmentB : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_b, container, false)
(requireActivity() as MainActivity).setupActionBar(view.findViewById(R.id.fragment_toolbar))
return view
}
}
Using the AndroidX navigation component, I've created a shared element transition between two fragments. The first fragment has a RecyclerView, and the second fragment shows details of the clicked element. The enter transition always works as expected. The return transition works if I hit the back button right away. However, if I wait more than about 5 seconds before hitting the back button, the animation doesn't work properly.
In that case, there is no animation at all. No move, no fade, everything in the fragment just shows up immediately in place.
Here's the navigation code in the main fragment:
override fun onClick(deck: SlideDeck, sourceView: View) {
viewModel.activeDeck = deck
val extras = FragmentNavigatorExtras(sourceView to "deck_details")
findNavController().navigate(
R.id.action_deckListFragment2_to_deckDetailsFragment,
null,
null,
extras
)
}
Here's the code to set the shared element transition in the second fragment:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val animation = TransitionInflater.from(requireContext()).inflateTransition(
android.R.transition.move
)
sharedElementEnterTransition = animation
sharedElementReturnTransition = animation
binding = FragmentDeckDetailsBinding.inflate(inflater, container, false)
return binding.root
}
Finally, back in the main fragment, I had to postpone the enter transition:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = FragmentDeckListBinding.inflate(inflater, container, false)
postponeEnterTransition()
binding.root.doOnPreDraw {
startPostponedEnterTransition()
}
return binding.root
}
I also had to make sure each element in the RecyclerView had a unique and consistent transitionName as follows:
<androidx.cardview.widget.CardView
android:id="#+id/deckDetailsCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
app:cardCornerRadius="4dp"
android:transitionName="#{String.format(#string/transition_name_string, deck.id)}"
android:onClick="#{() -> itemClickListener.onClick(deck, deckDetailsCard)}">
...
</androidx.cardview.widget.CardView>
Again, this all works as hoped unless I wait longer than ~5 seconds before returning to the main fragment. I've tested this on 2 emulaters (SDK 21 and 28) and a physical device (Galaxy S10E). All exhibit the same behavior.
I figured it out. The problem was here in the main fragment's onViewCreated:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val deckObserver = Observer<List<SlideDeck>> { deckList ->
val listener: DeckListOnItemClickListener = this
val deckListAdapter = DeckListAdapter(requireContext(), deckList,
listener)
deckListAdapter.dataSet = deckList
binding.deckRecyclerView.adapter = deckListAdapter
deckListAdapter.notifyDataSetChanged()
}
viewModel.deckList.observe(viewLifecycleOwner, deckObserver)
}
Do you see it?
I wasn't creating an adapter for the RecyclerView until I received a change notification from the ViewModel. I think the problem was that the RecyclerView didn't have an adpater set until after the animation ran.
So I made the adapter a member of the Fragment, set the RecyclerView's adapter member directly in onViewCreated, then just updated the adapter's list when changes were observed. That seems to have fixed it.
i have Fragment that include ImgaeView(s) in it's XML and i'm navigating from these images to another fragments but the problem is that the bottomsheet stays open, how to make it collapse when i navigate to another fragment?
here is a picture of the bottomsheet
and here i navigated to another fragment but the bottomsheet still appears on the screen
here is the code for inside the fragment
class MoreFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_more, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
home_button.setOnClickListener{
val homeFragment = HomeFragment()
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.nav_host_fragment, homeFragment, "findThisFragment")
?.addToBackStack(null)
?.commit()
}
so my question is:
how to make it collapse down after i navigate to another fragment?
in Onclick listener before navigating to another fragment call dismiss() function
Just remove .addToBackStack(null) and call method dismiss()