So I'm trying to create a tabbed app in Kotlin and I have chosen the default one they made for you to practice but I can't figure out how to get the buttons working `
package com.example.android_app.ui.home
import android.content.Intent
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.ViewModelProviders
import com.example.android_app.R
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Program Buttons
logout.setOnClickListener{
val intent = Intent(this, sign_in::class.java)
startActivity(intent)
}
}
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
homeViewModel.text.observe(viewLifecycleOwner, Observer {
})
return root
}
}
`
As far as I know this should work. The problem is not in the button but in Intent. My button is already defined and has no errors but there is a red line under Intent even though it's imported. The error message is below.
public constructor Intent(p0: Context!, p1: Class<*>!) defined in android.content.Intent
public constructor Intent(p0: String!, p1: Uri!) defined in android.content.Intent
You need to pass context into the constructor of Intent instead of this.
val intent = Intent(context, sign_in::class.java)
Related
I am working on an Android app using Android Studio.
I want to save the values input into some editText textFields.
These textFields are in a Fragment view? (sorry I am very new to Android coding).
I have tried to use SharedPreferences but keep getting the error.
(Unresolved reference: getSharedPreference).
Here is my code:
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
class ConnectFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_connect, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_connect).setOnClickListener {
val serverURIFromEditText =
view.findViewById<EditText>(R.id.edittext_server_uri).text.toString()
val clientIDFromEditText =
view.findViewById<EditText>(R.id.edittext_client_id).text.toString()
val usernameFromEditText =
view.findViewById<EditText>(R.id.edittext_username).text.toString()
val pwdFromEditText =
view.findViewById<EditText>(R.id.edittext_password).text.toString()
val mqttCredentialsBundle = bundleOf(
MQTT_SERVER_URI_KEY to serverURIFromEditText,
MQTT_CLIENT_ID_KEY to clientIDFromEditText,
MQTT_USERNAME_KEY to usernameFromEditText,
MQTT_PWD_KEY to pwdFromEditText
)
findNavController().navigate(
R.id.action_ConnectFragment_to_ClientFragment,
mqttCredentialsBundle
)
val sharedPreferences: SharedPreferences =
getSharedPreferences("MyFacts", MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString("UserName", usernameFromEditText)
editor.apply()
}
}
}
Not sure what is up except to think that it is not in the MainActivity view but in a Fragment. But can't figure out how to resolve it. Could someone help me.
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'm trying change some text after load a fragment. It will be location tracker in future. So I'm testing change of the text.
build.gradle module:
android {
buildFeatures{
dataBinding = true
viewBinding = true
}
}
start.xml:
<TextView
android:id="#+id/location"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:text="Current GPS Location"
android:textColor="#FF0000"
android:textSize="30sp"
android:textStyle="bold" />
Start.kt:
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil.setContentView
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.example.basic.databinding.StartBinding
import android.util.Log
class Start : Fragment() {
private lateinit var binding: StartBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = StartBinding.inflate(layoutInflater)
binding.location.setText("Hello World")
}
}
Application runs without problem but setText Not works. Do you know why?
You are initializing your binding but not adding it to the view
onCreateView(inflater... container...) {
binding = StartBinding.inflate(layoutInflater, container, false)
return binding.root
}
then following the life cycle usage previous to binding, you have to make the change after the view is created
onViewCreated(...) {
binding.location.setText("Hello World")
}
A small comment, your naming doesn't follow conventions:
StartFragment
fragment_start
You should do the binding in onCreateView instead of onCreate as in onCreate() the fragment view is not created yet.
So transfer below in onCreateView
binding = StartBinding.inflate(layoutInflater)
binding.location.setText("Hello World")
For more info check fragment lifecycle
Thanks for answers!
Solution is very simple.
Here is solution for people who will find this question:
class Start : Fragment() {
lateinit var binding : StartBinding //this must be at the begin of your class
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = StartBinding.inflate(layoutInflater,container,false) //this must be here in onCreateView
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.setText("Hello World") // and now setText works in onViewCreated
}
}
package com.app.myproject.Fragments
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.app.myproject.LoginActivity
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_login.*
import com.app.myproject.R
import com.app.myproject.RegisterActivity
import kotlinx.android.synthetic.main.fragment_settings.*
/**
* A simple [Fragment] subclass.
*/
class SettingsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_settings, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById(R.id.signout_button).setOnClickListener {
FirebaseAuth.getInstance().signOut()
val intent = Intent(this#SettingsFragment.context, LoginActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
}
}
This is my code. I'm using firebase for the user accounts. I have my settings form in a fragment like this https://prnt.sc/rvs5yn
When I click the button signout nothing happens. I was following some code I found on stackoverflow on how to get intent to work on fragments.
Any help would be greatly appreciated.
Your code is unreachable since you wrote it after the return statement, then, you have to access the inflated view from the onViewCreated method.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_settings, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<View>(R.id.signout_button).setOnClickListener {
... // Paste your code here
}
}
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.drawerlayout.widget.DrawerLayout
import com.example.tender.R
import com.example.tender.databinding.FragmentAvailableTenderBinding
import com.example.tender.databinding.FragmentLoginBinding
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.NavigationUI
/**
* A simple [Fragment] subclass.
*/
class AvailableTenderFragment : Fragment() {
private lateinit var drawerLayout: DrawerLayout
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentAvailableTenderBinding.inflate(inflater)
drawerLayout = binding.drawerLayout
**val navController = this.findNavController(R.id.nav_host_fragment)**
**NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)**
NavigationUI.setupWithNavController(binding.navView, navController)
binding.root
}
}
"To many arguments for public fun Fragment.findNavController():NAvcontroller defined in androidx.navigation.fragment" is showing when i hover on findnavcontroller.I am unable to resolve the error on the above bold lines.In this case what should I do?
As per the Navigate to a destination documentation, the androidx.navigation.fragment.findNavController you've imported takes no parameters (it finds the parent NavHostFragment of the current Fragment and doesn't need the ID of the NavHostFragment).
The lines you've written, namely findNavController(R.id.nav_host_fragment) and setupActionBarWithNavController() are methods you'd call in an Activity, not in a Fragment.