private static HorizontalLoopingSelectorItem GetFirstItem(HorizontalLoopingSelectorItem item, out int count) { count = 0; while (item.Previous != null) { ++count; item = item.Previous; } return item; }
private static HorizontalLoopingSelectorItem GetLastItem(HorizontalLoopingSelectorItem item, out int count) { count = 0; while (item.Next != null) { ++count; item = item.Next; } return item; }
private void SelectAndSnapTo(HorizontalLoopingSelectorItem item) { if (item == null) { return; } if (_selectedItem != null && _selectedItem != item) { _selectedItem.SetState(IsExpanded ? HorizontalLoopingSelectorItem.State.Expanded : HorizontalLoopingSelectorItem.State.Normal, true); } if (_selectedItem != item) { _selectedItem = item; // Update DataSource.SelectedItem aynchronously so that animations have a chance to start. Dispatcher.BeginInvoke(() => { _isSelecting = true; DataSource.SelectedItem = item.DataContext; _isSelecting = false; }); _selectedItem.SetState(HorizontalLoopingSelectorItem.State.Selected, true); } TranslateTransform transform = item.Transform; if (transform != null) { double newPosition = -transform.X - Math.Round(item.ActualWidth / 2); if (_panningTransform.X != newPosition) { AnimatePanel(_selectDuration, _selectEase, newPosition); } } }
/// <summary> /// Balances the items. /// </summary> private void Balance() { if (!IsReady) { return; } double actualItemWidth = ActualItemWidth; double actualItemHeight = ActualItemHeight; _additionalItemsCount = (int)Math.Round((ActualWidth * 1.5) / actualItemWidth); HorizontalLoopingSelectorItem closestToMiddle = null; int closestToMiddleIndex = -1; if (_itemsPanel.Children.Count == 0) { // We need to get the selection and start from there closestToMiddleIndex = 0; _selectedItem = closestToMiddle = CreateAndAddItem(_itemsPanel, DataSource.SelectedItem); closestToMiddle.Transform.X = -actualItemWidth / 2; closestToMiddle.Transform.Y = (ActualHeight - actualItemHeight) / 2; closestToMiddle.SetState(HorizontalLoopingSelectorItem.State.Selected, false); } else { closestToMiddleIndex = GetClosestItem(); closestToMiddle = (HorizontalLoopingSelectorItem)_itemsPanel.Children[closestToMiddleIndex]; } int itemsBeforeCount; HorizontalLoopingSelectorItem firstItem = GetFirstItem(closestToMiddle, out itemsBeforeCount); int itemsAfterCount; HorizontalLoopingSelectorItem lastItem = GetLastItem(closestToMiddle, out itemsAfterCount); // Does the right side need items? if (itemsBeforeCount < itemsAfterCount || itemsBeforeCount < _additionalItemsCount) { while (itemsBeforeCount < _additionalItemsCount) { object newData = DataSource.GetPrevious(firstItem.DataContext); if (newData == null) { // There may be room to display more items, but there is no more data. _maximumPanelScroll = -firstItem.Transform.X - actualItemWidth / 2; if (_isAnimating && _panelAnimation.To.Value > _maximumPanelScroll) { Brake(_maximumPanelScroll); } break; } HorizontalLoopingSelectorItem newItem = null; // Can an item from the left side be re-used? if (itemsAfterCount > _additionalItemsCount) { newItem = lastItem; lastItem = lastItem.Previous; newItem.Remove(); newItem.Content = newItem.DataContext = newData; } else { // Make a new item newItem = CreateAndAddItem(_itemsPanel, newData); newItem.Transform.Y = (ActualHeight - actualItemHeight) / 2; } // Put the new item on the top //if(newItem.Transform.X < firstItem.Transform.X) newItem.Transform.X = firstItem.Transform.X - actualItemWidth; newItem.InsertBefore(firstItem); firstItem = newItem; ++itemsBeforeCount; } } // Does the left side need items? if (itemsAfterCount < itemsBeforeCount || itemsAfterCount < _additionalItemsCount) { while (itemsAfterCount < _additionalItemsCount) { object newData = DataSource.GetNext(lastItem.DataContext); if (newData == null) { // There may be room to display more items, but there is no more data. _minimumPanelScroll = -lastItem.Transform.X - actualItemWidth / 2; if (_isAnimating && _panelAnimation.To.Value < _minimumPanelScroll) { Brake(_minimumPanelScroll); } break; } HorizontalLoopingSelectorItem newItem = null; // Can an item from the top be re-used? if (itemsBeforeCount > _additionalItemsCount) { newItem = firstItem; firstItem = firstItem.Next; newItem.Remove(); newItem.Content = newItem.DataContext = newData; } else { // Make a new item newItem = CreateAndAddItem(_itemsPanel, newData); newItem.Transform.Y = (ActualHeight - actualItemHeight) / 2; } // Put the new item on the bottom newItem.Transform.X = lastItem.Transform.X + actualItemWidth; newItem.InsertAfter(lastItem); lastItem = newItem; ++itemsAfterCount; } } _temporaryItemsPool = null; }
void listener_DragStarted(object sender, DragStartedGestureEventArgs e) { //Debug.WriteLine("listener_DragStarted"); if (e.Direction == Orientation.Horizontal) { _state = State.Dragging; e.Handled = true; _selectedItem = null; if (!IsExpanded) { IsExpanded = true; } _dragTarget = _panningTransform.X; UpdateItemState(); } }
void listener_Flick(object sender, FlickGestureEventArgs e) { //Debug.WriteLine("listener_Flick"); if (e.Direction == Orientation.Horizontal) { _state = State.Flicking; _selectedItem = null; if (!IsExpanded) { IsExpanded = true; } Point velocity = new Point(e.HorizontalVelocity, 0); double flickDuration = PhysicsConstants.GetStopTime(velocity); Point flickEndPoint = PhysicsConstants.GetStopPoint(velocity); IEasingFunction flickEase = PhysicsConstants.GetEasingFunction(flickDuration); AnimatePanel(new Duration(TimeSpan.FromSeconds(flickDuration)), flickEase, _panningTransform.X + flickEndPoint.X); e.Handled = true; _selectedItem = null; UpdateItemState(); } }
internal void InsertBefore(HorizontalLoopingSelectorItem before) { Next = before; Previous = before.Previous; if (before.Previous != null) { before.Previous.Next = this; } before.Previous = this; }
internal void InsertAfter(HorizontalLoopingSelectorItem after) { Next = after.Next; Previous = after; if (after.Next != null) { after.Next.Previous = this; } after.Next = this; }
internal void Remove() { if (Previous != null) { Previous.Next = Next; } if (Next != null) { Next.Previous = Previous; } Next = Previous = null; }
private void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { if (_isDragging) { // See if it was a flick if (e.IsInertial) { _state = State.Flicking; _selectedItem = null; if (!IsExpanded) { IsExpanded = true; } Point velocity = new Point(e.FinalVelocities.LinearVelocity.X, 0); double flickDuration = PhysicsConstants.GetStopTime(velocity); Point flickEndPoint = PhysicsConstants.GetStopPoint(velocity); IEasingFunction flickEase = PhysicsConstants.GetEasingFunction(flickDuration); AnimatePanel(new Duration(TimeSpan.FromSeconds(flickDuration)), flickEase, _panningTransform.X + flickEndPoint.X); e.Handled = true; _selectedItem = null; UpdateItemState(); } if (_state == State.Dragging) { SelectAndSnapToClosest(); } _state = State.Expanded; } }
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e) { if (_isDragging) { AnimatePanel(_panDuration, _panEase, _dragTarget += e.DeltaManipulation.Translation.X); e.Handled = true; } else if (Math.Abs(e.CumulativeManipulation.Translation.Y) > DragSensitivity) { _isAllowedToDragHorizontally = false; } else if (_isAllowedToDragHorizontally && Math.Abs(e.CumulativeManipulation.Translation.X) > DragSensitivity) { _isDragging = true; _state = State.Dragging; e.Handled = true; _selectedItem = null; if (!IsExpanded) { IsExpanded = true; } _dragTarget = _panningTransform.X; UpdateItemState(); } }