How to implement custom TabLayout with ViewPager2 with recyclerView in Kotlin? - android

I am stuck with this problem and I am not getting any solution to that, I want a tablayout with viewpager2 which has recycler view inside it. MainActivity.kt:-
#RequiresApi(Build.VERSION_CODES.Q)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
pager = findViewById(R.id.view_pager)
tab = findViewById(R.id.extra)
val adapter = SectionsPagerAdapter(supportFragmentManager, lifecycle)
pager.adapter = adapter
TabLayoutMediator(tab,pager){tab,position ->
when(position){
0->{
tab.text="RECENT"
}
1->{
tab.text="SAVED"
}
2->{
tab.text="TOOLS"
}
}
}.attach()
SectionPagerAdapter.kt:-
class SectionsPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle):
FragmentStateAdapter(fragmentManager, lifecycle) {
override fun getItemCount(): Int {
return 3 }
override fun createFragment(position: Int): Fragment {
// return a particular fragment page
return when (position) {
0 -> {
return tabrecentFragment()
}
1 -> {
return tabsavedFragment()
}
2 -> {
return tabtoolsFragment()
}
else -> {
return tabrecentFragment()
}
}
}
}
I am getting error-:
Installation failed due to: ''package install-create -r -t --user
current --full --dont-kill -S 7376065' returns error 'Unknown failure:
cmd: Can't find service: package'' Retry Failed to launch an
application on all devices.
And when I connect my android device to run the app then it gives the error:-
Caused by: java.lang.NullPointerException: findViewById(R.id.extra)
must not be null at
com.whatsappstatussaverlatest.MainActivitySSW.onCreate(MainActivitySSW.kt:125)
If you have any solution then please help

Related

Create fragment in viewpager adapter when tab selected

There are two fragments inside viewPager. When the main fragment load the location permission code on the second fragment that work. Want that fragmen work when click the second tab. So I think I need to create this fragment when selected second tab. How can detect and do this?
OurHospitalFragment.kt
viewPager2OurHospital.adapter = adapter
viewPager2OurHospital.offscreenPageLimit = 1
TabLayoutMediator(tabLayoutOurHospital, viewPager2OurHospital) { tab, position ->
when (position) {
0 -> tab.text = getString(R.string.list)
1 -> tab.text = getString(R.string.map)
}
}.attach()
tabLayoutOurHospital.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
tab?.let {
viewPager2OurHospital.isUserInputEnabled = tab.position != 1
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
OurHospitalASMViewPagerAdapter.kt
class OurHospitalViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
FragmentStateAdapter(fragmentManager, lifecycle) {
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> HospitalListFragment()
1 -> HospitalMapFragment()
else -> Fragment()
}
}
}
I wrote this code line:
viewPager2OurHospital.offscreenPageLimit = ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
instead of this:
viewPager2OurHospital.offscreenPageLimit = 1
and I get it what I want.

How can I tell the adapter ViewPager2 to redraw elements?

My app contains viewpager and tablayout. It requests data from the server, sorts and gives each tab its own set of information. I don't want to have a request to the network every time I select a tab, so I made a host fragment that makes a request to the network and creates tabs. But when the data arrives, the view is already rendered. I give the data through the bundle to the ViewPagerAdapter. The first tab does not update the data. How can I tell the adapter to redraw a particular element?
HostFragment
private val tabsTitles by lazy(LazyThreadSafetyMode.NONE) {
listOf("All", "Analytics", "Android", "Management")
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val departmentTabLayout = view.findViewById<TabLayout>(R.id.departmentTabLayout)
val departmentViewPager = view.findViewById<ViewPager2>(R.id.departmentViewPager)
val adapter = TabsAdapter(childFragmentManager, lifecycle)
departmentViewPager.adapter = adapter
attachTabs(departmentTabLayout, departmentViewPager)
departmentHostViewModel.listUsers.observe(viewLifecycleOwner, {
adapter.getUsers(it.items)
//adapter.notifyDataSetChanged()
})
}
private fun attachTabs(departmentTabLayout: TabLayout, departmentViewPager: ViewPager2) {
TabLayoutMediator(departmentTabLayout, departmentViewPager) { tab, position ->
tab.text = tabsTitles[position]
}.attach()
}
TabsAdapter
class TabsAdapter(
fm: FragmentManager,
lifecycle: Lifecycle,
) : FragmentStateAdapter(fm, lifecycle) {
private val listDepartments = listOf(
"all",
"analytics",
"android",
"management"
)
private val listUsers: MutableList<User> = mutableListOf()
override fun createFragment(position: Int): Fragment {
val departmentFragment = DepartmentFragment()
return when (position) {
0 -> {
departmentFragment.arguments = bundleOf(DepartmentFragment.LIST_USERS to listUsers)
return departmentFragment
}
else -> {
departmentFragment.arguments =
bundleOf(DepartmentFragment.LIST_USERS to listUsers.filter { it.department == listDepartments[position] })
return departmentFragment
}
}
}
override fun getItemCount(): Int {
return listDepartments.count()
}
fun getUsers(listUsers2: List<User>) {
listUsers.addAll(listUsers2)
notifyDataSetChanged()
}
}

How to fix "java.lang.IllegalStateException: Fragment already added" in Android Kotlin

