I'm trying to design something very similar to this design from the Material Design website.
So basically, I have a list of CardViews that each of them has multiple views that user can swipe between them. (First card on the image)
I started by implementing a simple recyclerview that contains CardView and for each cardview I implemented a FragmentStatePagerAdapter that contains multiple fragments that user can swipe through and it works (kind of). The issue that I'm facing is very similar to this issue Fragment in ViewPager using FragmentPagerAdapter is blank the second time it is viewed where fragments either won't load, or they disappear when you scroll up and down. I've tried every possible fix that people were suggesting and I still can't get this to work.
I was wondering if there is a better way of doing it.
Here is my code (C# - Xamarin)
using System;
using Android.Support.V7.Widget;
using System.Collections.Generic;
using Android.Views;
using Android.Widget;
using System.Security.Cryptography;
using Android.Support.V4.View;
using Android.Support.V4.App;
using Android.Runtime;
using Android.OS;
using Android.Content;
using Android.App;
using Android.Support.V7.App;
using JavaString = Java.Lang.String;
using Android.Util;
using Android.Animation;
using System.ComponentModel.Design.Serialization;
namespace Answers.PortalAppXamarin.Droid
{
public enum MyTestAdapterItemType {
Type1,
Type2,
Type3
};
public class MyTestDataObj
{
public MyTestAdapterItemType type { get; set; }
public string data { get; set; }
}
public class PagerFragmentAdapter : Android.Support.V4.App.FragmentStatePagerAdapter {
public List<MyTestPageFragmentContainer> Tabs { get; set; }
public PagerFragmentAdapter(Android.Support.V4.App.FragmentManager fm) : base(fm) {
}
public override Android.Support.V4.App.Fragment GetItem(int position) {
return Tabs [position].Fragment;
}
public override Java.Lang.ICharSequence GetPageTitleFormatted(int position)
{
return new JavaString(Tabs [position].Title);
}
public override int GetItemPosition (Java.Lang.Object objectValue) {
for (int i = 0; i < Tabs.Count; i++) {
if (Tabs[i].Fragment.Equals (objectValue) ) {
return i;
}
}
return PositionNone;
}
public override int Count {
get {
return Tabs.Count;
}
}
}
public class MyTestPageFragmentContainer {
public string Title { get; set; }
public Android.Support.V4.App.Fragment Fragment { get; set; }
public MyTestPageFragmentContainer(string title, Android.Support.V4.App.Fragment fragment)
{
this.Title = title;
this.Fragment = fragment;
}
}
public class BaseFragment : Android.Support.V4.App.Fragment
{
public static Android.Support.V4.App.Fragment newInstance(int position) {
BaseFragment f = new BaseFragment ();
// Supply num input as an argument.
Bundle args = new Bundle ();
args.PutInt ("num", position);
f.Arguments = (args);
return f;
}
}
public class PageFragment1 : BaseFragment {
View RootView;
public override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
RootView = inflater.Inflate (Resource.Layout.LoadingIndicatorOverlay, container, false);
return RootView;
}
public override void OnResume ()
{
base.OnResume ();
ValueAnimator _animator = ValueAnimator.OfFloat(0, 1);
_animator.SetDuration(2000);
_animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) => {
if (RootView != null) {
RootView.Alpha = (float)e.Animation.AnimatedValue;
}
};
}
}
public class PageFragment2 : BaseFragment {
View RootView;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
RootView = inflater.Inflate(Resource.Layout.MeasureListItem, container, false);
return RootView;
}
public override void OnResume ()
{
base.OnResume ();
ValueAnimator _animator = ValueAnimator.OfFloat(0, 1);
_animator.SetDuration(2000);
_animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) => {
if (RootView != null) {
RootView.Alpha = (float)e.Animation.AnimatedValue;
}
};
}
}
public abstract class BaseCardViewHolder : RecyclerView.ViewHolder
{
public ViewGroup Header;
public ViewGroup Footer;
public TextView TitleTextView;
public Button MoreInfoBtn;
public ViewPager ContentViewPager;
public PagerFragmentAdapter Adapter;
public List<MyTestPageFragmentContainer> Tabs;
public Android.Support.V4.App.FragmentManager fm;
public BaseCardViewHolder(View rootView, Android.Support.V4.App.FragmentManager fm) : base(rootView)
{
Header = rootView.FindViewById<ViewGroup> (Resource.Id.card_view_header);
Footer = rootView.FindViewById<ViewGroup> (Resource.Id.card_view_footer);
ContentViewPager = rootView.FindViewById<ViewPager> (Resource.Id.card_view_content_viewPager);
TitleTextView = Header.FindViewById<TextView> (Resource.Id.card_view_title);
MoreInfoBtn = Footer.FindViewById<Button> (Resource.Id.card_view_moreInfoBtn);
this.fm = fm;
Tabs = setupTabs ();
if (Tabs != null && fm != null) {
Adapter = new PagerFragmentAdapter (fm);
Adapter.Tabs = Tabs;
ContentViewPager.Adapter = Adapter;
}
}
public void RefreshViewPager()
{
ContentViewPager.Adapter.NotifyDataSetChanged ();
}
public abstract List<MyTestPageFragmentContainer> setupTabs ();
}
public class Type1ViewHolder : BaseCardViewHolder
{
public Type1ViewHolder(View v, Android.Support.V4.App.FragmentManager fm) : base(v, fm)
{
}
public override List<MyTestPageFragmentContainer> setupTabs()
{
return new List<MyTestPageFragmentContainer> {
new MyTestPageFragmentContainer ("Tab1", new PageFragment1 ()),
new MyTestPageFragmentContainer ("Tab2", new PageFragment1 ())
};
}
}
public class Type2ViewHolder : BaseCardViewHolder
{
public Type2ViewHolder(View v, Android.Support.V4.App.FragmentManager fm) : base(v, fm)
{
}
public override List<MyTestPageFragmentContainer> setupTabs()
{
return new List<MyTestPageFragmentContainer> {
new MyTestPageFragmentContainer ("Tab1", new PageFragment2 ()),
new MyTestPageFragmentContainer ("Tab2", new PageFragment2 ()),
new MyTestPageFragmentContainer ("Tab1", new PageFragment1 ()),
new MyTestPageFragmentContainer ("Tab2", new PageFragment1 ()),
};
}
}
public class Type3ViewHolder : BaseCardViewHolder
{
public Type3ViewHolder(View v, Android.Support.V4.App.FragmentManager fm) : base(v, fm)
{
}
public override List<MyTestPageFragmentContainer> setupTabs()
{
return new List<MyTestPageFragmentContainer> {
new MyTestPageFragmentContainer ("Tab1", new PageFragment2 ()),
new MyTestPageFragmentContainer ("Tab2", new PageFragment1 ()),
new MyTestPageFragmentContainer ("Tab3", new PageFragment2 ()),
new MyTestPageFragmentContainer ("Tab4", new PageFragment1 ())
};
}
}
public class MyTestRecyclerAdapter : RecyclerView.Adapter
{
public Android.Support.V4.App.FragmentManager FM;
readonly List<MyTestDataObj> myTestDataList = new List<MyTestDataObj>{
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 1"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 2"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 3"},
new MyTestDataObj {type = MyTestAdapterItemType.Type3, data = "Item 4"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 5"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 6"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 7"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 8"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 9"},
new MyTestDataObj {type = MyTestAdapterItemType.Type3, data = "Item 10"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 11"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 12"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 13"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 14"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 15"},
new MyTestDataObj {type = MyTestAdapterItemType.Type3, data = "Item 16"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 17"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 18"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 19"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 20"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 21"},
new MyTestDataObj {type = MyTestAdapterItemType.Type3, data = "Item 22"},
new MyTestDataObj {type = MyTestAdapterItemType.Type1, data = "Item 23"},
new MyTestDataObj {type = MyTestAdapterItemType.Type2, data = "Item 24"},
};
#region implemented abstract members of Adapter
public override void OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
MyTestDataObj item = myTestDataList [position];
switch (GetItemViewType (position)) {
case (int) MyTestAdapterItemType.Type1:
{
((Type1ViewHolder)holder).TitleTextView.Text = item.data;
((Type1ViewHolder)holder).RefreshViewPager ();
break;
}
case (int) MyTestAdapterItemType.Type2:
{
((Type2ViewHolder)holder).TitleTextView.Text = item.data;
((Type2ViewHolder)holder).RefreshViewPager ();
break;
}
case (int) MyTestAdapterItemType.Type3:
{
((Type3ViewHolder)holder).TitleTextView.Text = item.data;
((Type3ViewHolder)holder).RefreshViewPager ();
break;
}
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder (Android.Views.ViewGroup parent, int viewType)
{
LayoutInflater layoutInflater = LayoutInflater.From (parent.Context);
switch (viewType) {
case (int) MyTestAdapterItemType.Type1:
{
return new Type1ViewHolder (layoutInflater.Inflate (Resource.Layout.MyTestCardViewLayout, parent, false), FM);
}
case (int) MyTestAdapterItemType.Type2:
{
return new Type2ViewHolder (layoutInflater.Inflate (Resource.Layout.MyTestCardViewLayout, parent, false), FM);
}
case (int) MyTestAdapterItemType.Type3:
{
return new Type3ViewHolder (layoutInflater.Inflate (Resource.Layout.MyTestCardViewLayout, parent, false), FM);
}
}
return null;
}
public override int ItemCount {
get {
return myTestDataList.Count;
}
}
public override int GetItemViewType (int position)
{
return (int)myTestDataList [position].type;
}
#endregion
}
}
Here is the Demo:
Note: I'm sure that its possible, since the Google Analytics app for both iOS and Android is having the exact same design that I'm looking for.
I would appreciate any help, Thanks