private bool IsItemVisible(float scrollPosition, RecycleItem item) { bool result = false; View list = Container.GetParent() as View; if (list == null) { return(result); } Vector2 visibleArea = new Vector2(Math.Abs(scrollPosition), Math.Abs(scrollPosition) + (LayoutOrientation == Orientation.Horizontal ? list.Size.Width : list.Size.Height) ); float firstCheckPoint = LayoutOrientation == Orientation.Horizontal ? item.Position.X : item.Position.Y; float secondCheckPoint = LayoutOrientation == Orientation.Horizontal ? firstCheckPoint + item.Size.Width : firstCheckPoint + item.Size.Height; // Tizen.Log.Error("NUI", "[1p] "+visibleArea.X+ " =< "+firstCheckPoint+" =< "+visibleArea.Y+" ==== \n"); // Tizen.Log.Error("NUI", "[2p] "+visibleArea.X+ " =< "+secondCheckPoint+" =< "+visibleArea.Y+" ==== \n"); result = (firstCheckPoint >= visibleArea.X && firstCheckPoint <= visibleArea.Y) || (secondCheckPoint >= visibleArea.X && secondCheckPoint <= visibleArea.Y); return(result); }
/// <summary> /// This is called to find out where items are lain out according to current scroll position. /// </summary> /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API public override void Layout(float scrollPosition) { int itemInGroup = LayoutOrientation == Orientation.Vertical ? Rows : Columns; firstVisibleItemIndex = -1; lastVisibleItemIndex = -1; RecycleItem previousItem = null; for (int i = 0; i < Container.Children.Count; i++) { RecycleItem item = Container.Children[i] as RecycleItem; if (previousItem != null && item != null) { item.Position = LayoutOrientation == Orientation.Vertical ? new Position( (i % itemInGroup == 0 ? previousItem.Position.X + (previousItem.CurrentSize.Width != 0 ? previousItem.CurrentSize.Width : previousItem.Size.Width) : previousItem.Position.X), (i % itemInGroup == 0 ? 0 : previousItem.PositionY + (previousItem.CurrentSize.Height != 0 ? previousItem.CurrentSize.Height : previousItem.Size.Height)) ) : new Position( (i % itemInGroup == 0 ? 0 : previousItem.PositionX + (previousItem.CurrentSize.Width != 0 ? previousItem.CurrentSize.Width : previousItem.Size.Width)), (i % itemInGroup == 0 ? previousItem.Position.Y + (previousItem.CurrentSize.Height != 0 ? previousItem.CurrentSize.Height : previousItem.Size.Height) : previousItem.Position.Y) ); } bool isVisible = IsItemVisible(scrollPosition, item); if (isVisible) { firstVisibleItemIndex = firstVisibleItemIndex == -1 ? i : firstVisibleItemIndex; lastVisibleItemIndex = i; } previousItem = item; } if (StepSize == 0) { StepSize = LayoutOrientation == Orientation.Vertical ? ItemSize.Width : ItemSize.Height; } }
/// <summary> /// This is called to find out which items should be recycled according to current scroll position. /// </summary> /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param> /// <returns>List of RecycleItems which should be recycled.</returns> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API public override List <RecycleItem> Recycle(float scrollPosition) { List <RecycleItem> result = new List <RecycleItem>(); bool checkFront = (PrevScrollPosition - scrollPosition) > 0; int itemInGroup = LayoutOrientation == Orientation.Vertical ? Rows : Columns; if (checkFront) { int currentGroupNum = (int)(firstVisibleItemIndex / itemInGroup) + 1; if (currentGroupNum > 2) { // Too many item is in front!!! move first item to back!!!! for (int i = 0; i < itemInGroup; i++) { RecycleItem target = Container.Children[0] as RecycleItem; if (target != null) { target.DataIndex = target.DataIndex + Container.Children.Count; target.SiblingOrder = Container.Children.Count - 1; result.Add(target); } } } } else { int currentGroupNum = (int)(lastVisibleItemIndex / itemInGroup) + 1; if (currentGroupNum < (int)(Container.Children.Count / itemInGroup) - 3) { for (int i = 0; i < itemInGroup; i++) { RecycleItem prevFirstItem = Container.Children[itemInGroup] as RecycleItem; RecycleItem target = Container.Children[Container.Children.Count - 1] as RecycleItem; if (prevFirstItem != null && target != null) { target.Position = new Position( LayoutOrientation == Orientation.Vertical ? (prevFirstItem.Position.X - target.Size.Width) : prevFirstItem.Position.X, LayoutOrientation == Orientation.Vertical ? prevFirstItem.Position.Y : (prevFirstItem.Position.Y - target.Size.Height) ); target.DataIndex = target.DataIndex - Container.Children.Count; target.SiblingOrder = 0; result.Add(target); } } } } PrevScrollPosition = scrollPosition; return(result); }
/// <summary> /// Set focus to item which has specific data index. /// </summary> /// <param name="dataIndex">Data index of item.</param> /// <param name="animated">If set true, scroll to item using animation.</param> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API public void SetFocus(int dataIndex, bool animated) { foreach (RecycleItem item in Children) { if (item.DataIndex == dataIndex) { RecycleItem prevFocusedItem = FocusedItem; prevFocusedItem?.OnFocusLost(); FocusedItem = item; FocusedItem.OnFocusGained(); ScrollTo(item.DataIndex * mLayoutManager.StepSize, animated); } } }
/// <summary> /// This helps developer who wants to know before scroll is reaching target position. /// </summary> /// <param name="targetPosition">Index of item.</param> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API protected override void OnPreReachedTargetPosition(float targetPosition) { int targetDataIndex = (int)Math.Round(Math.Abs(targetPosition) / mLayoutManager.StepSize); for (int i = 0; i < Children.Count; i++) { RecycleItem item = Children[i] as RecycleItem; if (targetDataIndex == item.DataIndex) { FocusedItem = item; item.OnFocusGained(); break; } } }
/// <summary> /// This is called to find out where items are lain out according to current scroll position. /// </summary> /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API public override void Layout(float scrollPosition) { firstVisibleItemIndex = -1; lastVisibleItemIndex = -1; RecycleItem previousItem = null; for (int i = 0; i < Container.Children.Count; i++) { RecycleItem item = Container.Children[i] as RecycleItem; if (previousItem != null && item != null) { item.Position = LayoutOrientation == Orientation.Horizontal ? new Position( previousItem.Position.X + (previousItem.CurrentSize.Width != 0 ? previousItem.CurrentSize.Width : previousItem.Size.Width), item.PositionY ) : new Position( item.PositionX, previousItem.Position.Y + (previousItem.CurrentSize.Height != 0 ? previousItem.CurrentSize.Height : previousItem.Size.Height) ); } bool isVisible = IsItemVisible(scrollPosition, item); if (isVisible) { firstVisibleItemIndex = firstVisibleItemIndex == -1 ? i : firstVisibleItemIndex; lastVisibleItemIndex = i; } previousItem = item; // Tizen.Log.Error("NUI","["+item.DataIndex+"] "+item.Position.Y+" ==== \n"); } if (StepSize == 0) { StepSize = LayoutOrientation == Orientation.Horizontal ? ItemSize.Width : ItemSize.Height; } }
public override List <RecycleItem> Recycle(float scrollPosition) { List <RecycleItem> result = new List <RecycleItem>(); bool isBack = scrollPosition - PrevScrollPosition < 0; int previousFocusIndex = FocusedIndex; if (!isBack && FocusedIndex < 6) { RecycleItem target = Container.Children[Container.Children.Count - 1] as RecycleItem; if (target != null) { int previousSiblingOrder = target.SiblingOrder; target.SiblingOrder = 0; target.DataIndex = target.DataIndex - Container.Children.Count; target.Position = new Position(0, Math.Abs(scrollPosition) - 360); target.Scale = new Vector3(0, 0, 0); result.Add(target); FocusedIndex++; } } else if (isBack && FocusedIndex > 8) { RecycleItem target = Container.Children[0] as RecycleItem; if (target != null) { int previousSiblingOrder = target.SiblingOrder; target.SiblingOrder = Container.Children.Count - 1; target.DataIndex = target.DataIndex + Container.Children.Count; target.Position = new Position(0, Math.Abs(scrollPosition) + 360); target.Scale = new Vector3(0, 0, 0); result.Add(target); FocusedIndex--; } } PrevScrollPosition = scrollPosition; return(result); }
/// <summary> /// This is called to find out which items should be recycled according to current scroll position. /// </summary> /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param> /// <returns>List of RecycleItems which should be recycled.</returns> /// <since_tizen> 8 </since_tizen> /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API public override List <RecycleItem> Recycle(float scrollPosition) { List <RecycleItem> result = new List <RecycleItem>(); bool checkFront = (PrevScrollPosition - scrollPosition) > 0; if (checkFront) { if (firstVisibleItemIndex > 3) { // Too many item is in front!!! move first item to back!!!! RecycleItem target = Container.Children[0] as RecycleItem; if (target != null) { target.DataIndex = target.DataIndex + Container.Children.Count; target.SiblingOrder = Container.Children.Count - 1; result.Add(target); } } } else { if (lastVisibleItemIndex < Container.Children.Count - 3) { RecycleItem prevFirstItem = Container.Children[0] as RecycleItem; RecycleItem target = Container.Children[Container.Children.Count - 1] as RecycleItem; if (prevFirstItem != null && target != null) { target.Position = new Position( LayoutOrientation == Orientation.Horizontal ? (prevFirstItem.Position.X - target.Size.Width) : prevFirstItem.Position.X, LayoutOrientation == Orientation.Horizontal ? prevFirstItem.Position.Y : (prevFirstItem.Position.Y - target.Size.Height) ); target.DataIndex = target.DataIndex - Container.Children.Count; target.SiblingOrder = 0; result.Add(target); } } } PrevScrollPosition = scrollPosition; return(result); }
public override View RequestNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled) { View nextFocusedView = null; int targetSibling = -1; bool isHorizontal = LayoutOrientation == Orientation.Horizontal; switch (direction) { case View.FocusDirection.Left: { targetSibling = isHorizontal ? currentFocusedView.SiblingOrder - 1 : targetSibling; break; } case View.FocusDirection.Right: { targetSibling = isHorizontal ? currentFocusedView.SiblingOrder + 1 : targetSibling; break; } case View.FocusDirection.Up: { targetSibling = isHorizontal ? targetSibling : currentFocusedView.SiblingOrder - 1; break; } case View.FocusDirection.Down: { targetSibling = isHorizontal ? targetSibling : currentFocusedView.SiblingOrder + 1; break; } } if (targetSibling > -1 && targetSibling < Container.Children.Count) { RecycleItem candidate = Container.Children[targetSibling] as RecycleItem; if (candidate != null && candidate.DataIndex >= 0 && candidate.DataIndex < DataCount) { nextFocusedView = candidate; } } return(nextFocusedView); }
private bool IsItemVisible(float scrollPosition, RecycleItem item) { bool result = false; View list = Container.GetParent() as View; if (list == null) { return(result); } Vector2 visibleArea = new Vector2(Math.Abs(scrollPosition), Math.Abs(scrollPosition) + (LayoutOrientation == Orientation.Vertical ? list.Size.Width : list.Size.Height) ); float firstCheckPoint = LayoutOrientation == Orientation.Vertical ? item.Position.X : item.Position.Y; float secondCheckPoint = LayoutOrientation == Orientation.Vertical ? firstCheckPoint + item.Size.Width : firstCheckPoint + item.Size.Height; result = (firstCheckPoint >= visibleArea.X && firstCheckPoint <= visibleArea.Y) || (secondCheckPoint >= visibleArea.X && secondCheckPoint <= visibleArea.Y); return(result); }
private void InitializeItems() { for (int i = Children.Count - 1; i > -1; i--) { Children[i].Unparent(); notifications[i].Notified -= OnItemSizeChanged; notifications.RemoveAt(i); } for (int i = 0; i < totalItemCount; i++) { RecycleItem item = adapter.CreateRecycleItem(); item.DataIndex = i; item.Name = "[" + i + "] recycle"; if (i < adapter.Data.Count) { adapter.BindData(item); } Add(item); PropertyNotification noti = item.AddPropertyNotification("size", PropertyCondition.Step(0.1f)); noti.Notified += OnItemSizeChanged; notifications.Add(noti); } layoutManager.Layout(0.0f); if (ScrollingDirection == Direction.Horizontal) { ContentContainer.SizeWidth = layoutManager.CalculateLayoutOrientationSize(); } else { ContentContainer.SizeHeight = layoutManager.CalculateLayoutOrientationSize(); } }
public override void Layout(float scrollPosition) { RecycleItem centerItem = Container.Children[FocusedIndex] as RecycleItem; if (centerItem == null) { return; } float centerItemPosition = LayoutOrientation == Orientation.Horizontal ? centerItem.Position.X : centerItem.Position.Y; Vector2 stepRange = new Vector2(-scrollPosition - StepSize + 1.0f, -scrollPosition + StepSize - 1.0f); Vector2 visibleRange = new Vector2(Math.Abs(scrollPosition) - 180, Math.Abs(scrollPosition) + 180); if (StepSize != 0 && centerItemPosition <= stepRange.X) { FocusedIndex = Math.Min(Container.Children.Count - 1, FocusedIndex + 1); centerItem = Container.Children[FocusedIndex] as RecycleItem; if (centerItem != null) { centerItem.Position = new Position(0.0f, Math.Abs(StepSize * (centerItem.DataIndex))); centerItem.Scale = new Vector3(1.0f, 1.0f, 1.0f); } } else if (StepSize != 0 && centerItemPosition >= stepRange.Y) { FocusedIndex = Math.Max(0, FocusedIndex - 1); centerItem = Container.Children[FocusedIndex] as RecycleItem; if (centerItem != null) { centerItem.Position = new Position(0.0f, Math.Abs(StepSize * (centerItem.DataIndex))); centerItem.Scale = new Vector3(1.0f, 1.0f, 1.0f); } } else { float centerItemScale = CalculateScaleFactor(centerItemPosition, scrollPosition); centerItem.Scale = new Vector3(centerItemScale, centerItemScale, 1.0f); } RecycleItem prevItem = centerItem; if (prevItem == null) { return; } // Front of center item for (int i = FocusedIndex - 1; i > -1; i--) { RecycleItem target = Container.Children[i] as RecycleItem; if (target == null) { continue; } float prevItemPosition = LayoutOrientation == Orientation.Horizontal ? prevItem.Position.X : prevItem.Position.Y; float prevItemSize = (LayoutOrientation == Orientation.Horizontal ? prevItem.Size.Width : prevItem.Size.Height); float prevItemCurrentSize = (LayoutOrientation == Orientation.Horizontal ? prevItem.GetCurrentSizeFloat().Width : prevItem.GetCurrentSizeFloat().Height); prevItemSize = prevItemCurrentSize == 0 ? prevItemSize : prevItemCurrentSize; prevItemSize = prevItemSize * prevItem.Scale.X; float startPosition = prevItemPosition - prevItemSize / 2.0f; if (startPosition > visibleRange.X) { float candidatePosition = visibleRange.X; candidatePosition = FindCandidatePosition(startPosition, scrollPosition, false); target.Position = LayoutOrientation == Orientation.Horizontal ? new Position(candidatePosition, target.Position.Y) : new Position(target.Position.X, candidatePosition); float scaleFactor = CalculateScaleFactor(candidatePosition, scrollPosition); target.Scale = new Vector3(scaleFactor, scaleFactor, 1.0f); prevItem = target; } else { target.Scale = new Vector3(0.0f, 0.0f, 1.0f); } } prevItem = centerItem; // Back of center item for (int i = FocusedIndex + 1; i < Container.Children.Count; i++) { RecycleItem target = Container.Children[i] as RecycleItem; if (target == null) { continue; } float prevItemPosition = LayoutOrientation == Orientation.Horizontal ? prevItem.Position.X : prevItem.Position.Y; float prevItemSize = (LayoutOrientation == Orientation.Horizontal ? prevItem.Size.Width : prevItem.Size.Height); float prevItemCurrentSize = (LayoutOrientation == Orientation.Horizontal ? prevItem.GetCurrentSizeFloat().Width : prevItem.GetCurrentSizeFloat().Height); prevItemSize = prevItemCurrentSize == 0 ? prevItemSize : prevItemCurrentSize; prevItemSize = prevItemSize * prevItem.Scale.X; float startPosition = prevItemPosition + prevItemSize / 2.0f; if (startPosition < visibleRange.Y) { float candidatePosition = visibleRange.Y; candidatePosition = FindCandidatePosition(startPosition, scrollPosition, true); target.Position = LayoutOrientation == Orientation.Horizontal ? new Position(candidatePosition, target.Position.Y) : new Position(target.Position.X, candidatePosition); float scaleFactor = CalculateScaleFactor(candidatePosition, scrollPosition); target.Scale = new Vector3(scaleFactor, scaleFactor, 1.0f); prevItem = target; } else { target.Scale = new Vector3(0.0f, 0.0f, 1.0f); } } if (StepSize == 0) { if (LayoutOrientation == Orientation.Horizontal) { StepSize = Container.Children[0].Size.Width / 2.0f + Container.Children[1].Size.Width * Container.Children[1].Scale.X / 2.0f; } else { StepSize = Container.Children[0].Size.Height / 2.0f + Container.Children[1].Size.Height * Container.Children[1].Scale.X / 2.0f; } StepSize = float.IsNaN(StepSize)?0:StepSize; } }
private void OnScrollDragStarted(object source, ScrollEventArgs args) { RecycleItem prevFocusedItem = FocusedItem; prevFocusedItem?.OnFocusLost(); }
public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled) { View nextFocusedView = null; if (!focusedView) { // If focusedView is null, find child which has previous data index if (Children.Count > 0 && Adapter.Data.Count > 0) { for (int i = 0; i < Children.Count; i++) { RecycleItem item = Children[i] as RecycleItem; if (item.DataIndex == prevFocusedDataIndex) { nextFocusedView = item; break; } } } } else { // If this is not first focus, request next focus to LayoutManager if (LayoutManager != null) { nextFocusedView = LayoutManager.RequestNextFocusableView(currentFocusedView, direction, loopEnabled); } } if (nextFocusedView != null) { // Check next focused view is inside of visible area. // If it is not, move scroll position to make it visible. Position scrollPosition = ContentContainer.CurrentPosition; float targetPosition = -(ScrollingDirection == Direction.Horizontal ? scrollPosition.X : scrollPosition.Y); float left = nextFocusedView.Position.X; float right = nextFocusedView.Position.X + nextFocusedView.Size.Width; float top = nextFocusedView.Position.Y; float bottom = nextFocusedView.Position.Y + nextFocusedView.Size.Height; float visibleRectangleLeft = -scrollPosition.X; float visibleRectangleRight = -scrollPosition.X + Size.Width; float visibleRectangleTop = -scrollPosition.Y; float visibleRectangleBottom = -scrollPosition.Y + Size.Height; if (ScrollingDirection == Direction.Horizontal) { if ((direction == View.FocusDirection.Left || direction == View.FocusDirection.Up) && left < visibleRectangleLeft) { targetPosition = left; } else if ((direction == View.FocusDirection.Right || direction == View.FocusDirection.Down) && right > visibleRectangleRight) { targetPosition = right - Size.Width; } } else { if ((direction == View.FocusDirection.Up || direction == View.FocusDirection.Left) && top < visibleRectangleTop) { targetPosition = top; } else if ((direction == View.FocusDirection.Down || direction == View.FocusDirection.Right) && bottom > visibleRectangleBottom) { targetPosition = bottom - Size.Height; } } focusedView = nextFocusedView; if ((nextFocusedView as RecycleItem) != null) { prevFocusedDataIndex = (nextFocusedView as RecycleItem).DataIndex; } ScrollTo(targetPosition, true); } else { // If nextView is null, it means that we should move focus to outside of Control. // Return FocusableView depending on direction. switch (direction) { case View.FocusDirection.Left: { nextFocusedView = LeftFocusableView; break; } case View.FocusDirection.Right: { nextFocusedView = RightFocusableView; break; } case View.FocusDirection.Up: { nextFocusedView = UpFocusableView; break; } case View.FocusDirection.Down: { nextFocusedView = DownFocusableView; break; } } if (nextFocusedView) { focusedView = null; } else { //If FocusableView doesn't exist, not move focus. nextFocusedView = focusedView; } } return(nextFocusedView); }
public virtual void BindData(RecycleItem item) { }