setOnClickListener in Fragment with Kotlin - android

I am working on a sample code and I want a Button showing a message but it didn't work. App will open but buttonn didn't work
This app should show a Toast but it does not. I tried lateinit var firstComend : Button but didn't work too
I should sat will converting Activity to Fragment
Please help me
package com.mysfk.android.frogments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.mysfk.android.R
import android.graphics.Color
import android.telephony.SmsManager
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class OrderFragment : Fragment() {
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val let = arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
var firstComend = view?.findViewById<Button>(R.id.firstButton)
firstComend?.setOnClickListener {
Toast.makeText(context, "ارسال شد", Toast.LENGTH_SHORT).show()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_order, container, false)
}
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
MessageFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}

Try to set your click listener inside the onCreateView, like this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_order, container, false)
var firstComend = view?.findViewById<Button>(R.id.firstButton)
firstComend?.setOnClickListener {
Toast.makeText(context, "Test", Toast.LENGTH_SHORT).show()
}
}

All view related decision must be done in onCreateView or onViewCreated
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_order, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?){
var firstComend = view?.findViewById<Button>(R.id.firstButton)
firstComend?.setOnClickListener {
Toast.makeText(context, "Test", Toast.LENGTH_SHORT).show()
}
}

Related

BottomSheetDialogFragment.viewBinding

I struggle to do a property delegate for ViewBinding on BottomSheets.
The general Idea is similar to this
For Fragments i use something like this
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)
On BottomSheetsDialogFragments which are Fragments it does not accept the delegate.
fun <T : ViewBinding> BottomSheetDialogFragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)
The Lifecycle of BottomSheets would be the same as on regular Fragments, so i would not expect any problems.
Anyone came up with a solution on this ?
You can still use the FragmentViewBindingDelegate and extension from Gabor.
You just also need to inflate the view inside onCreateView().
For example:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
class ExampleBottomSheet : BottomSheetDialogFragment() {
//Using ::bind here since the view is already inflated in onCreateView()
private val binding by viewBinding(YourCustomViewBinding::bind)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.your_custom_view, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Use binding here or wherever you need it
}
}
Implement ViewBinding in BottomSheetFragment like this (Works for me):
class CustomBottomSheet : BottomSheetDialogFragment() {
private lateinit var binding: CustomBottomSheetBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = CustomBottomSheetBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//onClick listener
binding.button.setOnClickListener {
Toast.makeText(context, "Clicked", Toast.LENGTH_LONG).show()
}
}
}
This works:
class CampaignBottomSheet : BottomSheetDialogFragment() {
private var _binding: MenuCampaignsBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = MenuCampaignsBinding.inflate(layoutInflater)
binding.startCampaign.setOnClickListener { println("__print::CampaignBottomSheet") }
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Unlike Fragment class, BottomSheetDialogFragment doesn't have a constructor that accepts layout resource.
You can create a custom dialog for it. Basically, copy everything from AppCompatDialogFragment and BottomSheetDialogFragment.

How to pass a Mutable list from fragment to another fragment?

I'm new to Kotlin and Fragments, actually in my App i have two fragments, Fragment1 and Fragment2
In the first fragment i have a method which get data from some editTexts and add them to a MutableList then in my Fragment2 i have a ListView in which i would be able to show that MutableList...
But how can i pass the MutableList from Fragment1 to Fragment2?
Here is my Fragment1 code:
private var listArticoli: MutableList<Articolo>? = null
private fun addBarcode(barcode: String, qta: String) {
if (barcode.isEmpty()) {
txtBarcode.requestFocus()
return;
}
listArticoli?.add(Articolo(barcode, qta.toInt()))
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
txtBarcode = view.findViewById(R.id.txtBarcode)
listArticoli = mutableListOf()
btnArticoli.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) // button on click of which i navigate to Fragment2
}
}
Fragment2 code:
class SecondFragment : Fragment() {
lateinit var listView: ListView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
listView = view.findViewById(R.id.listView)
view.findViewById<Button>(R.id.btnIndietro).setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
}
}
1.Share the viewmodel with their common parent activity
2.FragmentResultListener from fragment(after 1.3.0-alpha04)
To access Mutable list in both the fragments,you can create ViewModel which consists of MutableLiveDate of you required data type.Then expose MutableLiveData from viewmodel.So use the same ViewModel in both the fragments by setting data from one fragment1 and by observing data from fragment2.
SampleViewModel.kt
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SampleViewModel: ViewModel() {
var mutableLiveData:MutableLiveData<MutableList<Articolo> = MutableLiveData()
}
Fragment1.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
class Fragment1 : Fragment() {
private lateinit var viewModel: SampleViewModel
var arrayList: ArrayList<Articolo> = ArrayList()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(requireActivity()).get(SampleViewModel::class.java)
//TODO: Add data to arraylist
viewModel.mutableLiveData.value = arrayList
}
}
Fragment2.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
class Fragment2 : Fragment() {
private lateinit var viewModel: SampleViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(requireActivity()).get(SampleViewModel::class.java)
viewModel.mutableLiveData.observe(viewLifecycleOwner, Observer {
//TODO:Can do you requirements here
})
}
}

Getting error findViewById when initiate recyclerview in a fragment

