/// <summary> /// Update ScrollView scroll start position based on other scrollview scrolling /// </summary> public static void UpdateScrollViewStart(HeaderLayout headerLayout, ContentPage contentPage, NavigationPage navigationPage, ScrollView scrollView, double scrollY) { bool isNavigationBarFloating = false; NavigationBarVisibility navBarVisibility = NavigationBarVisibility.Hidden; double navigationBarHeight = 0; if (contentPage != null) { isNavigationBarFloating = NavigationBar.GetIsFloating(contentPage); navBarVisibility = NavigationBar.GetVisibility(contentPage); } if (navigationPage != null) { bool isNavigationBarScrollable = navBarVisibility == NavigationBarVisibility.Scroll || navBarVisibility == NavigationBarVisibility.SmoothScroll; if (navigationPage != null && (isNavigationBarFloating || isNavigationBarScrollable)) { navigationBarHeight = navigationPage.GetNavigationBarHeight(); } } if (headerLayout != null) { // If scrolled header hidden if (scrollY >= headerLayout.HeaderHeight + navigationBarHeight) { // If scrollview is scrolled less than header height if (scrollView.ScrollY < headerLayout.HeaderHeight + navigationBarHeight) { if (Device.RuntimePlatform == Device.UWP) { ScrollEffect effect = scrollView.Effects.FirstOrDefault(c => c is ScrollEffect) as ScrollEffect; effect.ScrollTo(0, headerLayout.HeaderHeight + navigationBarHeight); } else { scrollView.ScrollToAsync(0, headerLayout.HeaderHeight + navigationBarHeight, false); } } } // If scrolled less than header height else if (scrollView.ScrollY.Equals(scrollY) == false) { if (Device.RuntimePlatform == Device.UWP) { ScrollEffect effect = scrollView.Effects.FirstOrDefault(c => c is ScrollEffect) as ScrollEffect; effect.ScrollTo(0, scrollY); } else { scrollView.ScrollToAsync(0, scrollY, false); } } } }
/// <summary> /// Update ScrollView / CollectionView padding which are header layout content /// </summary> public static void UpdateScrollSourcePadding(HeaderLayout headerLayout, ContentPage contentPage, NavigationPage navigationPage, View scrollSource) { bool isHeaderLayoutInScrollViewer = headerLayout != null?VisualTreeHelper.GetParent <ScrollView>(headerLayout) != null : false; // Get navigation page navigation bar height double topPadding = 0; if (contentPage != null && NavigationBar.GetIsFloating(contentPage) == false && isHeaderLayoutInScrollViewer == false && (NavigationBar.GetVisibility(contentPage) == NavigationBarVisibility.Scroll || NavigationBar.GetVisibility(contentPage) == NavigationBarVisibility.SmoothScroll)) { topPadding += navigationPage.GetNavigationBarHeight(); } if (headerLayout != null && isHeaderLayoutInScrollViewer == false) { topPadding += headerLayout.HeaderHeight; topPadding += headerLayout.StickyHeaderHeight; } if (scrollSource is ScrollView scrollView) { if (topPadding.Equals(scrollView.Padding.Top) == false) { scrollView.Padding = new Thickness(scrollView.Padding.Left, topPadding, scrollView.Padding.Right, scrollView.Padding.Bottom); } } else if (scrollSource is CollectionView collectionView) { if (collectionView.Header == null) { BoxView b = new BoxView(); b.HeightRequest = 0; collectionView.Header = b; } if (collectionView.Header is View headerView) { headerView.Margin = new Thickness(headerView.Margin.Left, topPadding, headerView.Margin.Right, headerView.Margin.Bottom); } } }
/// <summary> /// Update headers and navigation bar translation Y by scroll /// </summary> private static void HandleScrolling(HeaderLayout headerLayout, ContentPage contentPage, NavigationPage navigationPage, double oldScrollY, double newScrollY) { // Save previous scroll Y if (headerLayout != null) { headerLayout.ScrollY = newScrollY; } TryGetNavigationBarProperties(contentPage, navigationPage, out double navigationBarHeight, out double navigationBarY, out bool isNavigationBarFloating, out bool isNavigationBarScrollable); // Scroll delta double delta = Math.Max(0, newScrollY) - Math.Max(0, oldScrollY); // Update navigation bar translation when it should scroll out smoothly or not if (navigationPage != null && contentPage != null && (NavigationBar.GetVisibility(contentPage) == NavigationBarVisibility.Scroll || NavigationBar.GetVisibility(contentPage) == NavigationBarVisibility.SmoothScroll)) { View navigationBar = navigationPage.GetNavigationBar(); // Hide navigation bar smoothly if (NavigationBar.GetVisibility(contentPage) == NavigationBarVisibility.SmoothScroll && navigationBar != null) { // If scrolled enought speed do smooth navigation bar hiding with animation if (Math.Abs(delta) > 5) { string showScrollBarAnimationName = "showScrollBarAnimation"; string hideScrollBarAnimationName = "hideScrollBarAnimation"; double start = navigationBar.TranslationY; double target = 0; string actualAnimationName; if (delta < 0) { target = 0; actualAnimationName = showScrollBarAnimationName; } else { target = -navigationBarHeight + RootPage.Instance.SafeAreaInsest.Top; actualAnimationName = hideScrollBarAnimationName; } if (target != navigationBar.TranslationY && AnimationExtensions.AnimationIsRunning(navigationBar, actualAnimationName) == false) { AnimationExtensions.AbortAnimation(navigationBar, showScrollBarAnimationName); AnimationExtensions.AbortAnimation(navigationBar, hideScrollBarAnimationName); new Animation(d => { // Animate NavigastionBar TranslationY navigationBar.TranslationY = start + (target - start) * d; // Get NavigationBar properties during animation because they can change TryGetNavigationBarProperties(contentPage, navigationPage, out navigationBarHeight, out navigationBarY, out isNavigationBarFloating, out isNavigationBarScrollable); // Update headers transaltion because navigation bar translation is animated headerLayout?.UpdateHeadersTranslationY(headerLayout.ScrollY, navigationBarHeight, navigationBarY, isNavigationBarFloating, isNavigationBarScrollable); }, 0, 1).Commit(navigationBar, actualAnimationName, 64, 250); } else { headerLayout?.UpdateHeadersTranslationY(newScrollY, navigationBarHeight, navigationBar.TranslationY, isNavigationBarFloating, isNavigationBarScrollable); } } // If not scrolled enought speed, then hide other headers normally else { headerLayout?.UpdateHeadersTranslationY(newScrollY, navigationBarHeight, navigationBar.TranslationY, isNavigationBarFloating, isNavigationBarScrollable); } } // Hide navigation bar based on scroll only else { navigationBar.TranslationY = Math.Min(0, Math.Max(-navigationBarHeight + RootPage.Instance.SafeAreaInsest.Top, navigationBar.TranslationY - delta)); navigationBarY = navigationBar.TranslationY; headerLayout?.UpdateHeadersTranslationY(newScrollY, navigationBarHeight, navigationBarY, isNavigationBarFloating, isNavigationBarScrollable); } } // If navigation bar is visible or hidden else { headerLayout?.UpdateHeadersTranslationY(newScrollY, navigationBarHeight, navigationBarY, isNavigationBarFloating, isNavigationBarScrollable); } }