Kotlin Viewpager2 access from child fragment - android

I have 3 fragments. (Parent Fragment, A Fragment , B Fragment). The parent fragment has a viewpager, and the viewpager allows switching between fragments A and B. I want to return to fragment a with the button in fragment b. But viewpager is in parent fragment. How can I do that?
This is my Parent Fragment:
class ParentFragment : Fragment() {
private lateinit var binding: FragmentLoginRegisterBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = FragmentLoginRegisterBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setAdapter()
}
fun setAdapter(activity: MainActivity) {
val tabArrayList = arrayOf("Login", "Register")
val adapter = TablayoutAdapter(requireActivity(), tabArrayList.size)
binding.apply {
viewPager.adapter = adapter
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = tabArrayList[position]
}.attach()
}
}
}
This is my View Pager:
class TablayoutAdapter(fm : FragmentActivity, var totalTabs : Int) : FragmentStateAdapter(fm) {
override fun getItemCount(): Int {
return totalTabs
}
override fun createFragment(position: Int): Fragment {
return when(position){
0->{
FragmentA()
}
1->{
FragmentB()
}
else->{
FragmentA()
}
}
}
}
This is my A Fragment:
class FragmentA() : Fragment(){
private lateinit var binding : FragmentABinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentA.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
This is my B Fragment:
class FragmentB() : Fragment(){
private lateinit var binding : FragmentBBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentRegisterBinding.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btn.setOnClickListener{
//--> Goto ViewPager Item 0
}
}
}

You need to first find out tab layout's reference.
binding.btn.setOnClickListener{
tabs = activity.findViewById(R.id.myTabLayout)
tabs.getTabAt(0).select()
}
Write this in fragment B inside onClickListener()

Related

Livedata not triggering in fragment after configuration change

