public static void ScrollVerticallyTo(ScrollRect parentScrollRect, UiEventNavigation childControl, Dictionary <UiEventNavigation, SingleAxisBounds> cacheDict = null, bool centerTo = false) { if ((parentScrollRect != null) && (childControl != null) && (childControl.Selectable != null)) { // Check the cache, and see if the bounds for this child control already exists SingleAxisBounds childBounds; if ((cacheDict == null) || (cacheDict.TryGetValue(childControl, out childBounds) == false)) { // Calculate the top and bottom position of the the control float topPos, centerPos, bottomPos; centerPos = GetVerticalAnchoredPositionInContent(parentScrollRect.content, childControl, out topPos, out bottomPos); childBounds = new SingleAxisBounds(topPos, centerPos, bottomPos); // Cache these values if (cacheDict != null) { cacheDict.Add(childControl, childBounds); } } // Check whether we need to scroll or not, and if so, in which snapping direction ScrollVerticalSnap snapTo = ScrollVerticalSnap.CenterToChild; if (centerTo == false) { snapTo = GetVerticalSnapping(parentScrollRect.content, parentScrollRect.viewport, ref childBounds); } // Check whether we want to scroll or not if (snapTo != ScrollVerticalSnap.None) { // Grab the position to scroll to float selectionPosition = GetScrollToPosition(parentScrollRect.viewport, snapTo, ref childBounds); // Clamp the selection position value float maxPosition = (parentScrollRect.content.rect.height - parentScrollRect.viewport.rect.height); selectionPosition = Mathf.Clamp(selectionPosition, 0, maxPosition); // Directly set the position of the ScrollRect's content Vector3 scrollPosition = parentScrollRect.content.anchoredPosition; scrollPosition.y = selectionPosition; parentScrollRect.content.anchoredPosition = scrollPosition; } } }
private static float GetScrollToPosition(RectTransform viewportTransform, ScrollVerticalSnap snapTo, ref SingleAxisBounds childBounds) { // By default, snap to the top of the child control float childControlPosition = childBounds.max; // Check the snap-to algorithm if (snapTo == ScrollVerticalSnap.BottomOfChild) { // Shift the scroll position to the bottom of the scrollrect childControlPosition = childBounds.min; childControlPosition += viewportTransform.rect.height; } else if (snapTo == ScrollVerticalSnap.CenterToChild) { // Shift the scroll position to the center of the scrollrect childControlPosition = childBounds.middle; childControlPosition += (viewportTransform.rect.height / 2f); } childControlPosition *= -1f; return(childControlPosition); }
private static ScrollVerticalSnap GetVerticalSnapping(RectTransform contentTransform, RectTransform viewportTransform, ref SingleAxisBounds childBounds) { ScrollVerticalSnap returnOffset = ScrollVerticalSnap.None; float topOfChildControl = childBounds.max; float bottomOfChildControl = childBounds.min; // Check if viewport is smaller than content float viewportHeight = viewportTransform.rect.height; if (contentTransform.rect.height > viewportHeight) { // Based on these values, determine whether to snap to the top or bottom of out-of-view child control if (Mathf.Abs(topOfChildControl) < contentTransform.anchoredPosition.y) { returnOffset = ScrollVerticalSnap.TopOfChild; } else if (Mathf.Abs(bottomOfChildControl) > (contentTransform.anchoredPosition.y + viewportHeight)) { returnOffset = ScrollVerticalSnap.BottomOfChild; } } return(returnOffset); }