How is one supposed to use findViewById in fragments in kotlin? - android

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

Related

How do i use findViewById in a fragment instead of an activity?

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
}

Create a button programmatically in a fragment using Kotlin

I wish to generate a column of buttons inside a fragment in Kotlin from a database. For now I tried with just one button, but I cannot seem to do it without hardcoding it in the XML file. Here is my code so far:
class NotesFragment() : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_notes, container, false)
//val root : ViewGroup = inflater.inflate(R.layout.fragment_notes, null) as ViewGroup
val button_Id: Int = 1111
val button = Button((activity as MainActivity?)!!)
button.setText("Button 4 added dynamically")
button.setLayoutParams(ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT))
button.setId(button_Id)
button.x = 250f
button.y = 500f
button.setOnClickListener(this)
view.add(button)
return view
}
}
I know I should probably look for the layout somewhere in this and do an addView with it... What is the next step?
I did it like this
view.rootView.findViewById<RelativeLayout>(R.id.button_container).addView(button)

Jetpack Compose In Fragment doesn't recompose on popbackstack

I'm using the jetpack navigation component here, not the Compose Navigation Component since there are some areas in my app I cannot convert yet.
The issue I'm running into is:
Fragment A starts and contains a ComposeView in it's xml. Fragment A opens Fragment B. But, when you return to Fragment A, the ComposeView is empty and doesn't show anything.
Is this a bug? Is this known? Am I just doing something wrong? I looked into setting the view composition strategy and tried each option and none of them worked.
I found the answer. I had a BaseFragment:
abstract class BaseFragment : Fragment() {
private var hasInitializedRootView = false
private var rootView: View? = null
protected abstract val layoutId: Int
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return getPersistentView(inflater, container, savedInstanceState, layoutId)
}
private fun getPersistentView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?, layout: Int): View? {
if (rootView == null) {
// Inflate the layout for this fragment
rootView = inflater?.inflate(layout, container, false)
} else {
// Do not inflate the layout again.
// The returned View of onCreateView will be added into the fragment.
// However it is not allowed to be added twice even if the parent is same.
// So we must remove rootView from the existing parent view group
// (it will be added back).
(rootView?.parent as? ViewGroup)?.removeView(rootView)
}
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (!hasInitializedRootView) {
hasInitializedRootView = true
viewCreated(view, savedInstanceState)
}
}
abstract fun viewCreated(view: View, savedInstanceState: Bundle?)
}
What would happen is that onCreateView wouldn't be called as wanted and the composition wouldn't restart. Changing to using a normal Fragment fixed this perfectly.

Different ways to use Fragments

I am developing an app with Firebase. But whenever I use the onViewCreated method, the button does not respond to any clicks. But when I use the onCreateView, it works.
Here is my LoginFragment (Button does not respond to clicks):
class LoginFragment : Fragment(R.layout.fragment_login) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val binding = FragmentLoginBinding.inflate(layoutInflater)
binding.buttonGoogleSignin.setOnClickListener {
toast("THIS IS NOT WORKING")
Authentication.getInstance().signIn(context!!, getString(R.string.default_web_client_id)) {
startActivityForResult(mGoogleClient.signInIntent, RC_GOOGLE_SIGN_IN)
}
}
}
}
In this code, my button responds to clicks:
class LoginFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInFlater,
container: ViewGroup?,
savedInstanceState: Bundle?
) {
val view = inflater.inflate(R.layout.fragment_login, container, false)
val binding = FragmentLoginBinding.bind(view)
binding.buttonGoogleSignin.setOnClickListener {
toast("THIS IS WORKING")
Authentication.getInstance().signIn(context!!, getString(R.string.default_web_client_id)) {
startActivityForResult(mGoogleClient.signInIntent, RC_GOOGLE_SIGN_IN)
}
}
return view
}
}
Can someone explain to me why the first approach did not work?
The problem is in the fact that in onViewCreated you are creating a binding object with FragmentLoginBinding.inflate(layoutInflater) but you are not connecting that binding to the view, so whatever you do with that object will not have effect on the view.
FragmentLoginBinding.inflate(layoutInflater) creates a new binding object and also inflate a new view to which it is connected. But you are not using that view in your fragment, so using that method is not the correct choice.
So you can do something like:
val binding = FragmentLoginBinding.bind(getView())
inside onViewCreated if you really want, and that will create a binding with the view you have in your fragment.
Said that, creating the binding already in onCreateView is actually recommended by the Android documentation.

Caused by: kotlin.TypeCastException: null cannot be cast to non-null type android.widget.TextView in fragments

class DashBoardFragment : Fragment() {
private var recyclerView : RecyclerView?=null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view = inflater!!.inflate(R.layout.fragment_dash_board, container, false)
initComponents(view )
return view
}
private fun initComponents(View view) {
var textView : TextView = view?.findViewById(R.id.recyclerView) as TextView
textView.setText("hello world")
}
when changing into recycler its showing same problem appreciate if you help to me
Well, how about adding more details. Like, what are you trying to accomplish, how are you doing it, what difficulties you have found with the approach, another approaches you have tried, etc. In summary, without code isn't a good question neither is with just code. Search for the balance!
Try moving the code in the initComponents function to the onCreateView function. The error might occur because recyclerView id is not ready until the View is created.
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view = inflater!!.inflate(R.layout.fragment_dash_board, container, false)
var textView : TextView = view?.findViewById(R.id.recyclerView) as TextView
textView.setText("hello world")
return view
}

Categories

Resources