I'm trying to display my RecyclerView into a fragment, which is inside a TabLayout.
I am new to this and don't get what to do for fixing it. While debugging I get:
java.lang.IllegalStateException: Fragment already added.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewPager: ViewPager = findViewById(R.id.view_pager)
val tabs: TabLayout = findViewById(R.id.tabs)
viewPager.adapter = SectionsPagerAdapter(this, supportFragmentManager)
tabs.setupWithViewPager(viewPager)
MainActivity
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> FragIn()
1 -> FragProd()
2 -> FragShelf()
else -> FragIn()
}
}
getItem()-function in my PagerAdapter
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> FragIn()
1 -> FragProd()
2 -> FragShelf()
else -> FragIn()
}
}
Just check what is in the method of 'FragIn()', you will get a repeated fragment if there is not a new fragment.

In tab layout fragments not showing their layout in androidX

I have a tab layout in which I have included five fragments, but when i click on tabs, the fragments layout is not showed. In my adapter I've extended FragmentPagerAdapter which has FragmentManager and a variable behaviour.
class ViewPagerAdapter(#NonNull fm:FragmentManager, behaviour:Int):
FragmentPagerAdapter(fm, behaviour) {
private val tabs:Array<Fragment> = arrayOf(
Category1Fragment(),
Category2Fragment(),
Category3Fragment(),
Category4Fragment(),
Category5Fragment()
)
#NonNull
override fun getItem(position: Int): Fragment {
return tabs[position]
}
override fun getCount(): Int {
return tabs.size
}
#Nullable
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> "Bags"
1 -> "Watches"
2 -> "Shoes"
3 -> "Glasses"
4 -> "Audio"
else -> null
}
}
}
and in my activity I've called adapter through viewpager, but when I debug is telling me that adapter is null, here's my activity code:
val adapter = ViewPagerAdapter(supportFragmentManager, tab_layout.selectedTabPosition)
val viewPager = findViewById<ViewPager>(R.id.view_pager)
viewPager.adapter = adapter
val tab = findViewById<TabLayout>(R.id.tab_layout)
tab.setupWithViewPager(view_pager)
// -------------------------------------------------------------------------------- //
tab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(p0: TabLayout.Tab?) {
}
override fun onTabUnselected(p0: TabLayout.Tab?) {
}
override fun onTabSelected(p0: TabLayout.Tab?) {
viewPager.currentItem = tab.selectedTabPosition
}
})
In the previous versions of android I did the same, but in androidX things are something different. I tried also to use ViewPager2, but it was confusing.
Any help is appreciated!

How to use the FragmentPagerAdapter with unique unrelated fragments?

I am trying to implement a simple swiping action between the three main screens of my app (feed, forum & profile).
I've been looking for guides online but they all seem to take the same approach and show how to implement the adapter using fragments that are simple instances of a basic class that for example just inflates a title and a number on the screen.
In my case, the fragments are not all instances of the same class and are completely different.
M problem lays in the FragmentPagerAdapter. I am not sure how to return each fragment in the getItem method.
I have tried the following but it doesn't except it as a valid return statement and is still expecting one:
class PagesPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(p0: Int): Fragment? {
return when (p0){
0 -> FeedFragment.newInstance()
1 -> BoardFragment.newInstance()
2 -> ProfileFragment.newInstance()
else -> FeedFragment.newInstance()
}
}
override fun getCount(): Int {
return 3
}
}
This is an example of one of my fragments:
class FeedFragment : Fragment() {
val galleryAdapter = GroupAdapter<ViewHolder>()
private fun setUpGalleryAdapter() {
feed_gallary.adapter = galleryAdapter
val galleryLayoutManager = GridLayoutManager(this.context, 3)
feed_gallary.layoutManager = galleryLayoutManager
val dummyUri =
"https://firebasestorage.googleapis.com/v0/b/dere-3d530.appspot.com/o/20150923_100950.jpg?alt=media&token=97f4b02c-75d9-4d5d-bc86-a3ffaa3a0011"
val imageUri = Uri.parse(dummyUri)
if (imageUri != null) {
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setUpGalleryAdapter()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_feed, container, false)
companion object {
fun newInstance(): FeedFragment = FeedFragment()
}
}
And this is my main activity:
class MainActivity : AppCompatActivity() {
private lateinit var viewPager: ViewPager
private lateinit var pagerAdapter: PagesPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPager = findViewById<ViewPager>(R.id.view_pager)
pagerAdapter = PagesPagerAdapter(supportFragmentManager)
viewPager.adapter = pagerAdapter
}
}
I have also tried to define a variable currentFragment, have it reassigned for each of the when statements and have it be the return value, but as all my fragments are unique I am getting a type mismatch when trying to assign them all to one variable.
Is there some Array I can store the fragments in and then return the array position?
I feel like there is probably a simple elegant and common solution here.
Without seeing all of your code I cannot be sure but one thing to note is you must return an instance of your fragment not a reference to the class. Ex: FeedFragment() instead of FeedFragment.
Also, your when statement does not have a default case resulting in a compile error for the getItem method as you have a code path that doesn't return anything. Try the following code for getItem
override fun getItem(p0: Int): Fragment {
when(p0){
0 -> return FeedFragment.newInstance()
1 -> return BoardFragment.newInstance()
else -> return ProfileFragment.newInstance()
}
}
Unfortunately, there is no elegant solution for this case. You can store created fragment in array and then use this array when you need to access related fragment instance.
class PagesPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
private val fragments = SparseArray<WeakReference<Fragment>>()
override fun getCount() = 3
override fun getItem(position: Int): Fragment? {
val fragmentReference = fragments[position]
return if (fragmentReference?.get() != null) {
fragmentReference.get()
} else {
return when (position) {
0 -> FeedFragment.newInstance()
1 -> BoardFragment.newInstance()
2 -> ProfileFragment.newInstance()
else -> error("Incorrect position: $position")
}
}
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
fragments.put(position, WeakReference(fragment))
return fragment
}

Categories

Resources