summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs
blob: efee571ddfde389c810cf9edba9d33ab9d11a74b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using System.Collections.Specialized;
using System.Linq;
using Android.Content;
using Android.Support.V4.View;
using Android.Views;
using Xamarin.Forms.Internals;
using Object = Java.Lang.Object;

namespace Xamarin.Forms.Platform.Android
{
	internal class CarouselPageAdapter : PagerAdapter, ViewPager.IOnPageChangeListener
	{
		readonly Context _context;
		readonly ViewPager _pager;
		bool _ignoreAndroidSelection;
		CarouselPage _page;

		IElementController ElementController => _page as IElementController;

		public CarouselPageAdapter(ViewPager pager, CarouselPage page, Context context)
		{
			_pager = pager;
			_page = page;
			_context = context;

			page.PagesChanged += OnPagesChanged;
		}

		public override int Count
		{
			get { return _page.Children.Count(); }
		}

		public void OnPageScrolled(int position, float positionOffset, int positionOffsetPixels)
		{
		}

		public void OnPageScrollStateChanged(int state)
		{
		}

		public void OnPageSelected(int position)
		{
			if (_ignoreAndroidSelection)
				return;

			int currentItem = _pager.CurrentItem;
			_page.CurrentPage = currentItem >= 0 && currentItem < ElementController.LogicalChildren.Count ? ElementController.LogicalChildren[currentItem] as ContentPage : null;
		}

		public override void DestroyItem(ViewGroup p0, int p1, Object p2)
		{
			var holder = (ObjectJavaBox<Tuple<ViewGroup, Page, int>>)p2;
			Page destroyedPage = holder.Instance.Item2;

			IVisualElementRenderer renderer = Platform.GetRenderer(destroyedPage);
			renderer.ViewGroup.RemoveFromParent();
			holder.Instance.Item1.RemoveFromParent();
		}

		public override int GetItemPosition(Object item)
		{
			// The int is the current index.
			var holder = (ObjectJavaBox<Tuple<ViewGroup, Page, int>>)item;
			Element parent = holder.Instance.Item2.RealParent;
			if (parent == null)
				return PositionNone;

			// Unfortunately we can't just call CarouselPage.GetIndex, because we need to know
			// if the item has been removed. We could update MultiPage<T> to set removed items' index
			// to -1 to support this if it ever becomes an issue.
			int index = ((CarouselPage)parent).Children.IndexOf(holder.Instance.Item2);
			if (index == -1)
				return PositionNone;

			if (index != holder.Instance.Item3)
			{
				holder.Instance = new Tuple<ViewGroup, Page, int>(holder.Instance.Item1, holder.Instance.Item2, index);
				return index;
			}

			return PositionUnchanged;
		}

		public override Object InstantiateItem(ViewGroup container, int position)
		{
			ContentPage child = _page.Children.ElementAt(position);
			if (Platform.GetRenderer(child) == null)
				Platform.SetRenderer(child, Platform.CreateRenderer(child));

			IVisualElementRenderer renderer = Platform.GetRenderer(child);
			renderer.ViewGroup.RemoveFromParent();

			ViewGroup frame = new PageContainer(_context, renderer);

			container.AddView(frame);

			return new ObjectJavaBox<Tuple<ViewGroup, Page, int>>(new Tuple<ViewGroup, Page, int>(frame, child, position));
		}

		public override bool IsViewFromObject(global::Android.Views.View p0, Object p1)
		{
			var holder = (ObjectJavaBox<Tuple<ViewGroup, Page, int>>)p1;
			ViewGroup frame = holder.Instance.Item1;
			return p0 == frame;
		}

		public void UpdateCurrentItem()
		{
			if (_page.CurrentPage == null)
				throw new InvalidOperationException("CarouselPage has no children.");

			int index = CarouselPage.GetIndex(_page.CurrentPage);
			if (index >= 0 && index < _page.Children.Count)
				_pager.CurrentItem = index;
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && _page != null)
			{
				foreach (Element element in ElementController.LogicalChildren)
				{
					var childPage = element as VisualElement;

					if (childPage == null)
						continue;

					IVisualElementRenderer childPageRenderer = Platform.GetRenderer(childPage);
					if (childPageRenderer != null)
					{
						childPageRenderer.ViewGroup.RemoveFromParent();
						childPageRenderer.Dispose();
						Platform.SetRenderer(childPage, null);
					}
				}
				_page.PagesChanged -= OnPagesChanged;
				_page = null;
			}
			base.Dispose(disposing);
		}

		void OnPagesChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			_ignoreAndroidSelection = true;

			NotifyDataSetChanged();

			_ignoreAndroidSelection = false;

			if (_page.CurrentPage == null)
				return;

			UpdateCurrentItem();
		}
	}
}