public override AView GetView(int position, AView convertView, ViewGroup parent)
        {
            Cell cell = null;

            Performance.Start(out string reference);

            ListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;
            var nextCellIsHeader = false;

            if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
            {
                if (_listView.IsGroupingEnabled)
                {
                    List <Cell> cells = GetCellsFromPosition(position, 2);
                    if (cells.Count > 0)
                    {
                        cell = cells[0];
                    }

                    if (cells.Count == 2)
                    {
                        nextCellIsHeader = cells[1].GetIsGroupHeader <ItemsView <Cell>, Cell>();
                    }
                }

                if (cell == null)
                {
                    cell = GetCellForPosition(position);
                    if (cell == null)
                    {
                        return(new AView(_context));
                    }
                }
            }

            var cellIsBeingReused = false;
            var layout            = convertView as ConditionalFocusLayout;

            if (layout != null)
            {
                cellIsBeingReused = true;
                convertView       = layout.GetChildAt(0);
            }
            else
            {
                layout = new ConditionalFocusLayout(_context)
                {
                    Orientation = Orientation.Vertical
                };
                _layoutsCreated.Add(layout);
            }

            if (((cachingStrategy & ListViewCachingStrategy.RecycleElement) != 0) && convertView != null)
            {
                var boxedCell = convertView as INativeElementView;
                if (boxedCell == null)
                {
                    throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
                }
                cell = (Cell)boxedCell.Element;
        void DisposeOfConditionalFocusLayout(ConditionalFocusLayout layout)
        {
            var renderedView = layout?.GetChildAt(0);

            var element = (renderedView as INativeElementView)?.Element;
            var view    = (element as ViewCell)?.View;

            if (view != null)
            {
                var renderer = Platform.GetRenderer(view);

                if (renderer == renderedView)
                {
                    element.ClearValue(Platform.RendererProperty);
                }

                renderer?.Dispose();
                renderer = null;
            }

            renderedView?.Dispose();
            renderedView = null;
        }
Esempio n. 3
0
        void UpdateSeparatorVisibility(Cell cell, bool cellIsBeingReused, bool isHeader, bool nextCellIsHeader, ConditionalFocusLayout layout, out AView bline)
        {
            bline = null;
            if (cellIsBeingReused)
            {
                return;
            }
            var makeBline = _listView.SeparatorVisibility == SeparatorVisibility.Default || isHeader && !nextCellIsHeader;

            if (makeBline)
            {
                bline = new AView(_context)
                {
                    LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1)
                };
                layout.AddView(bline);
            }
            else if (layout.ChildCount > 1)
            {
                layout.RemoveViewAt(1);
            }
        }
Esempio n. 4
0
        public override AView GetView(int position, AView convertView, ViewGroup parent)
        {
            Cell cell = null;

            Performance.Start();

            ListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;
            var nextCellIsHeader = false;

            if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
            {
                if (_listView.IsGroupingEnabled)
                {
                    List <Cell> cells = GetCellsFromPosition(position, 2);
                    if (cells.Count > 0)
                    {
                        cell = cells[0];
                    }

                    if (cells.Count == 2)
                    {
                        nextCellIsHeader = cells[1].GetIsGroupHeader <ItemsView <Cell>, Cell>();
                    }
                }

                if (cell == null)
                {
                    cell = GetCellForPosition(position);
                    if (cell == null)
                    {
                        return(new AView(_context));
                    }
                }
            }

            var cellIsBeingReused = false;
            var layout            = convertView as ConditionalFocusLayout;

            if (layout != null)
            {
                cellIsBeingReused = true;
                convertView       = layout.GetChildAt(0);
            }
            else
            {
                layout = new ConditionalFocusLayout(_context)
                {
                    Orientation = Orientation.Vertical
                }
            };

            if (cachingStrategy == ListViewCachingStrategy.RecycleElement && convertView != null)
            {
                var boxedCell = convertView as INativeElementView;
                if (boxedCell == null)
                {
                    throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
                }
                cell = (Cell)boxedCell.Element;

                // We are going to re-set the Platform here because in some cases (headers mostly) its possible this is unset and
                // when the binding context gets updated the measure passes will all fail. By applying this here the Update call
                // further down will result in correct layouts.
                cell.Platform = _listView.Platform;

                ICellController cellController = cell;
                cellController.SendDisappearing();

                int row            = position;
                var group          = 0;
                var templatedItems = TemplatedItemsView.TemplatedItems;
                if (_listView.IsGroupingEnabled)
                {
                    group = templatedItems.GetGroupIndexFromGlobal(position, out row);
                }

                var templatedList = templatedItems.GetGroup(group);

                if (_listView.IsGroupingEnabled)
                {
                    if (row == 0)
                    {
                        templatedList.UpdateHeader(cell, group);
                    }
                    else
                    {
                        templatedList.UpdateContent(cell, row - 1);
                    }
                }
                else
                {
                    templatedList.UpdateContent(cell, row);
                }

                cellController.SendAppearing();

                if (cell.BindingContext == ActionModeObject)
                {
                    ActionModeContext = cell;
                    ContextView       = layout;
                }

                if (ReferenceEquals(_listView.SelectedItem, cell.BindingContext))
                {
                    Select(_listView.IsGroupingEnabled ? row - 1 : row, layout);
                }
                else if (cell.BindingContext == ActionModeObject)
                {
                    SetSelectedBackground(layout, true);
                }
                else
                {
                    UnsetSelectedBackground(layout);
                }

                Performance.Stop();
                return(layout);
            }

            AView view = CellFactory.GetCell(cell, convertView, parent, _context, _listView);

            Performance.Start("AddView");

            if (cellIsBeingReused)
            {
                if (convertView != view)
                {
                    layout.RemoveViewAt(0);
                    layout.AddView(view, 0);
                }
            }
            else
            {
                layout.AddView(view, 0);
            }

            Performance.Stop("AddView");

            bool isHeader = cell.GetIsGroupHeader <ItemsView <Cell>, Cell>();

            AView bline;

            UpdateSeparatorVisibility(cell, cellIsBeingReused, isHeader, nextCellIsHeader, layout, out bline);

            UpdateSeparatorColor(isHeader, bline);

            if ((bool)cell.GetValue(IsSelectedProperty))
            {
                Select(position, layout);
            }
            else
            {
                UnsetSelectedBackground(layout);
            }

            layout.ApplyTouchListenersToSpecialCells(cell);

            Performance.Stop();

            return(layout);
        }
        public override AView GetView(int position, AView convertView, ViewGroup parent)
        {
            Cell cell = null;

            Performance.Start();

            ListViewCachingStrategy cachingStrategy = _listView.CachingStrategy;
            var nextCellIsHeader = false;

            if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
            {
                if (_listView.IsGroupingEnabled)
                {
                    List <Cell> cells = GetCellsFromPosition(position, 2);
                    if (cells.Count > 0)
                    {
                        cell = cells[0];
                    }

                    if (cells.Count == 2)
                    {
                        nextCellIsHeader = TemplatedItemsList <ItemsView <Cell>, Cell> .GetIsGroupHeader(cells[1]);
                    }
                }

                if (cell == null)
                {
                    cell = GetCellForPosition(position);
                    if (cell == null)
                    {
                        return(new AView(_context));
                    }
                }
            }

            var makeBline = true;
            var layout    = convertView as ConditionalFocusLayout;

            if (layout != null)
            {
                makeBline   = false;
                convertView = layout.GetChildAt(0);
            }
            else
            {
                layout = new ConditionalFocusLayout(_context)
                {
                    Orientation = Orientation.Vertical
                }
            };

            if (cachingStrategy == ListViewCachingStrategy.RecycleElement && convertView != null)
            {
                var boxedCell = (INativeElementView)convertView;
                if (boxedCell == null)
                {
                    throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
                }
                cell = (Cell)boxedCell.Element;

                if (ActionModeContext == cell)
                {
                    // This appears to never happen, the theory is android keeps all views alive that are currently selected for long-press (preventing them from being recycled).
                    // This is convenient since we wont have to worry about the user scrolling the cell offscreen and us losing our context actions.
                    ActionModeContext = null;
                    ContextView       = null;
                }
                // We are going to re-set the Platform here because in some cases (headers mostly) its possible this is unset and
                // when the binding context gets updated the measure passes will all fail. By applying this hear the Update call
                // further down will result in correct layouts.
                cell.Platform = _listView.Platform;

                cell.SendDisappearing();

                int row   = position;
                var group = 0;
                if (_listView.IsGroupingEnabled)
                {
                    group = _listView.TemplatedItems.GetGroupIndexFromGlobal(position, out row);
                }

                TemplatedItemsList <ItemsView <Cell>, Cell> templatedList = _listView.TemplatedItems.GetGroup(group);

                if (_listView.IsGroupingEnabled)
                {
                    if (row == 0)
                    {
                        templatedList.UpdateHeader(cell, group);
                    }
                    else
                    {
                        templatedList.UpdateContent(cell, row - 1);
                    }
                }
                else
                {
                    templatedList.UpdateContent(cell, row);
                }

                cell.SendAppearing();

                if (cell.BindingContext == ActionModeObject)
                {
                    ActionModeContext = cell;
                    ContextView       = layout;
                }

                if (ReferenceEquals(_listView.SelectedItem, cell.BindingContext))
                {
                    Select(_listView.IsGroupingEnabled ? row - 1 : row, layout);
                }
                else if (cell.BindingContext == ActionModeObject)
                {
                    SetSelectedBackground(layout, true);
                }
                else
                {
                    UnsetSelectedBackground(layout);
                }

                Performance.Stop();
                return(layout);
            }

            AView view = CellFactory.GetCell(cell, convertView, parent, _context, _listView);

            Performance.Start("AddView");

            if (!makeBline)
            {
                if (convertView != view)
                {
                    layout.RemoveViewAt(0);
                    layout.AddView(view, 0);
                }
            }
            else
            {
                layout.AddView(view, 0);
            }

            Performance.Stop("AddView");

            AView bline;

            if (makeBline)
            {
                bline = new AView(_context)
                {
                    LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1)
                };

                layout.AddView(bline);
            }
            else
            {
                bline = layout.GetChildAt(1);
            }

            bool isHeader = TemplatedItemsList <ItemsView <Cell>, Cell> .GetIsGroupHeader(cell);

            Color separatorColor = _listView.SeparatorColor;

            if (nextCellIsHeader || _listView.SeparatorVisibility == SeparatorVisibility.None)
            {
                bline.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
            }
            else if (isHeader || !separatorColor.IsDefault)
            {
                bline.SetBackgroundColor(separatorColor.ToAndroid(Color.Accent));
            }
            else
            {
                if (s_dividerHorizontalDarkId == int.MinValue)
                {
                    using (var value = new TypedValue())
                    {
                        int id = global::Android.Resource.Drawable.DividerHorizontalDark;
                        if (_context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ListDivider, value, true))
                        {
                            id = value.ResourceId;
                        }
                        else if (_context.Theme.ResolveAttribute(global::Android.Resource.Attribute.Divider, value, true))
                        {
                            id = value.ResourceId;
                        }

                        s_dividerHorizontalDarkId = id;
                    }
                }

                bline.SetBackgroundResource(s_dividerHorizontalDarkId);
            }

            if ((bool)cell.GetValue(IsSelectedProperty))
            {
                Select(position, layout);
            }
            else
            {
                UnsetSelectedBackground(layout);
            }

            layout.ApplyTouchListenersToSpecialCells(cell);

            Performance.Stop();

            return(layout);
        }
        public override AView GetView(int position, AView convertView, ViewGroup parent)
        {
            Cell cell = null;

            Performance.Start(out string reference);

            ListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;
            var nextCellIsHeader = false;

            if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
            {
                if (_listView.IsGroupingEnabled)
                {
                    List <Cell> cells = GetCellsFromPosition(position, 2);
                    if (cells.Count > 0)
                    {
                        cell = cells[0];
                    }

                    if (cells.Count == 2)
                    {
                        nextCellIsHeader = cells[1].GetIsGroupHeader <ItemsView <Cell>, Cell>();
                    }
                }

                if (cell == null)
                {
                    cell = GetCellForPosition(position);
                    if (cell == null)
                    {
                        return(new AView(_context));
                    }
                }
            }

            var cellIsBeingReused = false;
            var layout            = convertView as ConditionalFocusLayout;

            if (layout != null)
            {
                cellIsBeingReused = true;
                convertView       = layout.GetChildAt(0);
            }
            else
            {
                layout = new ConditionalFocusLayout(_context)
                {
                    Orientation = Orientation.Vertical
                };
                _layoutsCreated.Add(layout);
            }

            if (((cachingStrategy & ListViewCachingStrategy.RecycleElement) != 0) && convertView != null)
            {
                var boxedCell = convertView as INativeElementView;
                if (boxedCell == null)
                {
                    throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
                }
                cell = (Cell)boxedCell.Element;

#pragma warning disable CS0618 // Type or member is obsolete
                // The Platform property is no longer necessary, but we have to set it because some third-party
                // library might still be retrieving it and using it
                cell.Platform = _listView.Platform;
#pragma warning restore CS0618 // Type or member is obsolete

                ICellController cellController = cell;
                cellController.SendDisappearing();

                int row            = position;
                var group          = 0;
                var templatedItems = TemplatedItemsView.TemplatedItems;
                if (_listView.IsGroupingEnabled)
                {
                    group = templatedItems.GetGroupIndexFromGlobal(position, out row);
                }

                var templatedList = templatedItems.GetGroup(group);

                if (_listView.IsGroupingEnabled)
                {
                    if (row == 0)
                    {
                        templatedList.UpdateHeader(cell, group);
                    }
                    else
                    {
                        templatedList.UpdateContent(cell, row - 1);
                    }
                }
                else
                {
                    templatedList.UpdateContent(cell, row);
                }

                cellController.SendAppearing();

                if (cell.BindingContext == ActionModeObject)
                {
                    ActionModeContext = cell;
                    ContextView       = layout;
                }

                if (ReferenceEquals(_listView.SelectedItem, cell.BindingContext))
                {
                    Select(_listView.IsGroupingEnabled ? row - 1 : row, layout);
                }
                else if (cell.BindingContext == ActionModeObject)
                {
                    SetSelectedBackground(layout, true);
                }
                else
                {
                    UnsetSelectedBackground(layout);
                }

                Performance.Stop(reference);
                return(layout);
            }

            AView view = CellFactory.GetCell(cell, convertView, parent, _context, _listView);

            Performance.Start(reference, "AddView");

            if (cellIsBeingReused)
            {
                if (convertView != view)
                {
                    layout.RemoveViewAt(0);
                    layout.AddView(view, 0);
                }
            }
            else
            {
                layout.AddView(view, 0);
            }

            Performance.Stop(reference, "AddView");

            bool isHeader = cell.GetIsGroupHeader <ItemsView <Cell>, Cell>();

            AView bline;

            UpdateSeparatorVisibility(cell, cellIsBeingReused, isHeader, nextCellIsHeader, layout, out bline);

            UpdateSeparatorColor(isHeader, bline);

            if ((bool)cell.GetValue(IsSelectedProperty))
            {
                Select(position, layout);
            }
            else
            {
                UnsetSelectedBackground(layout);
            }

            layout.ApplyTouchListenersToSpecialCells(cell);

            Performance.Stop(reference);

            return(layout);
        }
