my app use bottomNavBar with 3 fragments [Settings / Home / Gallery].
Now I'm trying to make a TabBar with 3 new Tabs inside of "Settings". [setting01 / setting02 / setting03]
I followed carefully this tutorial : https://www.youtube.com/watch?v=qfFANw7nPMU
and I used viewPager2 when the video uses viewPager.
but I'm still stuck in MainActivity.kt because for some reasons these two line (from the tutorial) didn't work for me :
viewPager2.adapter = PageAdapter(supportFragmentManager)
tabLayout.setupWithViewPager(viewPager2)
here is my entire MainActivity.kt file :
package com.example.appname
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.appname.ui.settings.PageAdapter
import kotlinx.android.synthetic.main.fragment_settings.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_settings, R.id.navigation_swapper, R.id.navigation_gallery))
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
viewPager2.adapter = PageAdapter(supportFragmentManager)
tabLayout.setupWithViewPager(viewPager2)
}
}
I'm almost certain that this error exists because these two lines should be somewhere else because of the particular situation of my application.
To find yourself in a situation similar to mine I recommend you to start a new project under android studio using the template "Bottom Navigation Activity" and then follow the tutorial.
A friend of mine give me the solution.
Nothing new in MainActivity.kt like I was thinking.
Here is the new code to make tabBar in the Settings fragment :
settingFragment.kt
class SettingsFragmentAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
private val fragments =
listOf(
fragment_setting_teams(),
fragment_setting_general(),
fragment_setting_movies()
)
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
class SettingsFragment : Fragment() {
private lateinit var settingsViewModel: SettingsViewModel
private lateinit var settingsAdapter: SettingsFragmentAdapter
private lateinit var viewPager: ViewPager2
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val tabLayout = view.findViewById<TabLayout>(R.id.tabLayout)
settingsAdapter =
SettingsFragmentAdapter(
this
)
viewPager = view.findViewById(R.id.viewPager2)
viewPager.adapter = settingsAdapter
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
when (position) {
0 -> tab.text = "Teams"
1 -> tab.text = "General"
2 -> tab.text = "Movies"
}
}.attach()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
settingsViewModel =
ViewModelProviders.of(this).get(SettingsViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_settings, container, false)
return root
}
}
Related
I am trying to pass array list data to one of my fragments in the nav bar from main activity. Is there a simple way to implement this? Or should I use activity instead of the fragment? I need to pass the array list data to my HomeFragment and use recycler view adapter in the fragment, but now the issue is I don't know how to pass data because I am using bottom navigation view and Android Navigation component.
Main Activity
package com.example.a5t1v2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
import android.widget.GridView
import androidx.navigation.NavArgument
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomnavigation.BottomNavigationView
class MainActivity : AppCompatActivity() {
private lateinit var bottomNavigationView: BottomNavigationView
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var shoppingItemList:MutableList<Item>
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initUI()
val dbHelper = DBHelper(this)
populateDB(dbHelper)
shoppingItemList = dbHelper.getAlItems()
}
private fun populateDB(dbHelper: DBHelper) {
dbHelper.insertItem(Item("Bread",1,"Default", urgent = true, bought = false,null))
dbHelper.insertItem(Item("Chocolate Bar",1,"Small", urgent = false, bought = false,null))
dbHelper.insertItem(Item("Instant noodle",1,"Default", urgent = false, bought = false,null))
dbHelper.insertItem(Item("Juice",2,"Large", urgent = false, bought = false,null))
dbHelper.insertItem(Item("Milk",3,"Large", urgent = true, bought = false,null))
dbHelper.insertItem(Item("Shampoo",1,"Small", urgent = false, bought = true,"24 Aug 2020"))
dbHelper.insertItem(Item("Shower Gel",1,"Large", urgent = false, bought = true,"24 Aug 2020"))
}
private fun initUI() {
appBarConfiguration = AppBarConfiguration(setOf(R.id.urgentListFragment, R.id.homeFragment, R.id.completedListFragment))
bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
navController = findNavController(R.id.fragmentContainerView)
setupActionBarWithNavController(navController,appBarConfiguration)
bottomNavigationView.setupWithNavController(navController)
}
}
An easy and good way would be to use a sharedViewModel.
Create a ViewModel and declare a LiveData in it.
class MainViewModel: ViewModel () {
private val arrayListLiveData = MutableLiveData<ArrayList<Item>>()
}
Inside Activity, create an instance of this ViewModel in the acitivity, and you can send your arrayList from here using post on the liveData
class MainActivity : AppCompatActivity() {
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.arrayListLiveData.post(YOUR_ARRAY_LIST_DATA)
}
}
You can observe the same liveData inside the fragment, and would receive the posted arrayList there, from the Activity
class TestFragment : Fragment(R.layout.test) {
private lateinit var mainViewModel: MainViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
mainViewModel.arrayListLiveData.observe(viewLifecycleOwner) { arrayList ->
//Perform desired operation with the array list
}
}
}
I am trying to get a spinner working with Kotlin, I have spent hours on it but to no avail. Whatever I do, it doesn't respond to items being selected.
Let's start with the code:
This is my xml layout: (only the spinner)
<Spinner
android:id="#+id/unitySelectionSpinner"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="50"
android:gravity="center"
android:textSize="24sp"
/>
My Fragment:
import android.app.Activity
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.navigation.Navigation
import com.epfl.esl.organizer.databinding.FragmentCreateStorageBinding
import com.google.firebase.database.*
import kotlin.collections.ArrayList
class CreateStorageFragment : Fragment(), AdapterView.OnItemSelectedListener {
private lateinit var binding: FragmentCreateStorageBinding
private lateinit var unitID: String
val database: FirebaseDatabase = FirebaseDatabase.getInstance("myDatabase")
val storageRef: DatabaseReference = database.getReference("Units")
var list = ArrayList<String>()
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Toast.makeText(context, "We got the Key:", Toast.LENGTH_SHORT).show()
var a = 7 / 0
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Toast.makeText(context, "Nothing selected", Toast.LENGTH_SHORT).show()
var b = 7 / 0
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_create_storage, container, false)
// Get the list of names of units from firebase
storageRef.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
// Fill an ArrayList with all the unit names
for(unit in snapshot.children) {
list.add(unit.child("unitName").value.toString())
}
}
override fun onCancelled(error: DatabaseError) {}
})
binding.addObjectButton.setOnClickListener{view: View ->
Navigation.findNavController(view).navigate(R.id.action_createStorageFragment_to_createObjectFragment)
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val spinner: Spinner = binding.unitySelectionSpinner
val spinnerArrayAdapter = ArrayAdapter<String>(activity as Context, android.R.layout.simple_spinner_dropdown_item, list)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = spinnerArrayAdapter
spinner.onItemSelectedListener = this
}
}
I feel that I've tried everything imaginable, including:
-Creating an independent class with the spinner functions (onItemSelected, etc.)
-Put everything in onCreateView, put everything in onViewCreated
-Creating an instance of spinner with AdapterView.OnItemSelectedListener inside onCreateView
Whatever I do the result is always the same: the spinner is populated (all the firebase data is written into it properly) but it doesn't respond when I click on an item in the app. None of the toasts (or the crash that should be caused by the division by zero) are triggered. It simply closes on selection as a normal spinner would do.
I am not sure what I am missing here. Any ideas?
I am very new to taking an android application and for a project I need a BottomNavigati but I cannot get my data that comes from the beginning of the session to pass to the main fragment
Activity:
val bundle1 = Bundle()
bundle1.putString("User",User)
bundle1.putString("Correo",Correo)
bundle1.putString("Region",Region)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController: NavController = navHostFragment.navController
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
navHostFragment.arguments = bundle1
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
HOMEFRAGMEN:
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.textView4)
return root
}
}
There is no direct access to HomeFragment from MainActivity in your case. BottomNavigation uses nested navigation architecture pattern with nested graphs.
More details here: Passing argument(s) to a nested Navigation architecture component graph
But you can use alternative way to pass data from Activity to Fragment using context.
Step 1 - Describe HomeFragmentData model:
data class HomeFragmentData(
val value: String
)
Step 2 - Describe HomeFragment interface:
interface IHomeFragment {
fun getHomeFragmentData(): HomeFragmentData
}
Step 3 - Implement interface to your Activity:
class MainActivity : AppCompatActivity(), IHomeFragment {
override fun getHomeFragmentData(): HomeFragmentData {
return HomeFragmentData(
value = "Home Fragment data"
)
}
// Rest of your code
}
Step 4 - Call function getHomeFragmentData() from HomeFragment using context:
class HomeFragment : Fragment() {
private var interactionListener: IHomeFragment? = null
override fun onAttach(context: Context) {
super.onAttach(context)
when(context) {
is IHomeFragment -> {
interactionListener = context
}
else -> throw RuntimeException("$context has to implement IHomeFragment")
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
interactionListener?.getHomeFragmentData().let {
textView.text = it?.value
}
return root
}
}
I'm having a problem with this SmartToolbar, if I open the app and click on the chat or book icon it opens perfectly and shows the fragments, but if I click on another icon to open another fragment, when I go back to them they don't show more The fragments that should be on the smartToolbar, as shown in the prints below, bug everything! I need to help on this as soon as possible !!!
[Opens normally When I click on another item and go back to it, it no longer opens the SmartToolbar fragmentshere]2
enter image description here
I will send the homeAcitivity code, where is the layout that opens the fragments of the buttonNavigationBar
class HomeActivity : AppCompatActivity() {
var MY_ACCOUNT = 1
var LIBRARY = 2
var HOME = 3
var CHAT = 4
var SETTINGS = 5
private var Content: ConstraintLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar!!.hide()
nav.show(HOME)
nav.setBackgroundColor(Color.TRANSPARENT)
abrirHome()
addOnMeowNavigattionBarIcons()
addOnNotificationInform()
chamarFragments()
}
fun abrirHome() {
val fragment = HomeFragment.newInstance()
addFragment(fragment)
}
fun addOnMeowNavigattionBarIcons() {
nav.add(MeowBottomNavigation.Model(MY_ACCOUNT, R.drawable.ic_baseline_account_circle_24))
nav.add(MeowBottomNavigation.Model(LIBRARY, R.drawable.ic_baseline_menu_book_24))
nav.add(MeowBottomNavigation.Model(HOME, R.drawable.ic_baseline_home_24))
nav.add(MeowBottomNavigation.Model(CHAT, R.drawable.ic_baseline_chat_24))
nav.add(MeowBottomNavigation.Model(SETTINGS, R.drawable.ic_baseline_settings_24))
}
fun addOnNotificationInform() {
nav.setCount(CHAT, "99")
}
fun chamarFragments() {
nav.setOnClickMenuListener {
when (it.id) {
HOME -> {
val fragment = HomeFragment.newInstance()
addFragment(fragment)
}
MY_ACCOUNT -> {
val fragment = MyAccountFragment.newInstance()
addFragment(fragment)
}
LIBRARY -> {
val fragment = LibraryFragment.newInstance()
addFragment(fragment)
}
CHAT -> {
val fragment = ChatFragment.newInstance()
addFragment(fragment)
}
SETTINGS -> {
val fragment = SettingsFragment.newInstance()
addFragment(fragment)
}
}
}
}
private fun addFragment(fragment: Fragment) {
supportFragmentManager
.beginTransaction()
.replace(R.id.parentfragments,fragment,fragment.javaClass.simpleName)
.addToBackStack(null)
.commit()
}
fun sair(view: View){
FirebaseAuth.getInstance().signOut()
val bundle = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
val intent = Intent(this, login::class.java)
startActivity(intent,bundle)
}
}
This is the code of the fragment Library that has a SmartToolbar that calls two more fragments within it, MyLibrary and Store
class LibraryFragment: Fragment() {
companion object{
fun newInstance():LibraryFragment {
val args = Bundle()
val fragment = LibraryFragment()
fragment.arguments = args
return fragment
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.library_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val adapter = FragmentPagerItemAdapter(
fragmentManager, FragmentPagerItems.with(context)
.add("Minha Bilioteca", MyLibraryFragment::class.java)
.add("Loja", StoreFragment::class.java)
.create())
viewpager.adapter = adapter
viewpagertab.setViewPager(viewpager)
}
}
And this is the MyLibrary fragment that is shown inside the Library that is shown inside HomeActivity
class MyLibraryFragment: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.mylibrary_fragment, container, false)
}
}
Beginner here. Creating an app using the Android Developer Studios Tabbed Activity Template. I have two xml, the generated fragment_main.xml that comes with the template and secondtab.xml for what I want to be the second tab.
This is the code generated by the template:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager)
val viewPager: ViewPager = findViewById(R.id.view_pager)
viewPager.adapter = sectionsPagerAdapter
val tabs: TabLayout = findViewById(R.id.tabs)
tabs.setupWithViewPager(viewPager)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
I've been reading through the ViewPager documentation and a lot of what I can find is making this all from scratch and I'm having trouble understanding. I feel like I'm missing something obvious. How do I add my secondtab.xml to this pregenerated template so it shows up when the user clicks on the second tab?
Yours SectionsPagerAdapter getItem function should looks like this:
class SectionsPagerAdapter(
private val context: Context,
fm: FragmentManager
) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int) = when (position) {
0 -> FirstTabFragment()
1 -> SecondTabFragment()
else -> error("Unknown")
}
override fun getPageTitle(position: Int) = context.resources.getString(TAB_TITLES[position])
override fun getCount() = 2
}
Because by default in this template SectionsPagerAdapter always creates PlaceholderFragment:
override fun getItem(position: Int): Fragment {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1)
}
But in yours case you need use two different fragments with two different xml-layouts like this:
class FirstTabFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_main, container, false)
val textView: TextView = root.findViewById(R.id.section_label)
return root
}
}
class SecondTabFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.secondtab, container, false)
val textView: TextView = root.findViewById(R.id.section_label)
return root
}
}
Also make sure to add:
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/activity_horizontal_margin"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginEnd="#dimen/activity_horizontal_margin"
android:layout_marginBottom="#dimen/activity_vertical_margin"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="#+id/constraintLayout"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1" />
to the fragment xml