I have tested this code in another project where I didn't use fragment and wrote it in MainActivity.kt, it works. But a problem comes when I make another project using fragment so I write it in a new class (HerbalFragment.kt). It's getting error in "findViewById" for initiate Recyclerview and also getting error in "this". Here is my code (HerbalFragment.kt)
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
/**
* A simple [Fragment] subclass.
*/
class HerbalFragment : Fragment() {
private lateinit var rvHerbal: RecyclerView
private var list: ArrayList<Herbal> = arrayListOf()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
super.onViewCreated(view, savedInstanceState)
return inflater.inflate(R.layout.fragment_herbal, container, false)
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(this)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
}
}[![enter image description here][1]][1]
Help me please, thanks before
As far as i have noticed your code is unreachable,
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
super.onViewCreated(view, savedInstanceState)
return inflater.inflate(R.layout.fragment_herbal, container, false)
// unreachable code you are already return the view so below code will never execute
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
To fix this issue you need to change your code as i have suggested.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_herbal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// do what ever you want here like find view ids and etc...
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(activity!!)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
}
You do not have to find view if you use the kotlin data binding by this easy method
add import to this (fragment_herbal is your xml layout view file name)
import kotlinx.android.synthetic.main.fragment_herbal.*
then
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_herbal, container, false)
}
then use your view item without findviewbyid
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}

How can I change different URL or view in tabbed activity?

I'm new in Android kotlin development. I would like to create a tabbed activity in my app to show different static HTML page.
I able to set 1 URL in my app now. But when I change or tap to another tab, it will show similar view or URL.
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.support.v4.app.Fragment
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.webkit.WebView
import xxx.abcabc.xxx.R
import android.util.Log
class PlaceholderFragment : Fragment() {
private lateinit var pageViewModel: PageViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pageViewModel = ViewModelProviders.of(this).get(PageViewModel::class.java).apply {
setIndex(arguments?.getInt(ARG_SECTION_NUMBER) ?: 1)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_left_menu_policies, container, false)
var webTnc: WebView = root.findViewById(R.id.myWebView)
webTnc.loadUrl("https://www.abcxyz.com/abcxyz/abcxyz_webpage/tnc.html")
return root
}
companion object {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private const val ARG_SECTION_NUMBER = "section_number"
/**
* Returns a new instance of this fragment for the given section
* number.
*/
#JvmStatic
fun newInstance(sectionNumber: Int): PlaceholderFragment {
return PlaceholderFragment().apply {
arguments = Bundle().apply {
putInt(ARG_SECTION_NUMBER, sectionNumber)
}
}
}
}
}
How can I detect sectionNumber something like
if(sectionNumber == 0)
{
var webTnc: WebView = root.findViewById(R.id.myWebView)
webTnc.loadUrl("https://www.abcxyz.com/abcxyz/abcxyz_webpage/tnc.html")
}
else
{
var webTnc: WebView = root.findViewById(R.id.myWebView)
webTnc.loadUrl("https://www.URL2.com/URL2.html")
}
Please help. Thank you.
Edited
I see that you're putting sectionNumber in bundle arguments in fragment. So you can use that arguments to get the data back.
Try this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_left_menu_policies, container, false)
val sectionNumber = arguments?.getInt(ARG_SECTION_NUMBER) ?: 1
if (sectionNumber == 1) {
var webTnc: WebView = root.findViewById(R.id.myWebView)
webTnc.loadUrl("https://www.abcxyz.com/abcxyz/abcxyz_webpage/tnc.html")
} else {
var webTnc: WebView = root.findViewById(R.id.myWebView)
webTnc.loadUrl("https://www.URL2.com/URL2.html")
}
return root
}

Using safeargs I get "required Bundle found Bundle?"

I am passing arguments using safeargs. In the reciving fragment I am getting a compile error: 'Required Bundle Found Bundle?'. Cannot see where the error has crept in.
Googled around, checked text and udacity tutorial
Where error appears (at 'arguments')
package com.example.android.naveditoryoutube
import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_two_fragment.*
class FragmentTwo : Fragment() {
companion object {
fun newInstance() = FragmentTwo()
}
private lateinit var viewModel: FragmentTwoViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_two_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(FragmentTwoViewModel::class.java)
}
override fun onStart() {
super.onStart()
var args = FragmentTwoArgs.fromBundle(arguments)
argText.text = args.calculated_Number
}
}
Sending code:
package com.example.android.naveditoryoutube
import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_one_fragment.*
class FragmentOne : Fragment() {
companion object {
fun newInstance() = FragmentOne()
}
private lateinit var viewModel: FragmentOneViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_one_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(FragmentOneViewModel::class.java)
var calculated_Number : String = viewModel.sendNewNumber().toString()
button_calculate.setOnClickListener{view: View ->
if (number_box.text.isNotEmpty()){
var number_entered: String = number_box.text.toString()
viewModel.findNewNumber((number_entered))
calculated_Number = viewModel.sendNewNumber()
Navigation.findNavController(view).navigate(FragmentOneDirections.actionFragmentOneToFragmentTwo(calculated_Number))
}
}
}
}
Error appears here
var args = FragmentTwoArgs.fromBundle(arguments)
arguments is expected to be Bundle but is Bundle?
I had to change it to use !!
var args = FragmentTwoArgs.fromBundle(arguments!!)
use requireArguments() instead of arguments!!
try using requireArguments() instead of arguments
var args = FragmentTwoArgs.fromBundle(requireArguments())
You shouldn't use FragmentTwoArgs.fromBundle(arguments)
just use:
val args: FragmentTwoArgsby navArgs()
And in your method call:
val amount = args.amount
It's work for me, see official guide:
https://developer.android.com/topic/libraries/architecture/navigation/navigation-pass-data
Instead of
var args = FragmentTwoArgs.fromBundle(arguments)
argText.text = args.calculated_Number
you can use
arguments?.let {
val args = FragmentTwoArgs.fromBundle(it)
argText.text = args.calculated_Number
}

Categories

Resources