I have three tabs (fragments) in my app, one of which should be a settings tab. I would like to use the AndroidX preference library for this settings tab.
I can open the settings tab and change settings, however once I have opened the settings tab once, the bottom navigation bar does not work anymore. When I close and restart the app the preferences have been saved. I think this is because .replace(android.R.id.content, SettingsFragmentCompat()) replaces the entire activity including the bottom navigation bar.
How can I correctly load the preference fragment into the tab fragment?
SettingsFragment.kt (tab fragment)
package net.htlgrieskirchen.jheschl17.hypernote.ui.settings
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import net.htlgrieskirchen.jheschl17.hypernote.R
class SettingsFragment : Fragment() {
private lateinit var view1: View
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
view1 = inflater.inflate(R.layout.fragment_settings, container, false)
requireActivity().supportFragmentManager
.beginTransaction()
.replace(android.R.id.content, SettingsFragmentCompat())
.commit()
return view1
}
}
SettingsFragmentCompat.kt (android boilerplate)
package net.htlgrieskirchen.jheschl17.hypernote.ui.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import net.htlgrieskirchen.jheschl17.hypernote.R
class SettingsFragmentCompat : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
I solved the issue by changing the root element of the layout file corresponding to SettingsFragment to androidx.drawerlayout.widget.DrawerLayout with id view_settings and changing .replace(android.R.id.content, SettingsFragmentCompat()) to .replace(R.id.view_settings, SettingsFragmentCompat()).
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 using fragments in my android application, when I run the program, the percentage name is displayed incorrectly, but after I switch to another fragment and perform some actions, everything becomes as it should be.
I set the title for the fragment on this line:
(activity as AppCompatActivity).supportActionBar?.title = "Soccer Quiz"
but it only applies when moving to another fragment.
My kotlin code:
package com.example.soccerquiz
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.navigation.Navigation
import com.example.soccerquiz.databinding.FragmentWelcomeScreenBinding
/**
* A simple [Fragment] subclass.
*/
class WelcomeScreenFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val binding: FragmentWelcomeScreenBinding =
DataBindingUtil.inflate(
inflater, R.layout.fragment_welcome_screen, container, false
)
binding.letsPlayButton.setOnClickListener { view: View ->
Navigation.findNavController(view)
.navigate(R.id.action_welcomeScreenFragment_to_quizFragment)
}
(activity as AppCompatActivity).supportActionBar?.title = "Soccer Quiz"
return binding.root
}
}
https://i.stack.imgur.com/LzNLk.png
https://i.stack.imgur.com/66NXk.png
Please help me with my problem.
It was necessary to change the title of fragment in navigation graph.
No need to install manually, because when you start the program it does not always work, you have to switch between fragments.
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
}
}
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.
I am trying to go back to another fragment, but the android studio keep saying that I cant override onBackPressed():
package com.educator.dualsignal
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class DraftFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.draft_layout,null)
}
override fun onBackPressed() {
val fm = fragmentManager
fm!!.popBackStackImmediate()
}
}
onBackPressed() is a method in the Activity class. The Fragment class has no such method.
You need to implement your backstack logic in the parent Activity.
onBackPressed() is for activity, if you want to back pre fragment by clicking on back button you can add your fragments to a stack and when user tap on back button fragments pop.
https://medium.com/#bherbst/managing-the-fragment-back-stack-373e87e4ff62