Esempio n. 7
0
        public override AView GetView(int position, AView convertView, ViewGroup parent)
        {
            bool isHeader, nextIsHeader;
            Cell item = GetCellForPosition(position, out isHeader, out nextIsHeader);

            if (item == null)
            {
                return(new AView(Context));
            }

            var makeBline = true;
            var layout    = convertView as ConditionalFocusLayout;

            if (layout != null)
            {
                makeBline   = false;
                convertView = layout.GetChildAt(0);
            }
            else
            {
                layout = new ConditionalFocusLayout(Context)
                {
                    Orientation = Orientation.Vertical
                }
            };

            AView aview = CellFactory.GetCell(item, convertView, parent, Context, _view);

            if (!makeBline)
            {
                if (convertView != aview)
                {
                    layout.RemoveViewAt(0);
                    layout.AddView(aview, 0);
                }
            }
            else
            {
                layout.AddView(aview, 0);
            }

            AView bline;

            if (makeBline)
            {
                bline = new AView(Context)
                {
                    LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1)
                };

                layout.AddView(bline);
            }
            else
            {
                bline = layout.GetChildAt(1);
            }

            if (isHeader)
            {
                bline.SetBackgroundColor(Color.Accent.ToAndroid());
            }
            else if (nextIsHeader)
            {
                bline.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
            }
            else
            {
                using (var value = new TypedValue())
                {
                    int id = global::Android.Resource.Drawable.DividerHorizontalDark;
                    if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ListDivider, value, true))
                    {
                        id = value.ResourceId;
                    }
                    else if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.Divider, value, true))
                    {
                        id = value.ResourceId;
                    }

                    bline.SetBackgroundResource(id);
                }
            }

            layout.ApplyTouchListenersToSpecialCells(item);

            if (_restoreFocus == item)
            {
                if (!aview.HasFocus)
                {
                    aview.RequestFocus();
                }

                _restoreFocus = null;
            }
            else if (aview.HasFocus)
            {
                aview.ClearFocus();
            }

            return(layout);
        }
