Why fragment based viewPager.setCurrentItem is not working inside an adapter? - android

I have a fragment in MainActivity that handles other fragments inside a view page.
This is that one:
class FragOrdersHolder : Fragment() {
lateinit var viewPager: ViewPager
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
val mainView = inflater.inflate(R.layout.orders_holder_frg, container, false)
return mainView
}
override fun onViewCreated(mainView: View, savedInstanceState: Bundle?) {
super.onViewCreated(mainView, savedInstanceState)
viewPager = mainView.findViewById(R.id.ordersViewPagerID)
viewPager.adapter = OrdersPagerAdapter(activity!!.supportFragmentManager)
val pagerTab = mainView.findViewById<PagerTabStrip>(R.id.pagerHeaderID)
pagerTab.tabIndicatorColor = Color.WHITE
pagerTab.setTextColor(Color.WHITE)
}
fun GoTo(pos: Int) {
Handler().post(Runnable {
viewPager.setCurrentItem(pos, true)
})
}
}
I have 3 fragments in my viewPager and one of them, have a recyclerview inside it.
the recyclerview has a custom adapter class.
I want to go to next tap in viewPager when clicking on an item in the recylerview.
I'm calling the GoTo method in adapter class like this:
val fm = (activity as MainActivity).supportFragmentManager
val fragm = fm.findFragmentByTag("HOLDER") as FragOrdersHolder
fragm.GoTo(2)
I'd tried everything viewPager.setCurrentItem not working!
please help me.

Related

Android LiveData was observed in three fragments, but only one is actually observing and upadate UI. Other two are not observing

I have tried this problem all days long and still cannot be resolved.
I am writing an app which has three fragments, connected by Navigation Component (with only one activity).
Fragment A
Fragment B
Fragment C
And I observed one LiveData variable from ViewModel in these three fragments.
But only Fragment B is responding. The other two are not.
I have read almost all similar problems from this stack over flow. But still can't see the answer.
Please suggest me.
I have tried removing the observer from FragmentB (which is ok with observing Live Data). But the other two is not still observing)
Here is my code:
Fragment B: (Observe Working)
class ServerFragment : Fragment() {
private lateinit var binding: ServerLayoutBinding
private val vm: DataModel by viewModels()
private lateinit var devices_observer: Observer<MutableList<ClientSocket>>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = ServerLayoutBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var client_list_adapter = ClientListAdapter(layoutInflater)
binding.clientListRcv.apply {
layoutManager = LinearLayoutManager(this.context)
addItemDecoration(
DividerItemDecoration(
this.context,
DividerItemDecoration.VERTICAL
)
)
adapter = client_list_adapter
}
client_list_adapter.submitList(vm.clientDevices.value?.toList())
vm.clientDevices.observe(viewLifecycleOwner, Observer {
client_list_adapter.submitList(vm.clientDevices.value?.toList())} )
}
}
Fragment C: (Observe Not Working)
class FileListFragment: Fragment() {
private val vm: DataModel by viewModels()
private lateinit var binding: FileListBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding=FileListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Here I am populating my recycler view with ViewModel data
//And ViewModel live dat is obeserving here and
vm.clientDevices.observe(viewLifecycleOwner, Observer{
///Here UI updating work will be done. But did'not responded. Here is the problem point I think.
Toast.makeText(context, "OKKK", Toast.LENGTH_SHORT).show()
})
}
}

Get reference of viewPager2 from child fragment

