I have a Parent Fragment in an activity and have a Child Fragment in Parent Fragment. The NavGraphs of the two Fragments are different. I want to access the function in the Parent Fragment from the Child Fragment, but the application crashes. How can I do it?
Child Fragment:
class ProfilinMenu : Fragment(){
private var _binding : FragmentProfilinMenuBinding? = null
private val profilinmenubinding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {
_binding = FragmentProfilinMenuBinding.inflate(inflater,container,false)
(parentFragment as Parent).changeName() // this is for access parent
return profilinmenubinding.root
}}
Parent Fragment:
public class Parent : Fragment() {
private var _binding : FragmentParentBinding? = null
private val parentBinding get() = _binding!!
private var instance: Parent? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentParentBinding.inflate(inflater, container, false)
val view = parentBinding.root
return view
}
public fun changeName(){
parentBinding.profilinIsmin.text = "Merhaba"
}
Try this..
NavHostFragment navHostFragment = (NavHostFragment) getParentFragment();
ParentFragment parent = (ParentFragment) navHostFragment.getParentFragment();
parent.changeName()
Related
I am working on a basic bluetooth app in android studio and I am having trouble with view binding. So far I have this in my MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
...
Later in the onCreate I have this line
val btnONOFF = findViewById<View>(R.id.btnONOFF) as Button
and I would like to replace the findViewById using viewbinding but I'm not sure what to replace that line with.
The android developers website says to use something like this
binding.name.text = viewModel.name
but I'm also not sure what a viewModel is.
Here is my ViewFragment.kt incase that is helpful
class ViewFragment : Fragment() {
private var _binding: ActivityMainBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): RelativeLayout {
_binding = ActivityMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}}
Any help is appreciated, thanks!
You can find the tutorial of viewmodel from here.
ViewFragment.kt
class ViewFragment : Fragment() {
private var _binding: ActivityMainBinding? = null
private val binding get() = _binding!!
private val viewModel by viewModel<ActivityViewModel>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): RelativeLayout {
_binding = ActivityMainBinding.inflate(inflater, container, false)
setupView()
return binding.root
}
private fun setupView(){
binding.text = viewModel.name
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
You can customise your ActivityViewModel.kt
class ActivityViewModel : ViewModel() {
val name = "Hello"
}
Note: by viewModel is koin injection.
I want to create a variable that holds my View LinearLayoutManager, but I'm using bottom nav bar and I got fragments instead of views and I don't know how to get the context.
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
val cardsRecyclerView : RecyclerView = binding.rvCards
val homeLayout : ConstraintLayout = binding.homeLayout
homeViewModel.text.observe(viewLifecycleOwner) {
val linearLayout = LinearLayoutManager(/*here i can't get the context*/)
val adapter = RecyclerAdapter(mutableListOf("blue", "orange", "pink", "gray"), mutableListOf(6092049204821920, 3958271029482085, 8375027502862095, 2957285928029573)
, mutableListOf(16,7,13,24), mutableListOf(7,4,1,10), mutableListOf("Eduard Radu", "John Doe", "Ayman Achalhe", "Mike Rivera"))
cardsRecyclerView.layoutManager = linearLayout
cardsRecyclerView.adapter = adapter
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
You can use activity or requireActivity
Here is the code :
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
binding.btnOpen.setOnClickListener {
Navigation.findNavController(view).navigate(R.id.secondFragment)
}
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
At line: Navigation.findNavController(view).navigate(R.id.secondFragment) I'm getting error as Type mismatch required view found view?
My question is why we can't combine navcontroller with view binding?
And is there any resources to learn restrictions of using view binding
Instead of view use binding.root
Like this:
Navigation.findNavController(binding.root).navigate(R.id.secondFragment)
binding.root is reference to root view.
So, I am trying to migrate from kotlin synthetic to Jetpack view binding.
Here is the kotlin synthetic code (works fine) that simply set visibility to invisible of TextView in the parent activity from fragment.
import kotlinx.android.synthetic.main.activity_main.*
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_first, container, false)
requireActivity().textView.visibility = View.INVISIBLE
return view
}
}
And here is what I'm doing to migrate:
import com.mypc.myapp.databinding.FragmentFirstBinding
import com.mypc.myapp.databinding.ActivityMainBinding
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.visibility = View.INVISIBLE
binding.textview.setOnClickListener {
Navigation.findNavController(view).navigate(R.id.goto_secondfragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
I'm getting error as 'Unsolved reference' at 'textview':
binding.textView.visibility = View.INVISIBLE
And at:
binding.textview.setOnClickListener {
Navigation.findNavController(view).navigate(R.id.goto_secondfragment)
}
Obviously the compiler is not able to find TextView that is in Activity
I've added this line:
import com.mypc.myapp.databinding.ActivityMainBinding
Since your binding is private to MainActivity you can refer to your textView from the MainActivity only. To show/hide this view from FirstFragment you can create a public function in MainActivity and call it from your FirstFragment.
class MainActivity: AppCompatActivity {
private var _binding: ActivityMainBinding? = null
private val binding get() = _binding!!
fun showHideTextView(visible: Boolean) {
binding.textView.isVisible = visible
}
}
And in your fragment, you can call:
(requireActivity() as MainActivity).showHideTextView(false) // This will hide the textView
First of all, you should define instance of activity view binding in baseActivity which is a parent class of your MainActivity, and then define method to change your text view like 'showTextView' , after that in the base fragment class initalize base activity instance with casting context object in onAttach method.
I provide you some code:
abstract class BaseRegisterActivity : BaseActivity() {
//---
protected lateinit var binding: ActivityRegisterBinding
private val navHostFragment by lazy {
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as
NavHostFragment
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_register)
//---
}
fun showTextView() {
binding.textView.visibility = View.VISIBLE
binding.textView.setOnClickListener {
val fragment =
navHostFragment.childFragmentManager.fragments[0]
if (fragment is FirstFragment) {
//todo
}
}
}
}
abstract class BaseFragment : Fragment(), Injectable {
//--
lateinit var baseActivity: BaseRegisterActivity
override fun onAttach(context: Context) {
super.onAttach(context)
baseActivity = context as BaseRegisterActivity
}
//--
}
class ShopFragment : Fragment() {
var binding:FragmentShopBinding ?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentShopBinding.inflate(inflater,container,false)
return binding?.root
}
The following code is from the project architecture-samples, you can see it here.
I'm not sure where I should place viewDataBinding.lifecycleOwner = this.viewLifecycleOwner between onCreateView() and onActivityCreated(), could you tell me?
class TasksFragment : Fragment() {
private lateinit var viewDataBinding: TasksFragBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewDataBinding = TasksFragBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
}
setHasOptionsMenu(true)
//viewDataBinding.lifecycleOwner = this.viewLifecycleOwner Can I place here?
return viewDataBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// Set the lifecycle owner to the lifecycle of the view
viewDataBinding.lifecycleOwner = this.viewLifecycleOwner
}
..
}
onActivityCreated is deprecated. You should use onViewCreated or onCreateView.
private var binding: TasksFragBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val viewDataBinding = TasksFragBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
lifecycleOwner = viewLifecycleOwner
}
this.binding = viewDataBinding
return viewDataBinding.root
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}