I was following the tutorial here: https://gist.github.com/EmmanuelGuther/1fde5cfbd1cdcd21cd852e3bb5716e02.
I have one button which computes the total from user input. It uses the layout fragment_ab.xml. I would like to add a "Clear" button but I do not know how to add a second button.
In the main activity I would just use clear.setOnClickListener{} alongside compute.setOnClickListener{} but it doesn't work here. I'm new to fragments.
Here's the code:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.fragment.app.Fragment
class AbActivity: Fragment(), View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view: View = inflater!!.inflate(R.layout.fragment_ab, container, false)
val btn: Button = view.findViewById(R.id.compute)
btn.setOnClickListener(this)
return view
}
companion object {
fun newInstance(): AbActivity{
return AbActivity()
}
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.compute -> {
Toast.makeText(
activity,"Yay!",
Toast.LENGTH_SHORT).show()
}
else -> {
}
}
}
}
Add a button in you fragment_ab.xml with id = clear and then do as following:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.fragment.app.Fragment
class AbActivity: Fragment(), View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view: View = inflater!!.inflate(R.layout.fragment_ab, container, false)
val btn: Button = view.findViewById(R.id.compute)
btn.setOnClickListener(this)
// for clear button
val btnClear: Button = view.findViewById(R.id.clear)
btnClear.setOnClickListener(this)
return view
}
companion object {
fun newInstance(): AbActivity{
return AbActivity()
}
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.compute -> {
Toast.makeText(
activity,"Yay!",
Toast.LENGTH_SHORT).show()
}
// clear button click
R.id.clear -> {
Toast.makeText(
activity,"Clear!",
Toast.LENGTH_SHORT).show()
}
else -> {
}
}
}
Related
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()
}
}
I'm developing an app where I made a login and register with firebase. I'm trying to pass a string from an activity to a fragment and The function that sends the strings gets called when the login or the register is successful. Then the string passed to the fragment is shown in a textView, but that doesn't happen. This is the Register class when the function is created. Thanks in advance!
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_register.*
class Register : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
setup()
}
private fun setup(){
registerBtn.setOnClickListener{
if(emailEditText.text.isNotEmpty() && passwordEditText.text.isNotEmpty()){
FirebaseAuth.getInstance().createUserWithEmailAndPassword(emailEditText.text.toString(),
passwordEditText.text.toString()).addOnCompleteListener{
if(it.isSuccessful){
//If email doesn't exists send empty string(shouldn't happen,
//already controlled with createUserWithEmailAndPassword.isSuccesful
passUserData()
showMainMenu()
}else{
showAlert()
}
}
}
}
loginBtn.setOnClickListener{
if(emailEditText.text.isNotEmpty() && passwordEditText.text.isNotEmpty()){
FirebaseAuth.getInstance().signInWithEmailAndPassword(emailEditText.text.toString(),
passwordEditText.text.toString()).addOnCompleteListener{
if(it.isSuccessful){
//If email doesn't exists send empty string(shouldn't happen,
//already controlled with createUserWithEmailAndPassword.isSuccesful
passUserData()
showMainMenu()
}else{
showAlert()
}
}
}
}
}
private fun showAlert(){
val builder = AlertDialog.Builder(this)
builder.setTitle("Error")
builder.setMessage("Se ha producido un error al intentar autenticar el usuario")
builder.setPositiveButton("Acceptar", null)
val dialog: AlertDialog = builder.create()
dialog.show()
}
private fun showMainMenu(){
val goMainMenu = Intent(this, MainActivity::class.java)
startActivity(goMainMenu)
}
private fun passUserData(){
val bundle = Bundle()
bundle.putString("sayhi", "Hello")
val transact = supportFragmentManager.beginTransaction()
val myFrag = FourthFragment()
myFrag.arguments = bundle
transact.commit()
}
}
And this is the fragment (as you can see I tried to put the same code in both methods to see if it worked):
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
enum class ProviderType{
BASIC
}
class FourthFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (arguments != null){
val sayHello = requireArguments().getString("sayhi")
val showtext : TextView = requireView().findViewById(R.id.emailShow)
showtext.text = "$sayHello"
}
return inflater.inflate(R.layout.fragment_fourth, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (arguments != null){
val sayHello = requireArguments().getString("sayhi")
val showtext : TextView = requireView().findViewById(R.id.emailShow)
showtext.text = "$sayHello"
}
}
}
I would like to navigate between fragments using a textView inside a recyclerview.
Currently I am successfully navigating between fragments using the item, but I would like to go further and navigate using the individual textViews within an item.
The recyclerview is inflated from a local room database.
Below is my adapter
package com.benb.inventory
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.benb.inventory.data.Item
import com.benb.inventory.data.getFormattedPrice
import com.benb.inventory.databinding.ItemListItemBinding
class ItemListAdapter(private val onItemClicked: (Item) -> Unit) :
ListAdapter<Item, ItemListAdapter.ItemViewHolder>(DiffCallback) {
class ItemViewHolder(internal var binding: ItemListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Item) {
binding.apply {
itemName.text = item.itemName
itemPrice.text = item.getFormattedPrice()
itemShop.text = item.shop.toString()
itemShop.setOnClickListener{
val shopName = itemShop.text.toString()
Toast.makeText(root.context, "Clicked: ${item.shop}", Toast.LENGTH_SHORT ).show()
}
}
}
}
companion object {
private val DiffCallback = object : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem.itemName == newItem.itemName
}
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemListAdapter.ItemViewHolder {
return ItemViewHolder(ItemListItemBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: ItemListAdapter.ItemViewHolder, position: Int) {
val current = getItem(position)
holder.itemView.setOnClickListener {
onItemClicked(current)
}
holder.binding.itemShop.setOnClickListener {
onItemClicked(current)
val shopName = current.shop
fun showShopList(shopName: String) {
val shopName = holder.binding.itemShop.text.toString()
val action = ItemListFragmentDirections.actionItemListFragmentToShopItemFragment(shopName)
}
}
holder.bind(current)
}
}
This is the fragment that contains the list
package com.benb.inventory
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.benb.inventory.databinding.ItemListFragmentBinding
import kotlinx.coroutines.InternalCoroutinesApi
#InternalCoroutinesApi
class ItemListFragment : Fragment() {
#InternalCoroutinesApi
private val viewModel: InventoryViewModel by activityViewModels {
InventoryViewModelFactory(
(activity?.application as InventoryApplication).database.itemDao()
)
}
private var _binding: ItemListFragmentBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ItemListFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = ItemListAdapter {
val action = ItemListFragmentDirections.actionItemListFragmentToItemDetailFragment(it.id)
this.findNavController().navigate(action)
}
binding.recyclerView.adapter = adapter
viewModel.allItems.observe(this.viewLifecycleOwner) {items ->
items.let {
adapter.submitList(it)
}
}
binding.itemShop.setOnClickListener{
val shop = binding.itemShop.text.toString()
val action = ItemListFragmentDirections.actionItemListFragmentToShopItemFragment(shop)
viewModel.retrieveShopItems(shop)
this.findNavController().navigate(action)
}
binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
binding.floatingActionButton.setOnClickListener {
val action = ItemListFragmentDirections.actionItemListFragmentToAddItemFragment(
getString(R.string.add_fragment_title)
)
this.findNavController().navigate(action)
}
}
}
For clarity this is what the inflated recyclerview looks like, it can contain many items, I have only added one.
At the moment if I click anywhere on the item it takes you to a screen with more detail about the fragment.
[A screenshot of the recycler view][1]
I would like to be able to navigate to a specific fragment depending on the textView clicked.
For example one fragment that only contains other products from the same shop.
As you may notice, I have been able to add an onClickListener in the ViewHolder class, it creates a Toast.
I have not had success in using the same onClickListener to navigate.
Thank you very much.
P.S. Any other advice is welcome, particularly if anyone knows what the #internalcoroutinesAPI thing is about please tell me!
[1]: https://i.stack.imgur.com/k6Td3.png
I am considering a simple example consists of the following component:
MainActivity: has editText, button, viewPager
FragmentA: has nothing
FragmentB: has a textView
So, in the screen, you can swipe to see each fragment. I want my example to have the function: if one writes a text in the editText and click the button then it shows up in Fragment B.
A tried it by using notifyDatsetChanged() but it does not work. Could anyone help? Below is the whole code of mine:
MainActivity.kt
package com.myproject.chapterfivesectionone
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.myproject.chapterfivesectionone.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
lateinit var fragmentB: FragmentB
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val fragmentList = listOf(FragmentA(), FragmentB())
val adapter = FragmentAdapter(this)
adapter.fragmentList = fragmentList
binding.viewPager.adapter = adapter
binding.buttonSend.setOnClickListener {
var bundle = Bundle()
bundle.putString("key1", binding.editTextWriteSomething.text.toString())
fragmentB.arguments = bundle
adapter.notifyDataSetChanged()
}
}
}
FragmentAdapter.kt
package com.myproject.chapterfivesectionone
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
class FragmentAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
var fragmentList = listOf<Fragment>()
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList.get(position)
}
}
FragmentA.kt
package com.myproject.chapterfivesectionone
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class FragmentA : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false)
}
}
FragmentB.kt
package com.myproject.chapterfivesectionone
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.myproject.chapterfivesectionone.databinding.FragmentBBinding
class FragmentB : Fragment() {
lateinit var binding: FragmentBBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentBBinding.inflate(inflater, container, false)
if (arguments?.getString("key1") != null) {
binding.textViewInFragmentB.text = arguments?.getString("key1")
}
return binding.root
}
}
Currently, fragmentB is inside fragmentList so you can retrieve it like fragmentList[fragmentBPosition]. Then defind a function inside FragmentB for update the TextView
binding.buttonSend.setOnClickListener {
(fragmentList[1] as FragmentB).updateTheTextView("new")
// if you want code more clean, can replace hard code value by a constant or you can write some logic to find FragmentB from fragmentList
}
FragmentB
class FragmentB : Fragment() {
fun updateTheTextView(newText : String) {
binding.textViewInFragmentB.text = newText
}
}
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
}