@@ -44,7 +44,7 @@ public partial class SfBottomSheet : SfView, IParentThemeElement
4444 /// <summary>
4545 /// The shape used to provide corner radius for the grabber.
4646 /// </summary>
47- RoundRectangle ? _grabberStrokeShape ;
47+ RoundRectangle ? _grabberStrokeShape ;
4848
4949 // Shape
5050 /// <summary>
@@ -823,7 +823,6 @@ public void Show()
823823 }
824824
825825 SetupBottomSheetForShow ( ) ;
826- _isSheetOpen = true ;
827826 AnimateBottomSheet ( GetTargetPosition ( ) ) ;
828827 IsOpen = true ;
829828 }
@@ -1028,7 +1027,8 @@ void InitializeBottomSheetBorder()
10281027 HeightRequest = CalculateInitialHeight ( ) ,
10291028 IsVisible = false ,
10301029 StrokeShape = _bottomSheetStrokeShape ,
1031- Content = _bottomSheetContent ?? throw new InvalidOperationException ( "Bottom sheet content is not initialized." )
1030+ Content = _bottomSheetContent ?? throw new InvalidOperationException ( "Bottom sheet content is not initialized." ) ,
1031+ Padding = ContentPadding
10321032 } ;
10331033 }
10341034
@@ -1048,8 +1048,7 @@ void InitializeContentBorder()
10481048 {
10491049 _contentBorder = new SfBorder ( )
10501050 {
1051- StrokeThickness = 0 ,
1052- Padding = ContentPadding
1051+ StrokeThickness = 0
10531052 } ;
10541053 }
10551054
@@ -1298,9 +1297,9 @@ CornerRadius EnsureValidCornerRadius(CornerRadius cornerRadius)
12981297 /// <param name="padding">The new padding to be applied.</param>
12991298 void UpdatePadding ( Thickness padding )
13001299 {
1301- if ( _contentBorder is not null && ! _contentBorder . Padding . Equals ( padding ) )
1300+ if ( _bottomSheet is not null && ! _bottomSheet . Padding . Equals ( padding ) )
13021301 {
1303- _contentBorder . Padding = padding ;
1302+ _bottomSheet . Padding = padding ;
13041303 OnPropertyChanged ( nameof ( ContentPadding ) ) ;
13051304 }
13061305 }
@@ -1316,7 +1315,7 @@ void UpdateGrabberHeightProperty(double newValue)
13161315 return ;
13171316 }
13181317
1319- _grabber . HeightRequest = ( newValue < 0 ) ? ( double ) ( GrabberHeightProperty . DefaultValue ) : newValue ;
1318+ _grabber . HeightRequest = ( newValue <= 0 ) ? ( double ) ( GrabberHeightProperty . DefaultValue ) : newValue ;
13201319 }
13211320
13221321 /// <summary>
@@ -1330,7 +1329,7 @@ void UpdateGrabberWidthProperty(double newValue)
13301329 return ;
13311330 }
13321331
1333- _grabber . WidthRequest = ( newValue < 0 ) ? ( double ) GrabberWidthProperty . DefaultValue : newValue ;
1332+ _grabber . WidthRequest = ( newValue <= 0 ) ? ( double ) GrabberWidthProperty . DefaultValue : newValue ;
13341333 }
13351334
13361335
@@ -1495,15 +1494,29 @@ void UpdateStateBasedOnNearestPoint()
14951494
14961495 if ( nearestPoint == fullExpandedHeight )
14971496 {
1498- State = BottomSheetState . FullExpanded ;
1497+ if ( State is not BottomSheetState . FullExpanded )
1498+ {
1499+ State = BottomSheetState . FullExpanded ;
1500+ }
1501+ else
1502+ {
1503+ Show ( ) ;
1504+ }
14991505 }
15001506 else if ( nearestPoint == halfExpandedHeight )
15011507 {
15021508 State = BottomSheetState . HalfExpanded ;
15031509 }
15041510 else
15051511 {
1506- State = BottomSheetState . Collapsed ;
1512+ if ( State is not BottomSheetState . Collapsed )
1513+ {
1514+ State = BottomSheetState . Collapsed ;
1515+ }
1516+ else
1517+ {
1518+ Show ( ) ;
1519+ }
15071520 }
15081521 }
15091522
@@ -1519,12 +1532,7 @@ void UpdateStateChanged(BottomSheetState oldState, BottomSheetState newState)
15191532 {
15201533 _stateChangedEventArgs . OldState = oldState ;
15211534 _stateChangedEventArgs . NewState = newState ;
1522- if ( _overlayGrid is not null )
1523- {
1524- _overlayGrid . IsVisible = ( State is BottomSheetState . Collapsed ) ? false : IsModal ;
1525- }
1526-
1527- OnStateChanged ( _stateChangedEventArgs ) ;
1535+ OnStateChanged ( _stateChangedEventArgs ) ;
15281536 }
15291537 }
15301538
@@ -1611,12 +1619,7 @@ double GetFullExpandedPosition()
16111619 double GetCollapsedPosition ( )
16121620 {
16131621 double targetPosition = Height - CollapsedHeight ;
1614- if ( _overlayGrid is not null )
1615- {
1616- _overlayGrid . IsVisible = false ;
1617- }
1618-
1619- return targetPosition ;
1622+ return targetPosition ;
16201623 }
16211624
16221625 /// <summary>
@@ -1645,23 +1648,68 @@ double GetHalfExpandedPosition()
16451648 /// <param name="onFinish">Optional action to be executed when the animation finishes.</param>
16461649 void AnimateBottomSheet ( double targetPosition , Action ? onFinish = null )
16471650 {
1648- const int AnimationDuration = 150 ;
1649- const int topPadding = 2 ;
1651+ if ( _bottomSheet . AnimationIsRunning ( "bottomSheetAnimation" ) )
1652+ {
1653+ _bottomSheet . AbortAnimation ( "bottomSheetAnimation" ) ;
1654+ }
1655+
1656+ if ( _overlayGrid . AnimationIsRunning ( "overlayGridAnimation" ) )
1657+ {
1658+ _overlayGrid . AbortAnimation ( "overlayGridAnimation" ) ;
1659+ }
16501660
1661+ const int animationDuration = 150 ;
1662+ const int topPadding = 2 ;
1663+ _isSheetOpen = true ;
16511664 if ( _bottomSheet is not null )
16521665 {
16531666 var bottomSheetAnimation = new Animation ( d => _bottomSheet . TranslationY = d , _bottomSheet . TranslationY , targetPosition + topPadding ) ;
1654- _bottomSheet ? . Animate ( "bottomSheetAnimation" , bottomSheetAnimation , length : AnimationDuration , easing : Easing . Linear , finished : ( v , e ) =>
1667+ _bottomSheet ? . Animate ( "bottomSheetAnimation" , bottomSheetAnimation , length : animationDuration , easing : Easing . Linear , finished : ( v , e ) =>
16551668 {
16561669 UpdateBottomSheetHeight ( ) ;
16571670 onFinish ? . Invoke ( ) ;
16581671 } ) ;
16591672 }
16601673
1674+ AnimateOverlay ( animationDuration ) ;
1675+ }
1676+
1677+ /// <summary>
1678+ /// Animates the overlay of the bottom sheet based on state transitions.
1679+ /// </summary>
1680+ void AnimateOverlay ( int animationDuration )
1681+ {
16611682 if ( _overlayGrid is not null )
16621683 {
1663- var overlayGridAnimation = new Animation ( d => _overlayGrid . Opacity = d , _overlayGrid . Opacity , _isSheetOpen ? DefaultOverlayOpacity : 0 ) ;
1664- _overlayGrid ? . Animate ( "overlayGridAnimation" , overlayGridAnimation , length : AnimationDuration , easing : Easing . Linear ) ;
1684+ double startValue = 0 ;
1685+ double endValue = 0 ;
1686+ _overlayGrid . IsVisible = IsModal ;
1687+
1688+ if ( IsModal )
1689+ {
1690+ if ( State is BottomSheetState . Collapsed || State is BottomSheetState . Hidden )
1691+ {
1692+ startValue = _overlayGrid . Opacity ;
1693+ endValue = 0 ;
1694+ }
1695+ else
1696+ {
1697+ startValue = _overlayGrid . Opacity ;
1698+ endValue = DefaultOverlayOpacity ;
1699+ }
1700+
1701+ var overlayGridAnimation = new Animation ( d => _overlayGrid . Opacity = d , startValue , endValue ) ;
1702+ _overlayGrid . Animate ( "overlayGridAnimation" , overlayGridAnimation ,
1703+ length : ( uint ) animationDuration ,
1704+ easing : Easing . Linear ,
1705+ finished : ( e , v ) =>
1706+ {
1707+ if ( State is BottomSheetState . Collapsed || State is BottomSheetState . Hidden )
1708+ {
1709+ _overlayGrid . IsVisible = false ;
1710+ }
1711+ } ) ;
1712+ }
16651713 }
16661714 }
16671715
@@ -1767,14 +1815,31 @@ bool ShouldRestrictMovement(double newTranslationY, double diffY)
17671815 return false ;
17681816 }
17691817
1770- bool isHalfExpandedAndRestricted = State is BottomSheetState . HalfExpanded &&
1818+ double endPosition = 0 ;
1819+ double updatedHeight = Height - newTranslationY ;
1820+ switch ( State )
1821+ {
1822+ case BottomSheetState . FullExpanded :
1823+ endPosition = Height * FullExpandedRatio ;
1824+ break ;
1825+
1826+ case BottomSheetState . HalfExpanded :
1827+ endPosition = Height * HalfExpandedRatio ;
1828+ break ;
1829+
1830+ case BottomSheetState . Collapsed :
1831+ endPosition = CollapsedHeight ;
1832+ break ;
1833+ }
1834+
1835+ bool isHalfExpandedAndRestricted = State is BottomSheetState . HalfExpanded &&
17711836 AllowedState is BottomSheetAllowedState . HalfExpanded &&
1772- _bottomSheet . TranslationY > newTranslationY ;
1837+ updatedHeight > endPosition ;
17731838
1774- bool isCollapsedAndMovingDown = State is BottomSheetState . Collapsed && diffY > 0 ;
1839+ bool isCollapsedAndMovingDown = State is BottomSheetState . Collapsed && updatedHeight < endPosition ;
17751840
17761841 bool isFullExpandedRestricted = State is BottomSheetState . FullExpanded &&
1777- _bottomSheet . TranslationY > newTranslationY ;
1842+ updatedHeight > endPosition ;
17781843
17791844 bool isBehind = ( newTranslationY > Height - CollapsedHeight ) || ( newTranslationY < Height * ( 1 - FullExpandedRatio ) ) ;
17801845
@@ -1789,14 +1854,35 @@ AllowedState is BottomSheetAllowedState.HalfExpanded &&
17891854 /// <param name="touchY">The current Y coordinate of the touch point.</param>
17901855 void UpdateBottomSheetPosition ( double newTranslationY , double touchY )
17911856 {
1792- if ( _bottomSheet is null )
1857+ if ( _bottomSheet is null || _overlayGrid is null )
17931858 {
17941859 return ;
17951860 }
17961861
17971862 _bottomSheet . TranslationY = newTranslationY ;
17981863 _initialTouchY = touchY ;
17991864 _bottomSheet . HeightRequest = Height - newTranslationY ;
1865+ _overlayGrid . IsVisible = IsModal && ( _bottomSheet . HeightRequest > CollapsedHeight ) ;
1866+ _overlayGrid . Opacity = CalculateOverlayOpacity ( _bottomSheet . HeightRequest ) ;
1867+ }
1868+
1869+ /// <summary>
1870+ /// Calculates the overlay opacity based on the current height of the bottom sheet.
1871+ /// </summary>
1872+ /// <param name="currentHeight">The current height of the bottom sheet.</param>
1873+ /// <returns>The calculated opacity value ranging from 0 to 0.5</returns>
1874+ double CalculateOverlayOpacity ( double currentHeight )
1875+ {
1876+ const double maxOpacity = 0.5 ;
1877+
1878+ // Calculate how far along the transition from collapsed to half-expanded.
1879+ double transitionProgress = ( currentHeight - CollapsedHeight ) / ( ( HalfExpandedRatio * Height ) - CollapsedHeight ) ;
1880+
1881+ // Clamp the transition progress to between 0 and 1.
1882+ transitionProgress = Math . Clamp ( transitionProgress , 0 , 1 ) ;
1883+
1884+ // Calculate and return the opacity based on the transition progress.
1885+ return transitionProgress * maxOpacity ;
18001886 }
18011887
18021888 /// <summary>
@@ -1809,7 +1895,10 @@ void HandleTouchReleased(double touchY)
18091895 _initialTouchY = 0 ;
18101896 _isPointerPressed = false ;
18111897
1812- UpdatePosition ( ) ;
1898+ if ( _bottomSheet is not null && touchY >= _bottomSheet . TranslationY )
1899+ {
1900+ UpdatePosition ( ) ;
1901+ }
18131902 }
18141903
18151904
@@ -1940,9 +2029,10 @@ static void OnIsModalPropertyChanged(BindableObject bindable, object oldValue, o
19402029 {
19412030 if ( bindable is SfBottomSheet sheet )
19422031 {
1943- if ( sheet . _overlayGrid is not null )
2032+ if ( sheet . _overlayGrid is not null && ( sheet . State is BottomSheetState . FullExpanded || sheet . State is BottomSheetState . HalfExpanded ) )
19442033 {
19452034 sheet . _overlayGrid . IsVisible = sheet . IsModal ;
2035+ sheet . AnimateOverlay ( 150 ) ;
19462036 }
19472037 }
19482038 }
@@ -2035,7 +2125,7 @@ static void OnStatePropertyChanged(BindableObject bindable, object oldValue, obj
20352125
20362126 if ( newState == BottomSheetState . Hidden )
20372127 {
2038- sheet . _isHalfExpanded = true ;
2128+ sheet . _isHalfExpanded = ( sheet . AllowedState != BottomSheetAllowedState . FullExpanded ) ;
20392129 if ( sheet . _isSheetOpen )
20402130 {
20412131 sheet . _isSheetOpen = false ;
0 commit comments