Esempio n. 8
0
		public override AView GetView(int position, AView convertView, ViewGroup parent)
		{
			Cell cell = null;

			Performance.Start();

			ListViewCachingStrategy cachingStrategy = _listView.CachingStrategy;
			var nextCellIsHeader = false;
			if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
			{
				if (_listView.IsGroupingEnabled)
				{
					List<Cell> cells = GetCellsFromPosition(position, 2);
					if (cells.Count > 0)
						cell = cells[0];

					if (cells.Count == 2)
						nextCellIsHeader = TemplatedItemsList<ItemsView<Cell>, Cell>.GetIsGroupHeader(cells[1]);
				}

				if (cell == null)
				{
					cell = GetCellForPosition(position);
					if (cell == null)
						return new AView(_context);
				}
			}

			var makeBline = true;
			var layout = convertView as ConditionalFocusLayout;
			if (layout != null)
			{
				makeBline = false;
				convertView = layout.GetChildAt(0);
			}
			else
				layout = new ConditionalFocusLayout(_context) { Orientation = Orientation.Vertical };

			if (cachingStrategy == ListViewCachingStrategy.RecycleElement && convertView != null)
			{
				var boxedCell = (INativeElementView)convertView;
				if (boxedCell == null)
				{
					throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
				}
				cell = (Cell)boxedCell.Element;

				if (ActionModeContext == cell)
				{
					// This appears to never happen, the theory is android keeps all views alive that are currently selected for long-press (preventing them from being recycled).
					// This is convenient since we wont have to worry about the user scrolling the cell offscreen and us losing our context actions.
					ActionModeContext = null;
					ContextView = null;
				}
				// We are going to re-set the Platform here because in some cases (headers mostly) its possible this is unset and
				// when the binding context gets updated the measure passes will all fail. By applying this hear the Update call
				// further down will result in correct layouts.
				cell.Platform = _listView.Platform;

				cell.SendDisappearing();

				int row = position;
				var group = 0;
				if (_listView.IsGroupingEnabled)
					group = _listView.TemplatedItems.GetGroupIndexFromGlobal(position, out row);

				TemplatedItemsList<ItemsView<Cell>, Cell> templatedList = _listView.TemplatedItems.GetGroup(group);

				if (_listView.IsGroupingEnabled)
				{
					if (row == 0)
						templatedList.UpdateHeader(cell, group);
					else
						templatedList.UpdateContent(cell, row - 1);
				}
				else
					templatedList.UpdateContent(cell, row);

				cell.SendAppearing();

				if (cell.BindingContext == ActionModeObject)
				{
					ActionModeContext = cell;
					ContextView = layout;
				}

				if (ReferenceEquals(_listView.SelectedItem, cell.BindingContext))
					Select(_listView.IsGroupingEnabled ? row - 1 : row, layout);
				else if (cell.BindingContext == ActionModeObject)
					SetSelectedBackground(layout, true);
				else
					UnsetSelectedBackground(layout);

				Performance.Stop();
				return layout;
			}

			AView view = CellFactory.GetCell(cell, convertView, parent, _context, _listView);

			Performance.Start("AddView");

			if (!makeBline)
			{
				if (convertView != view)
				{
					layout.RemoveViewAt(0);
					layout.AddView(view, 0);
				}
			}
			else
				layout.AddView(view, 0);

			Performance.Stop("AddView");

			AView bline;
			if (makeBline)
			{
				bline = new AView(_context) { LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1) };

				layout.AddView(bline);
			}
			else
				bline = layout.GetChildAt(1);

			bool isHeader = TemplatedItemsList<ItemsView<Cell>, Cell>.GetIsGroupHeader(cell);

			Color separatorColor = _listView.SeparatorColor;

			if (nextCellIsHeader || _listView.SeparatorVisibility == SeparatorVisibility.None)
				bline.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
			else if (isHeader || !separatorColor.IsDefault)
				bline.SetBackgroundColor(separatorColor.ToAndroid(Color.Accent));
			else
			{
				if (s_dividerHorizontalDarkId == int.MinValue)
				{
					using (var value = new TypedValue())
					{
						int id = global::Android.Resource.Drawable.DividerHorizontalDark;
						if (_context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ListDivider, value, true))
							id = value.ResourceId;
						else if (_context.Theme.ResolveAttribute(global::Android.Resource.Attribute.Divider, value, true))
							id = value.ResourceId;

						s_dividerHorizontalDarkId = id;
					}
				}

				bline.SetBackgroundResource(s_dividerHorizontalDarkId);
			}

			if ((bool)cell.GetValue(IsSelectedProperty))
				Select(position, layout);
			else
				UnsetSelectedBackground(layout);

			layout.ApplyTouchListenersToSpecialCells(cell);

			Performance.Stop();

			return layout;
		}
