i am trying to add viewpager and tablayout along with bottom navigation. First time fragment loads fine then i click the item the fragment is not loading properly
here is my main activity code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<include layout="#layout/toolbar"
android:id="#+id/layout_toolbar"/>
<FrameLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_nav_menu"
android:background="#drawable/bg_bottom_bar"
/>
</LinearLayout>
Kotlin Code
bottomNav.setOnNavigationItemSelectedListener {
var selectedFragment: Fragment? = null
when (it.itemId) {
R.id.homeFragment -> {
replaceFragment(fragment = HomeFragment())
return#setOnNavigationItemSelectedListener true
}
R.id.fixtures -> {
replaceFragment(fragment = AllMatchsFragment())
return#setOnNavigationItemSelectedListener true
}
}
false
}
private fun replaceFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction().replace(R.id.fragmentContainer, fragment).commit()
}
Here is fragment code where i want to load viewpager and tablayout:
homePagerAdapter = HomeViewpagerAdapter(activity!!.supportFragmentManager)
homePagerAdapter!!.populateFragment(AllMatchsFragment())
homePagerAdapter!!.populateFragment(LiveMatchesFragment())
view.homeViewPager.adapter=homePagerAdapter
view.tabLayout.setupWithViewPager(view.homeViewPager)
return view
Fragment XML
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="172dp"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabTextColor="#color/colorPrimary"
app:tabSelectedTextColor="#color/colorAccent"
>
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/homeViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tabLayout"/>
ViewPagerAdapter
val tabNameList= listOf("All","Live")
val fragmentList = mutableListOf<Fragment>()
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
override fun getCount(): Int {
return 2
}
override fun getPageTitle(position: Int): CharSequence? {
return tabNameList[position]
}
fun populateFragment(fragment: Fragment){
fragmentList.add(fragment)
}
When I perform second click on the second viewpager got stuck and fragment disappear when I close and reopen the app it works fine and after second click again remain the same.
Try to use childFragmentManager instead of supportFragmentManager
homePagerAdapter = HomeViewpagerAdapter(activity!!.supportFragmentManager)
Related
this is MainActivity
class MainActivity : AppCompatActivity(), FragmentDrawerListener,
BottomNavigationView.OnNavigationItemSelectedListener {
private lateinit var drawerFragment: DrawerFragment
#Inject
lateinit var mainActivityViewModel: MainActivityViewModel
#Inject
lateinit var appPreference: AppPreference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidInjection.inject(this)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
navigation.setOnNavigationItemSelectedListener(this)
displayView()
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onDrawerItemSelected(view: View, position: Int) {
displayView(position)
}
private fun displayView() {
drawerFragment =
supportFragmentManager.findFragmentById(R.id.fragment_navigation_drawer) as DrawerFragment
drawerFragment.init(R.id.fragment_navigation_drawer, drawer_layout, toolbar)
displayView(0)
}
private fun displayView(position: Int) {
when (position) {
0 -> {
HomeFragment()
}
5 -> {
val intent = Intent(this, MerchantOnBoardingActivity::class.java)
startActivity(intent)
}
9 -> {
val intent = Intent(this, AppSecurityActivity::class.java)
startActivity(intent)
}
else -> {
val bundle = Bundle()
bundle.putInt("menuItemPosition", position - 1)
val intent = Intent(this, MenuActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
}
}
}
private fun showDefaultPage() {
val fragment = HomeFragment()
title = "Home"
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.main_content, fragment)
fragmentTransaction.commit()
supportActionBar?.title = title
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
var fragment: Fragment? = null
when (item.itemId) {
R.id.navigation_home -> fragment = HomeFragment()
R.id.navigation_monitor -> Toast.makeText(this, "Monitor", Toast.LENGTH_LONG).show()
R.id.navigation_profile -> Toast.makeText(this, "Profile", Toast.LENGTH_LONG).show()
}
return loadFragment(fragment)
}
private fun loadFragment(fragment: Fragment?): Boolean {
//switching fragment
if (fragment != null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit()
return true
}
return false
}
}
This is my xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:local="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
local:popupTheme="#style/ThemeOverlay.AppCompat.Light"
local:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<FrameLayout
android:id="#+id/main_content"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemIconTint="#color/design_default_color_primary"
app:itemTextColor="#color/design_default_color_primary"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation" />
</LinearLayout>
<fragment
android:id="#+id/fragment_navigation_drawer"
android:name="com.egpaid.employeeapp.home.homedashboard.DrawerFragment"
android:layout_width="260dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:layout="#layout/fragment_drawer"
tools:layout="#layout/fragment_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
</LinearLayout>
</RelativeLayout>
using this code i am able to display data but when i try to click on Home button on either from bottom navigation view or from drawber then i am getting
No view found for id 0x7f0900a3 (com.egpaid.employeeapp:id/fragment_container) for fragment HomeFragment{9d6bf5} (7b531975-d1d4-4ad4-b3c7-6f43ae436c6d) id=0x7f0900a3}
I don't know what i am missing i am trying to create custom navigation drawber with bottom navigation view please help me Thanks
I'm having an issue with a very simple task with Navigation component.
I have just 2 screens: MainFragment and SearchFragment.
When I try to go from MainFragment to SearchFragment by navigation with an action it works perfectly. Then I press the back button and naturally it goes back to the MainFragment.
The issue is, when I click the same button the second time to go again to the SearchFragment, I receive the following error:
java.lang.IllegalArgumentException: Navigation action/destination action_mainFragment_to_searchFragment cannot be found from the current destination Destination(searchFragment)
I'm navigating from the MainFragment to Search like this:
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
I tried redoing the nav_graph.xml but without success.
If I just navigate with the id directly, it works fine and I go back and forth as many times as I want
findNavController().navigate(R.id.searchFragment)
Any ideas how to fix the issue with the safe args?
Edit:
This is my nav_graph
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph_main"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="news.presentation.main.MainFragment"
android:label="fragment_main"
tools:layout="#layout/fragment_main">
<action
android:id="#+id/action_mainFragment_to_searchFragment"
app:destination="#id/searchFragment" />
</fragment>
<fragment
android:id="#+id/searchFragment"
android:name="news.presentation.search.SearchFragment"
android:label="fragment_search"
tools:layout="#layout/fragment_search" />
</navigation>
This is the activity (it's basically just a container for the fragments):
This is the activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/homeFragContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph_main"
tools:context=".presentation.HomeActivity" />
And this is the HomeActivity.kt
#AndroidEntryPoint
class HomeActivity : AppCompatActivity(R.layout.activity_home)
This is the HomeFragment:
#AndroidEntryPoint
class MainFragment : Fragment(R.layout.fragment_main) {
private val binding by viewBinding(FragmentMainBinding::bind)
private val viewModel by viewModels<MainViewModel>()
private val articlesAdapter = ArticlesAdapter(::onSubscriptionClicked)
private lateinit var layoutManager: LinearLayoutManager
override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle)
setupViews()
setupViewModel()
setupRecyclerView()
}
private fun setupViews() {
binding.toolbar.title = getString(R.string.app_name)
binding.fab.setOnClickListener {
viewModel.intent.offer(MainViewModel.Intent.SearchClicked)
}
}
private fun setupViewModel() {
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
viewModel.feedFlow
.onEach(articlesAdapter::submitList)
.launchIn(lifecycleScope)
}
private fun setupRecyclerView() {
layoutManager = LinearLayoutManager(requireContext())
binding.recycler.layoutManager = layoutManager
binding.recycler.adapter = articlesAdapter
binding.recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val canScroll = recyclerView.canScrollVertically(-1)
binding.toolbar.isLifted = canScroll
}
})
}
private fun onSubscriptionClicked(article: Article) {
viewModel.intent.offer(MainViewModel.Intent.ItemClicked(article))
}
private fun handleState(state: MainViewModel.State) = when (state) {
NavigateToSearch -> findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
is FeedReady -> binding.progress.isVisible = false
Loading -> binding.progress.isVisible = true
is NavigateToArticle -> {
// works
// findNavController().navigate(
// R.id.articleFragment,
// bundleOf("articleLink" to state.link)
// )
}
}
}
And this is the XML for it:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
tools:context=".presentation.main.MainFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/bottomNav"
app:layout_constraintTop_toBottomOf="#id/toolbar"
tools:listitem="#layout/item_article_big" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/standard"
android:text="Add Feed"
android:textAlignment="center"
app:icon="#drawable/ic_add"
app:layout_constraintBottom_toTopOf="#id/bottomNav"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="#menu/menu_main" />
<tgo1014.news.presentation.customview.LiftableToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="#+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="#id/toolbar"
app:layout_constraintTop_toBottomOf="#id/toolbar"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
the error is due to the lifecycle.
Replace this:
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
by
viewModel.state
.onEach(::handleState)
.launchIn(viewLifecycleOwner.lifecycleScope)
I have got problems.
There are 5 fragment in MainActivity. It is D1, D2, D3, D4, D5 Fragment. And there is BottomNavigationView in MainActivity. I want to call DxFragment from D1fragment. The button will be clicked and only the frame will change. But the button navigation bar will not change.
I've been looking for a while. I couldn't find the solution. Can anyone please help?
MAINACTIVITY
class MainActivity : AppCompatActivity() {
private lateinit var bottomNavigationView : BottomNavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomNavigationView = findViewById(R.id.nav_view)
navigateFragment(false)
}
public fun loadFragment (fragment: Fragment){
supportFragmentManager.beginTransaction().also { fragmentTransaction ->
fragmentTransaction.replace(R.id.bottom_nav_host_fragment, fragment)
fragmentTransaction.commit()
}
}
public fun navigateFragment ( stateFragment : Boolean) {
bottomNavigationView = findViewById(R.id.nav_view)
bottomNavigationView.setOnNavigationItemSelectedListener { menuItem : MenuItem ->
when{
menuItem.itemId== R.id.navigation_home -> {
loadFragment(D1Fragment())
return#setOnNavigationItemSelectedListener true
}
menuItem.itemId == R.id.navigation_map -> {
loadFragment(D2Fragment())
return#setOnNavigationItemSelectedListener true
}
menuItem.itemId == R.id.navigation_userpage -> {
loadFragment(D3Fragment())
return#setOnNavigationItemSelectedListener true
}
menuItem.itemId == R.id.navigation_fav -> {
loadFragment(D4Fragment())
return#setOnNavigationItemSelectedListener true
}
menuItem.itemId == R.id.navigation_list -> {
loadFragment(D5Fragment())
return#setOnNavigationItemSelectedListener true
}
stateFragment == true -> {
loadFragment(BlankFragment())
return#setOnNavigationItemSelectedListener true
}
else -> {
return#setOnNavigationItemSelectedListener true
}
}
}
}
override fun onSupportNavigateUp(): Boolean {
return Navigation.findNavController(this, R.id.bottom_nav_host_fragment).navigateUp() ||
super.onSupportNavigateUp()
}
}
ACTIVITY_MAIN.XML
some part
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_menu" />
<FrameLayout
android:id="#+id/bottom_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
FRAGMENT_D1.XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".D1Fragment">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CLICK AND GO BLANKFRAGMENT" />
</FrameLayout>
D1FRAGMENT
class D1Fragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_d1, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
button.setOnClickListener {
Toast.makeText(context , "CLICKED" , Toast.LENGTH_SHORT ).show()
Navigation.findNavController(view).navigate(R.id.action_d1Fragment_to_blankFragment)
}
super.onViewCreated(view, savedInstanceState)
}
}
BUTTON CLICK AND ERROR
java.lang.IllegalStateException: View android.widget.FrameLayout{16424ce5 V.E..... ........ 0,0-1080,1365} does not have a NavController set
at androidx.navigation.Navigation.findNavController(Navigation.java:84)
at com.axisting.bottomelledeneme.D1Fragment$onViewCreated$1.onClick(D1Fragment.kt:35)
You only needs to have a principal class,
Example main's activity, it contains the BottomNavigationView and fragment. the fragments have the other element
Example
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_nav_menu" />
</androidx.con straintlayout.widget.ConstraintLayout>
You only need to attach the fragment
I have a TabLayout with two fragments which both of them shows a RecyclerView (one movies and the other tv shows). The TabLayout works perfectly but the problem comes when I click on the image of a film. The click in a movie should make a transaction to the movie details fragment. But when this happens the ListFragment with the TabLayout appears under the new one so the two of them are displayed.
My ActivityMain code where I call the transaction and where I set the Page Adapter:
override fun onMovieClicked(iDMovie: Int) {
val movieDetails = MovieDetailsFragment.newInstance(iDMovie)
supportFragmentManager.
beginTransaction().
replace(R.id.main_container, movieDetails).
addToBackStack(null).
commit()
}
private fun setStatePageAdapter() {
val fragmentAdapter = MyPagerAdapter(supportFragmentManager)
viewPager.adapter = fragmentAdapter
tabLayout.setupWithViewPager(viewPager)
}
My PageAdapterClass:
class MyPagerAdapter(fm: FragmentManager): FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> {
ListFilmFragment()
}
else -> {
return TVShowsFragmentList()
}
}
}
override fun getCount(): Int {
return 2
}
override fun getPageTitle(position: Int): CharSequence {
return when (position) {
0 -> "PelĂculas"
else -> {
return "Series"
}
}
}
}
And the Layouts:
Activity Main:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?actionBarSize"
app:tabGravity="fill"
app:tabIndicatorHeight="4dp"
app:tabBackground="#color/black"
app:tabMode="fixed"
app:tabTextColor="#color/white"
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_height="match_parent"
android:layout_width="match_parent">
</android.support.v4.view.ViewPager>
Observation: With FrameLayout instead of Coordinator didn't work either.
The result I get is the following:
The FragmentDetails overlaps the filmListFragment and the two of them are displayed at the same time. But only the details fragments has to be displayed.
You can solve your problem in 2 ways
first:
You can hide your ViewPager and TabLayout befor inflating Your fragments.
so change your MovieClicked method like below
override fun onMovieClicked(iDMovie: Int) {
viewPager.visibiliy=View.Gone;
tabLayout.visibility=View.Gone
val movieDetails = MovieDetailsFragment.newInstance(iDMovie)
supportFragmentManager.
beginTransaction().
replace(R.id.main_container, movieDetails).
addToBackStack(null).
commit()
}
Seconde:
You can change your fragments XML Root elements
1-set a background for each of you fragments android:background="yourColor" to hide
behind layout .
2-set OnClick attribute to true to make app receive your current layout
onClickListeners not behind layout with android:onClick=true
Your Xml must be like below
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="true"
android:background="#ffffff"<!--White Color for example-->
>
</android.support.design.widget.CoordinatorLayout>
If you have several fragment layout that has your problem
You can set an style and change your fragment style to your style
So declare an style in style.xml
<style name="fragmentsRootElementStyle">
<item name="android:onClick">true</item>
<item name="android:background">#ffffff</item>
</style>
and set style for fragment layouts root as below
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="#style/fragmentsRootElementsStyle"
>
</android.support.design.widget.CoordinatorLayout>
There are many answers to that question in Java language, but I can not apply it
using Kotlin.
I use ViewPager to switch between tabs and I want MainActivity title to be changed every time when I swipe.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
container.adapter = TabPagerAdapter(supportFragmentManager)
container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container))
}
override fun setTitle(title: CharSequence?) {
supportActionBar?.title = title
}
}
I use "kotlin-android-extensions", so container is id of ViewPager and tabs is id of TabLayout. I also created class TabPagerAdapter that extends FragmentPagerAdapter. It returns correct tab, which is Fragment derivative, with getItem method. I tried to achieve my goal by overriding getPageTitle method but it doesn't work.
class TabPagerAdapter(fragmentManager: FragmentManager) :
FragmentPagerAdapter(fragmentManager) {
override fun getItem(p0: Int): Fragment {
return when (p0) {
else -> TestTab.newInstance()
}
}
override fun getPageTitle(position: Int): CharSequence? {
return "test title"
}
override fun getCount(): Int {
return 1
}
}
My tab example:
class NotificationsTab : Fragment() {
private val _title = "Notifications"
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_notifications, container, false)
}
companion object {
fun newInstance(): NotificationsTab {
return NotificationsTab()
}
}
}
I want variable _title to be the MainActivity title.
XMLs that I use:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.androidtest.activities.MainActivity"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="63"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="50"
android:background="#ffffff"
app:layout_scrollFlags="scroll|enterAlways"
app:title="#string/app_name">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="50"
app:tabIndicatorColor="#color/tabIndicatorColor"
app:tabIndicatorHeight="3dp">
<android.support.design.widget.TabItem
android:id="#+id/tab_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"/>
<android.support.design.widget.TabItem
android:id="#+id/tab_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"/>
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_weight="390"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="0dp"/>
</LinearLayout>
fragment_notifications.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:text="notifications"
android:layout_gravity="center"
android:textAlignment="center"
android:textSize="56sp"
android:layout_height="wrap_content"/>
</LinearLayout>
As I understand when users swipe between tabs, you will set the tab's text as title of the activity. Here is a solution
First remove all TabItem tags from activity_main.xml layout file because you are using TabLayout with ViewPager. The ViewPager will handle how to setup tab (number of tabs, fragment at each tab, title at each tab, etc).
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="50"
app:tabIndicatorHeight="3dp">
<!--<android.support.design.widget.TabItem-->
<!--android:id="#+id/tab_profile"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="1"/>-->
<!--<android.support.design.widget.TabItem-->
<!--android:id="#+id/tab_notifications"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="2"/>-->
</android.support.design.widget.TabLayout>
Then change your code in MainActivity
container.adapter = TabPagerAdapter(supportFragmentManager)
// Comment-out or remove these lines
// container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
// tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container))
// Pass viewpager to tablayout to setup tabs.
tabs.setupWithViewPager(container)
// Handle event when users swipe to a tab, here we set tab's text as title of the activity.
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
title = tab.text // the value of tab's text is the returned value from `getPageTitle` method in TabPagerAdapter class.
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
// For the first time open the app, we set first tab's title as title of this activity
title = container.adapter!!.getPageTitle(0)
viewPagerAtmosphericInfo.addOnPageChangeListener(object: ViewPager.OnPageChangeListener{
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
// code here
})
If you want to set the title of your activity with tabs, You have to set the title of activity(s) actionbar which you can set from fragment by using activity instance.
Example :
//initialize activity instance
lateinit var mActivity: AppCompatActivity
//get activity inside your onViewCreated of fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mActivity = activity as MainActivity
}
// inside your fragment
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if(isVisibleToUser){
//change your title from here, make sure that activity is not null
mActivity.supportActionBar?.title = "Your Title"
}
}
Let me now if you have any query! :)