I have a fragment which contains a ViewPager2, It has 3 child fragments, I want to receive an reference viewpager in child fragment to be able to change viewPager programmatically. Since parent fragment which contains viewPager is not activity I can not access the viewPager with findViewById. On another question a usersuggested val pager = container as ViewPager2 but it's returning null. Can someone help me with this. As seen in code snippets, I am trying to get an reference to viewPager in BillingFragment from OneFragment.
Please let me know if you need to see ViewPagerAdapter code snippet.
Child fragment
class OneFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_billing, container, false)
val pager = container as ViewPager2
// ^^^^^ page is null
return view;
}
ViewPager main fragment
class BillingFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_billing_main, container, false)
setupStepView(view)
setupViewPager(view)
setupButtons(view)
return view
}
private fun setupStepView(view: View) {
view.stepView.state
// You should specify only stepsNumber or steps array of strings.
// In case you specify both steps array is chosen.
.steps(
listOf(
"First Step",
"Second Step",
"Third Step"
)
) // You should specify only steps number or steps array of strings.
// In case you specify both steps array is chosen.
.stepsNumber(3)
.animationDuration(resources.getInteger(android.R.integer.config_shortAnimTime))
.commit()
view.stepView.setOnStepClickListener { position ->
// viewPager.setCurrentItem(position, false)
}
}
private fun setupViewPager(view: View) {
// viewPager = view.viewPager;
view.viewPager.adapter = ViewPagerAdapter(childFragmentManager, lifecycle)
view.viewPager.registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
view.stepView.go(position, true)
setButtons(position, view)
}
}
)
}
private fun setupButtons(view: View) {
view.backButton.setOnClickListener {
view.viewPager.setCurrentItem(view.viewPager.currentItem - 1, false)
}
view.nextButton.setOnClickListener {
view.viewPager.setCurrentItem(view.viewPager.currentItem + 1, false)
}
}
private fun setButtons(position: Int, view: View) {
when (position) {
0 -> {
view.backButton.visibility = View.INVISIBLE
view.nextButton.visibility = View.VISIBLE
}
1 -> {
view.backButton.visibility = View.VISIBLE
view.nextButton.visibility = View.VISIBLE
}
2 -> {
view.backButton.visibility = View.VISIBLE
view.nextButton.visibility = View.INVISIBLE
}
}
}
}
Accessing the child fragment's view in parent fragment is not a good idea. If you want to trigger any action from the fragment. You can follow these steps:
class MyViewPagerAdapter(...) : FragmentStateAdapter(...){
lsit : List<Fragment>
fun getItem(position :Int) = list[position]
}
class OneFragment : Fragment(){
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_billing, container, false)
val position = viewPager2.currentItem
(adapter.getItem(position) as? BillingFragment)?.
return view;
}
}
class BillingFragment : Fragment(){
override fun onViewCreated(...){
...
}
// pass the data in the parameter that you want to use or update
fun updateViewPager(position : Int){
// perform your actions
view.viewPager.currentItem = position
}
}
Alternatives
If you know about EventBus, then you can use EventBus.
The android's default way is to use BroadcastReceiver.

Kotlin Android Navigate to a Fragment with OnItemClickListener of a listview

So I Have this one Fragment:
class OrderListFragment : Fragment() {
val language = arrayOf<String>(//Some String Content)
val description = arrayOf<String>( //Some String Content )
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Binding object for this fragment and the layout
val binding: FragmentOrderListBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_order_list, container, false)
val myListAdapter = OrderListAdapter((activity as AppCompatActivity),language,description)
binding.listView.adapter = myListAdapter
binding.listView.setOnItemClickListener(){adapterView, view, position, id ->
val itemAtPos = adapterView.getItemAtPosition(position)
val itemIdAtPos = adapterView.getItemIdAtPosition(position)
Navigation.createNavigateOnClickListener(R.id.action_orderListFragment_to_orderDetailFragment)
Toast.makeText((activity as AppCompatActivity), "Click on item at $itemAtPos its item id $itemIdAtPos", Toast.LENGTH_LONG).show()
}
//Return.... i don't know.
return binding.root
}
}
What i want is that when i click one of the listview items, it'll navigate to other fragments using this line.
Navigation.createNavigateOnClickListener(R.id.action_orderListFragment_to_orderDetailFragment)
But it does not do anything. Am i missing something ?

How to speedup when change fragment in Android

