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
}
Related
I am trying to create a registration page where there is return for a button that can be clicked to a login page and then I need to return a binding command for the registration form to the firebase but I cannot use two types of return because onCreateView only allows return to be implemented once. But the button's "return view" and the registration form's "return binding.root" are two different types of returns that cannot be combined.
How can I implement both of these returns at the same time?
Here is the code:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
val view: View = inflater!!.inflate(R.layout.fragment_register_email, container, false)
view.navigate_to_login_register_email.setOnClickListener { view ->
requireActivity().run {
startActivity(Intent(this, LogIn::class.java))
finish()
}
}
return view
binding = FragmentRegisterEmailBinding.inflate(layoutInflater, container, false)
binding.registerButtonEmail.setOnClickListener {
validateData()
}
return binding.root
You're inflating the same layout twice, in two different ways. That's creating two copies, and you're setting one click listener in one layout, and another in the other layout. And your fragment can only use one of them for its view - whichever you pass back, it'll be missing a click listener.
If you're using view binding, and you're keeping a reference to the binding object (which you are, and that's how you'd normally do it) then just do this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// generate your binding class by inflating the layout
binding = FragmentRegisterEmailBinding.inflate(layoutInflater, container, false)
// set your listeners on the views in the layout
binding.navigateToLoginRegisterEmail.setOnClickListener {
requireActivity().run {
startActivity(Intent(this, LogIn::class.java))
finish()
}
}
binding.registerButtonEmail.setOnClickListener {
validateData()
}
// return the root of the view hierarchy (i.e. the inflated layout)
return binding.root
}
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 using this instruction: https://developer.android.com/training/graphics/opengl/environment.
But I have to work with fragment instead of activity. Also I have some picture on main fragment and using OpenGl I have to draw some shapes. But, when I start app in becomes just empty dark screen.
Somewhere I found that I can write something like this for fragment, but If I remove this line of code my xml layout become on app, but I need to mix fragment and draw shapes over this fragment.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
lifecycle.addObserver(viewModel)
val rootView = inflater.inflate(R.layout.main_fragment, container, false)
val fL = rootView.findViewById<ConstraintLayout>(R.id.main)
customGLSurfaceView = CustomGLSurfaceView(requireContext())
fL.addView(customGLSurfaceView) // this line
return rootView
}
class HomeFragment : Fragment() {
var sampleImage = intArrayOf(
R.drawable.Tokyo,
R.drawable.Kenya,
R.drawable.Newyork
)
var carouselView: CarouselView? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
carouselView =findViewById(R.id.carouselview)
carouselView!!.pageCount = sampleImage.size
carouselView!!.setImageListener(imageListener)
}
var imageListener = ImageListener { position, imageView -> imageView.setImageResource(sampleImage
[ position]) }
}
You can use view.findViewById() inside fragments for finding views.
It is not releated to kotlin. So findViewById is a part of View, We can use findViewById if the class is extending AppCompactActivity because AppCompactActivity extends View. So Fragment doesn't extend them, We load our fragment XML from onCreateView which returns a View Instance, And we can use that View instance to call findViewByID
Cut Story Short use view.findViewById()
To Know more
I was trying to change ImageView in one Fragment from another Fragment. But since this cannot be done without container, I have to create another view value with the inflater method. Then I need to return these view values with the inflater methods. How do I return two views?
code is written in a fragment:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.firstfragment, container, false)
val view2 = inflater.inflate(R.layout.secondfragment, container, false)
val imgPF: ImageView = view2.findViewById(R.id.imageView)
imgPF.setImageResource(R.drawable.image_29)
view.ButtonFromFirstFragment.setOnClickListener{
//Unimportant code
}
setHasOptionsMenu(true)
return view //Approximately here i need to return two views, but how?
//And can it be done somehow differently?
}
Basically you should not have 2 fragments within a fragment. Please double check that you are not confusing fragments with views.
If you want to have those 2 fragments in an activity and you are showing both of your fragments at the same time then you should have 2 separate fragments:
Fragment A:
(...)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.firstfragment, container, false)
view.ButtonFromFirstFragment.setOnClickListener{
//Unimportant code
}
return view
}
(...)
Fragment B:
(...)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.secondfragment, container, false)
val imgPF: ImageView = view.findViewById(R.id.imageView)
imgPF.setImageResource(R.drawable.image_29)
return view
}