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
}
}
So I'm building this calculator and I used activities but now I have to use fragments instead.
I had these buttons implemented but now that I've moved them in a fragment I cant use findViewById. How can I assign the id to my variables?
Notice that onViewCreated has a view parameter. You can call it on that so like view.findViewById(R.id.text)
I would suggest to use viewBinding, and if you are not comfortable with that then you should do it in onCreateView() method of your fragment. Like this,
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
view = inflater.inflate(R.layout.your_layout_file, container, false)
val imageView = view.findViewById<ImageView>(R.id.id_of_imageview)
return view
}
So, findViewbyId does not work in this case, binding does not seem to work as well, at least I haven't found a working solution to it, and I'm stuck. I've read countless answers here
but none of them seem to do the trick since it looks like it's different for fragments.
Please do not answer with kotlin-android-extension, that is deprecated and I'd like to not use it
since most of my code is already under binding.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
frameLayout = inflater.inflate(R.layout.fragment_augmented_face, container, false) as FrameLayout
surfaceView = frameLayout?.findViewById<View>(R.id.surface_view) as GLSurfaceView
surfaceView?.let {
it.preserveEGLContextOnPause = true
it.setEGLContextClientVersion(2)
it.setEGLConfigChooser(8, 8, 8, 8, 16, 0) // Alpha used for plane blending.
it.setRenderer(this)
it.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
it.setWillNotDraw(false)
}
return frameLayout
}
These two lines here, they are unresolved references:
frameLayout = inflater.inflate(R.layout.fragment_augmented_face, container, false) as FrameLayout
surfaceView = frameLayout?.findViewById<View>(R.id.surface_view) as GLSurfaceView
I'm not sure if it is because it's a Fragment and not AppCompatActivity that I can't make it work?
What are my options here?
Edit here to clarify what I've tried:
I use instead id 'kotlin-parcelize', and viewBinding true
Also tried the Fragment binding instructions on the documentation, so it would look like this.:
lateinit var _binding: AugmentedFaceFragment
private val binding get() = _binding!!
...
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
_binding = AugmentedFaceListener.inflate(inflater, container, false)
And now I get unresolved reference on inflate. (Even before adding the rest of the code).
Seems apart from writing the right way here, I was also setting the wrong name of the binding, instead of the xml file I was writing the class name. Here is the working code:
private var _binding: FragmentAugmentedFaceBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentAugmentedFaceBinding.inflate(inflater, container, false)
frameLayout = binding.root
surfaceView = binding.surfaceView as GLSurfaceView
surfaceView?.let {
it.preserveEGLContextOnPause = true
it.setEGLContextClientVersion(2)
it.setEGLConfigChooser(8, 8, 8, 8, 16, 0) // Alpha used for plane blending.
it.setRenderer(this)
it.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
it.setWillNotDraw(false)
}
return frameLayout
}
//Also need to remember to nullify the binding onDestroy:
override fun onDestroy() {
_binding = null
super.onDestroy()
}
Did you get rid of the kotlin-android-extension declaration? I think that would be the problem on why it cannot find these method declration.
Either way, you should really use viewBinding/dataBinding instead of this old-school way of grabbing onto your UI components. Is a lot easier to use and much more convenient.
Here are some links
View binding: https://developer.android.com/topic/libraries/view-binding
Data binding: https://developer.android.com/topic/libraries/data-binding
Choose your weapons wisely!
UPDATE:
While using viewBinding, all of your XML classes should be automatically generating a `binding class that you can then use to access your UI components.
For the example above with a fragment called AugmentedFaceFragment, you should be able to access your binding class and inflate it by calling:
_binding = AugmentedFaceFragmentBinding.inflate(inflater, container, false)
I am working on the codelab:
https://codelabs.developers.google.com/codelabs/kotlin-android-training-add-navigation/index.html?index=..%2F..android-kotlin-fundamentals#0
I have the following function in the GameFragment.kt
private fun setTitle() {
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.title_android_trivia_question, questionIndex + 1, numQuestions)
}
strings.xml contains this line:
<string name="title_android_trivia_question" formatted="false">Android Trivia (%d/%d)</string>
I call this function in the onCreateView like this:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate<FragmentGameBinding>(
inflater, R.layout.fragment_game, container, false)
// Shuffles the questions and sets the question index to the first question.
randomizeQuestions()
setTitle()
...
This displays the title properly. But before showing this the default title "GameFragment" is shown for a fraction of second. How to avoid that?