After configuration change, the observer is not triggered anymore in my fragment. I really can't understand what I'm missing in the code (it is using latest androidx support libraries).
Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
FragmentManager fragMgr = getSupportFragmentManager();
itemListFragment = (ItemListFragment) fragMgr.findFragmentById(R.id.container_fragment_items);
if (itemListFragment == null) {
itemListFragment = ItemListFragment.newInstance();
fragMgr.beginTransaction()
.add(R.id.container_fragment_items, itemListFragment)
.commit();
}
...
Fragment:
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_item_list, container, false);
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
mainViewModel.getAllItems().observe(getViewLifecycleOwner(), items -> adapter.setItems(items));
...
MainViewModel:
public class MainViewModel extends AndroidViewModel {
private MainRepository mMainRepository;
private LiveData<List<Item>> mAllItems;
public MainViewModel(Application application) {
super(application);
mMainRepository = new MainRepository(application);
mAllItems = mMainRepository.getAll();
}
public LiveData<List<Item>> getAllItems() {
return mAllItems;
}
...

If roll up app and back again one Fragment mix with next fragment in ViewPager

I follow this tutorial https://tausiq.wordpress.com/2014/06/06/android-multiple-fragments-stack-in-each-viewpager-tab/
But there exist some bug - if we are on the Fragment A2 screen and press button "Home" then back to app - I see Fragment A1 and Fragment A2, how to fix it???
My code for example on Kotlin:
public class MyViewPagerAdapter extends FragmentPagerAdapter {
private SparseArray<Fragment> registeredFragments = new SparseArray<>();
public MyViewPagerAdapter( FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
final Fragment result;
switch (position) {
case 0:
result = new CamerasFragment();
break;
case 1:
result = new SettingsFragment();
break;
default:
result = null;
break;
}
return result;
}
#Override
public int getCount() {
return 2;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
class MainActivity : AppCompatActivity() {
private lateinit var carouselFragment: CarouselFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
initScreen()
} else {
carouselFragment = supportFragmentManager.fragments[0] as CarouselFragment
}
}
private fun initScreen() {
carouselFragment = CarouselFragment()
val fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.replace(R.id.container, carouselFragment)
.commit()
}
override fun onBackPressed() {
if (!carouselFragment.onBackPressed()) {
super.onBackPressed()
} else {
// carousel handled the back pressed task
// do not call super
}
}
fun onAddContract(view: View) {
showToast("Will open contract adding screen", this)
}
}
class CarouselFragment : Fragment() {
lateinit var navigation: BottomNavigationView
lateinit var mainViewPager: ViewPager
private var adapter: MyViewPagerAdapter? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val rootView = inflater!!.inflate(R.layout.fragment_carousel, container, false)
navigation = rootView.findViewById(R.id.navigation)
mainViewPager = rootView.findViewById(R.id.mainViewPager)
return rootView
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupMainViewPager()
}
fun onBackPressed(): Boolean {
val currentFragment = adapter!!.getRegisteredFragment(mainViewPager.currentItem) as OnBackPressListener
return currentFragment.onBackPressed()
// this Fragment couldn't handle the onBackPressed call
}
private fun setupMainViewPager() {
// Note that we are passing childFragmentManager, not FragmentManager
adapter = MyViewPagerAdapter(childFragmentManager)
mainViewPager.adapter = adapter
mainViewPager.offscreenPageLimit = 2
navigation.itemIconTintList = null
navigation.menu.getItem(0).setIcon(R.drawable.ic_camera_active)
navigation.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener)
mainViewPager.addOnPageChangeListener(onViewPagerChangeListener)
}
private val onNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.tabbar_my_camera -> {
mainViewPager.currentItem = 0
navigation.menu.getItem(0).setIcon(R.drawable.ic_camera_active)
navigation.menu.getItem(1).setIcon(R.drawable.ic_settings)
return#OnNavigationItemSelectedListener true
}
R.id.tabbar_settings -> {
mainViewPager.currentItem = 1
navigation.menu.getItem(0).setIcon(R.drawable.ic_camera)
navigation.menu.getItem(1).setIcon(R.drawable.ic_settings_active)
return#OnNavigationItemSelectedListener true
}
}
false
}
private val onViewPagerChangeListener = (object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
mainViewPager.adapter
navigation.menu.getItem(position).isChecked = true
if (position == 0) {
mainViewPager.currentItem = 0
navigation.menu.getItem(0).setIcon(R.drawable.ic_camera_active)
navigation.menu.getItem(1).setIcon(R.drawable.ic_settings)
} else {
mainViewPager.currentItem = 1
navigation.menu.getItem(0).setIcon(R.drawable.ic_camera)
navigation.menu.getItem(1).setIcon(R.drawable.ic_settings_active)
}
}
override fun onPageScrollStateChanged(state: Int) {
}
})
}
public class RootFragment extends Fragment implements OnBackPressListener {
#Override
public boolean onBackPressed() {
return new BackPressImpl(this).onBackPressed();
}
}
class CamerasFragment : RootFragment(), CamerasContract.View, CamerasAdapter.Listener, SwipeRefreshLayout.OnRefreshListener {
...
override fun onItemClick(list: ContractData) {
val videoFragment = VideoFragment().newInstance(list.id)
val transaction = childFragmentManager.beginTransaction()
transaction.addToBackStack(null) // Store the Fragment in stack
transaction.replace(R.id.cameraFrame, videoFragment) // as the reference to replace fragment
transaction.commitAllowingStateLoss()
}
...
}
class VideoFragment : RootFragment(), View.OnClickListener, VideoContract.View {
...
fun newInstance(idContract: Int?): VideoFragment {
val bundle = Bundle()
bundle.putInt(ID_CONTRACT, idContract!!)
val fragment = VideoFragment()
fragment.arguments = bundle
return fragment
}
...
}
In my app I open VideoFragment from CamerasFragment and press button "Home" then back to app - I see CamerasFragment is at the VideoFragment, why???
I myself found the answer to my question - in class CamerasFragment I added check use backStackEntryCount:
override fun onResume() {
val fragmentCount = childFragmentManager.backStackEntryCount
if (fragmentCount >=1) {
makeInvisibleScreen()
} else {
makeVisibleScreen()
}
super.onResume()
}
I think it's all clear

MvxCachingFragmentStatePagerAdapter pass parameter to viewmodel

How can i pass parameter to my viewmodel when i build a List of Fragment for a viewpager ?
I try to use the "parametervaluesobject" in "MvxCachingFragmentStatePagerAdapter.FragmentInfo" but that doesn't seem to work.
[MvxFragment(typeof(MainViewModel), Resource.Id.content_frame, true)]
[Register("mvvmcrosslearning.droid.fragments.DateFragment")]
public class DateFragment : BaseFragment<DateViewModel>
{
protected override int FragmentId => Resource.Layout.fragment_date;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
var viewPager = view.FindViewById<ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxCachingFragmentStatePagerAdapter.FragmentInfo>();
for (int i = 0; i < 3; i++)
fragments.Add(new MvxCachingFragmentStatePagerAdapter.FragmentInfo($"Date {i}",
typeof(RecyclerViewFragment), typeof(RecyclerViewModel), new Device() { Date = $"Date {i}" }));
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(Activity,ChildFragmentManager,fragments);
viewPager.OffscreenPageLimit = 1;
}
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
return view;
}
}
Thanks you York Shen. I found how to get the data in my ViewModel :
Just override that method in the RecyclerViewModel's ViewModel:
protected override void InitFromBundle(IMvxBundle parameters)
{
base.InitFromBundle(parameters);
Device = new Device()
{
Date = parameters.Data["Date"]
};
RaisePropertyChanged(() => Device);
}