WHY NOT ANY PEOPLE HELP TO ME???
In my application I used BottomNavBar and NavigationGraph for show some fragments!
In one of my fragments I have many views (fragment layout has 1069 lines xml codes) and when select this fragment from BottomNavBar, after some second show me this fragment.
In the other words show me this fragment with delay!
Fragment codes:
class HomeDashboardFragment : Fragment(), HomeDashboardContracts.View {
#NonNull
private var pageTitle: TextView? = null
#NonNull
private var menuIcon: TextView? = null
private lateinit var token: String
private lateinit var presenter: HomeDashboardPresenterImpl
private var giftExpireSplit: List<String> = emptyList()
private var giftExpireDate: List<String> = emptyList()
private var timeUtils: TimeUtils? = null
#NonNull
private var disposable: Disposable? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home_dashboard, container, false)
}
#SuppressLint("WrongConstant")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Initialize
presenter = HomeDashboardPresenterImpl(requireContext(), this)
//Initialize views from activity
activity?.let { itActivity ->
pageTitle = itActivity.findViewById(R.id.toolbarMain_title)
menuIcon = itActivity.findViewById(R.id.toolbarMain_menuIcon)
//Set title
pageTitle?.let { itTitle ->
itTitle.text = getString(R.string.menuHomeDashboard)
}
//Open menu
menuIcon?.let { itMenu ->
itMenu.setOnClickListener {
itActivity.findViewById<AwesomeDrawerLayout>(R.id.homePage_drawerLayout).openDrawer(Gravity.END)
}
}
//Get token
token = GoodPrefs.getInstance().getString(PrefsKey.USER_JWT_TOKEN.name, "")
//User registered
if (GoodPrefs.getInstance().isKeyExists(PrefsKey.USER_JWT_TOKEN.name)) {
menuIcon?.visibility = View.VISIBLE
}
//Set layout
presenter.checkRegisterUser(token)
//Load profile data
if (!isEmptyString(token)) {
presenter.getProfile(token, USER_NOTIF_ID)
}
}
}
MainActivity codes for set fragments into BottomNavBar with NavigationGraph :
private fun setupNavigation() {
val navController = Navigation.findNavController(this, R.id.homePage_fragmentNavHost)
NavigationUI.setupWithNavController(homePage_bottomNavBar, navController)
}
override fun onSupportNavigateUp() = Navigation.findNavController(this, R.id.homePage_fragmentNavHost).navigateUp()
How can i fix this issue?
You can add a layout dummy consisting of a single viewGroup. Then in the onViewCreated method inflate the real layout. For example:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
inflater.inflate(R.layout.layout_dummy, container, false);
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Handler().post {
val layout = flContainer
val child = layoutInflater.inflate(R.layout.fragment_real, null)
layout.removeAllViews()
layout.addView(child)
setupToolbar()
setupWebView()
}
}
layout_dummy.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="#+id/flContainer"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
You issue is almost assuredly caused by your massive XML file. Loading all of those views takes time. You have A LOT of nesting which slows things down.
You have to optimize your layout. Remove things you don't need. Replace as many nested LinearLayouts as you can with ConstraintLayout. Maybe use a RecyclerView if this is intended to be a long, scrolling view.
Hope that helps.

Base Navigation Fragment for multiple Fragments

Is it possible to create a Navigation Fragment to contain my navigation back button click logic.
Multiple Fragment's that have a back button would then be able then inherit from the Navigation Fragment.
I'm new to Kotlin development. As you see below the SigninFragment inflates the view, I'm not sure how to get a reference to the view & back button in a parent Navigation Fragment
class SigninFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_signin, container, false)
// Navigation back button logic
var headerBackButton = view.findViewById<ImageButton>(R.id.headerBackButton)
headerBackButton.setOnClickListener {
val navController = NavHostFragment.findNavController(this#SignInFragment)
navController.navigateUp()
}
return view
}
}
I'm not sure if I got your problem right but could this be the trick?
open class NavigationFragment() : Fragment() {
fun asignNavigationBackClickListener(backButton: View) {
backButton.setOnClickListener {
val navController = NavHostFragment.findNavController(this#NavigationFragment)
navController.navigateUp()
}
}
}
class SigninFragment : NavigationFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_signin, container, false)
asignNavigationBackClickListener(view.findViewById(R.id.headerBackButton))
return view
}
}
I think you can use this code for going back to the previous activity:
headerBackButton.setOnClickListener {
finish()
}

Categories

Resources