Esempio n. 9
0
		void UpdateSeparatorVisibility(Cell cell, bool cellIsBeingReused, bool isHeader, bool nextCellIsHeader, ConditionalFocusLayout layout, out AView bline)
		{
			bline = null;
			if (cellIsBeingReused)
				return;
			var makeBline = _listView.SeparatorVisibility == SeparatorVisibility.Default || isHeader && !nextCellIsHeader;
			if (makeBline)
			{
				bline = new AView(_context) { LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1) };
				layout.AddView(bline);
			}
			else if (layout.ChildCount > 1)
			{
				layout.RemoveViewAt(1);
			}
		}
Esempio n. 10
0
		public override AView GetView(int position, AView convertView, ViewGroup parent)
		{
			Cell cell = null;

			Performance.Start();

			ListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;
			var nextCellIsHeader = false;
			if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
			{
				if (_listView.IsGroupingEnabled)
				{
					List<Cell> cells = GetCellsFromPosition(position, 2);
					if (cells.Count > 0)
						cell = cells[0];

					if (cells.Count == 2)
						nextCellIsHeader = cells[1].GetIsGroupHeader<ItemsView<Cell>, Cell>();
				}

				if (cell == null)
				{
					cell = GetCellForPosition(position);
					if (cell == null)
						return new AView(_context);
				}
			}

			var cellIsBeingReused = false;
			var layout = convertView as ConditionalFocusLayout;
			if (layout != null)
			{
				cellIsBeingReused = true;
				convertView = layout.GetChildAt(0);
			}
			else
				layout = new ConditionalFocusLayout(_context) { Orientation = Orientation.Vertical };

			if (cachingStrategy == ListViewCachingStrategy.RecycleElement && convertView != null)
			{
				var boxedCell = (INativeElementView)convertView;
				if (boxedCell == null)
				{
					throw new InvalidOperationException($"View for cell must implement {nameof(INativeElementView)} to enable recycling.");
				}
				cell = (Cell)boxedCell.Element;

				if (ActionModeContext == cell)
				{
					// This appears to never happen, the theory is android keeps all views alive that are currently selected for long-press (preventing them from being recycled).
					// This is convenient since we wont have to worry about the user scrolling the cell offscreen and us losing our context actions.
					ActionModeContext = null;
					ContextView = null;
				}
				// We are going to re-set the Platform here because in some cases (headers mostly) its possible this is unset and
				// when the binding context gets updated the measure passes will all fail. By applying this here the Update call
				// further down will result in correct layouts.
				cell.Platform = _listView.Platform;

				ICellController cellController = cell;
				cellController.SendDisappearing();

				int row = position;
				var group = 0;
				var templatedItems = TemplatedItemsView.TemplatedItems;
				if (_listView.IsGroupingEnabled)
					group = templatedItems.GetGroupIndexFromGlobal(position, out row);

				var templatedList = templatedItems.GetGroup(group);

				if (_listView.IsGroupingEnabled)
				{
					if (row == 0)
						templatedList.UpdateHeader(cell, group);
					else
						templatedList.UpdateContent(cell, row - 1);
				}
				else
					templatedList.UpdateContent(cell, row);

				cellController.SendAppearing();

				if (cell.BindingContext == ActionModeObject)
				{
					ActionModeContext = cell;
					ContextView = layout;
				}

				if (ReferenceEquals(_listView.SelectedItem, cell.BindingContext))
					Select(_listView.IsGroupingEnabled ? row - 1 : row, layout);
				else if (cell.BindingContext == ActionModeObject)
					SetSelectedBackground(layout, true);
				else
					UnsetSelectedBackground(layout);

				Performance.Stop();
				return layout;
			}

			AView view = CellFactory.GetCell(cell, convertView, parent, _context, _listView);

			Performance.Start("AddView");

			if (cellIsBeingReused)
			{
				if (convertView != view)
				{
					layout.RemoveViewAt(0);
					layout.AddView(view, 0);
				}
			}
			else
				layout.AddView(view, 0);

			Performance.Stop("AddView");

			bool isHeader = cell.GetIsGroupHeader<ItemsView<Cell>, Cell>();

			AView bline;

			UpdateSeparatorVisibility(cell, cellIsBeingReused, isHeader, nextCellIsHeader, layout, out bline);

			UpdateSeparatorColor(isHeader, bline);

			if ((bool)cell.GetValue(IsSelectedProperty))
				Select(position, layout);
			else
				UnsetSelectedBackground(layout);

			layout.ApplyTouchListenersToSpecialCells(cell);

			Performance.Stop();

			return layout;
		}
		public override AView GetView(int position, AView convertView, ViewGroup parent)
		{
			object obj = this[position];
			if (obj == null)
				return new AView(Context);

			bool isHeader, nextIsHeader;
			Cell item = GetCellForPosition(position, out isHeader, out nextIsHeader);

			var makeBline = true;
			var layout = convertView as ConditionalFocusLayout;
			if (layout != null)
			{
				makeBline = false;
				convertView = layout.GetChildAt(0);
			}
			else
				layout = new ConditionalFocusLayout(Context) { Orientation = Orientation.Vertical };

			AView aview = CellFactory.GetCell(item, convertView, parent, Context, _view);

			if (!makeBline)
			{
				if (convertView != aview)
				{
					layout.RemoveViewAt(0);
					layout.AddView(aview, 0);
				}
			}
			else
				layout.AddView(aview, 0);

			AView bline;
			if (makeBline)
			{
				bline = new AView(Context) { LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1) };

				layout.AddView(bline);
			}
			else
				bline = layout.GetChildAt(1);

			if (isHeader)
				bline.SetBackgroundColor(Color.Accent.ToAndroid());
			else if (nextIsHeader)
				bline.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
			else
			{
				using (var value = new TypedValue())
				{
					int id = global::Android.Resource.Drawable.DividerHorizontalDark;
					if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ListDivider, value, true))
						id = value.ResourceId;
					else if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.Divider, value, true))
						id = value.ResourceId;

					bline.SetBackgroundResource(id);
				}
			}

			layout.ApplyTouchListenersToSpecialCells(item);

			if (_restoreFocus == item)
			{
				if (!aview.HasFocus)
					aview.RequestFocus();

				_restoreFocus = null;
			}
			else if (aview.HasFocus)
				aview.ClearFocus();

			return layout;
		}