Display layout in fragment on main activity xamarin

I am not able to display layout on class SecondFragment : Fragment
MAIN ACTIVITY
$ [Activity (Label = "project", Theme = "#style/Tab")]
public class TabActivity : Activity
{
ProductDB dbHelper;
ICursor cursor;
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.MainTab);
dbHelper = new ProductDB(this);
cursor = dbHelper.ReadableDatabase.RawQuery ("select * from movie", null);
StartManagingCursor (cursor);
this.ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab ("Products", new FirstFragment(this, cursor));
AddTab ("User Profile", new SecondFragment());
AddTab("User Order", new ThirdFragment());
if (savedInstanceState != null)
this.ActionBar.SelectTab(this.ActionBar.GetTabAt(savedInstanceState.GetInt("tab")));
}
void AddTab (string tabText, Fragment view)
{
var tab = this.ActionBar.NewTab ();
tab.SetText (tabText);
tab.TabSelected += delegate(object sender, ActionBar.TabEventArgs ab)
{
var fragment = this.FragmentManager.FindFragmentById(Resource.Id.frameLayout1);
if (fragment != null)
ab.FragmentTransaction.Remove(fragment);
ab.FragmentTransaction.Add (Resource.Id.frameLayout1, view); };
tab.TabUnselected += delegate(object sender, ActionBar.TabEventArgs ab) {
ab.FragmentTransaction.Remove(view); };
this.ActionBar.AddTab (tab);
}
protected override void OnDestroy ()
{
StopManagingCursor (cursor);
cursor.Close ();
base.OnDestroy ();
}
class FirstFragment: Fragment
{
ICursor cursor;
ListView listView;
Activity context;
public FirstFragment(Activity context, ICursor cursor) {
this.cursor = cursor;
this.context = context;
}
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var view = inflater.Inflate (Resource.Layout.Tab1, container, false);
listView = view.FindViewById<ListView> (Resource.Id.mylist);
listView.Adapter = new ProductAdapter (context, cursor);
listView.ItemClick += OnItemListClick;
return view;
}
protected void OnItemListClick (object sender, AdapterView.ItemClickEventArgs ab)
{
var curs = (ICursor)listView.Adapter.GetItem (ab.Position);
var movieName = curs.GetString (1);
Android.Widget.Toast.MakeText (context, movieName, Android.Widget.ToastLength.Short).Show();
}
}
class SecondFragment : Fragment
{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate(R.layout.your_fragment, container, false);
return view;
}
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.article_view, container, false);
// base.OnCreateView(inflater, container, savedInstanceState);
// var view = inflater.Inflate(Resource.Layout.User, container, false);
// var layout = view.FindViewById<LinearLayout>(Resource.Id.linearLayoutmargin1);
// return view;
}
class ThirdFragment : Fragment
After observing above code, there might be some issue in onCreateView of SecondFragment, you missed below line,
base.OnCreateView (inflater, container, savedInstanceState);
Confirm and let me know whether working or not?
:)GlbMP

Custom MvxAdapter - Override Methods not getting called

I have created an MvxListView with a custom adapter, but none of the adapter methods are getting called. It is worth mentioning the list is in a fragment. What am I doing wrong?
Adapter:
public class WishlistAdapter : MvxAdapter
{
public WishlistAdapter(Context context, IMvxAndroidBindingContext bindingContext)
: base(context, bindingContext)
{
}
protected override View GetBindableView(View convertView, object source, int templateId)
{
if (((Wish)source).IsOwner == false)
{
if (((Wish)source).IsBought)
{
templateId = Resource.Layout.listitem_wishbought;
}
}
return base.GetBindableView(convertView, source, templateId);
}
}
View:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.WishlistView, null);
var list = view.FindViewById<ListView>(Resource.Id.WishlistView_ListWishes);
list.Adapter = new WishlistAdapter(Activity, (MvxAndroidBindingContext)BindingContext);
return view;
}
ViewModel:
public ObservableCollection<Wish> Wishes
{
get
{
return _Wishes;
}
set
{
_Wishes = value;
RaisePropertyChanged("Wishes");
}
}
FIXED:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.WishlistView, null);
var list = view.FindViewById<**MvxListView**>(Resource.Id.WishlistView_ListWishes);
list.Adapter = new WishlistAdapter(Activity, (MvxAndroidBindingContext)BindingContext);
return view;
}

Categories

Resources