diff --git a/maui/src/BottomSheet/SfBottomSheet.cs b/maui/src/BottomSheet/SfBottomSheet.cs
index 789f3267..a1ef3b35 100644
--- a/maui/src/BottomSheet/SfBottomSheet.cs
+++ b/maui/src/BottomSheet/SfBottomSheet.cs
@@ -1,4 +1,4 @@
-using Microsoft.Maui.Controls.Shapes;
+using Microsoft.Maui.Controls.Shapes;
using Syncfusion.Maui.Toolkit.Internals;
using Syncfusion.Maui.Toolkit.Themes;
using Syncfusion.Maui.Toolkit.Helper;
@@ -74,11 +74,16 @@ public partial class SfBottomSheet : SfView, IParentThemeElement
///
bool _isPointerPressed;
- // Touch tracking
- ///
- /// The initial Y-coordinate of a touch event on the bottom sheet.
- ///
- double _initialTouchY;
+ ///
+ /// Indicates whether the overlay grid is currently added to the view hierarchy.
+ ///
+ bool _isOverlayAdded;
+
+ // Touch tracking
+ ///
+ /// The initial Y-coordinate of a touch event on the bottom sheet.
+ ///
+ double _initialTouchY;
///
/// The starting Y-coordinate of a swipe gesture on the bottom sheet.
@@ -1242,7 +1247,7 @@ internal Color OverlayBackgroundColor
///
public void Show()
{
- if (_bottomSheet is null || _overlayGrid is null)
+ if (_bottomSheet is null)
{
return;
}
@@ -1267,7 +1272,7 @@ public void Show()
///
public void Close()
{
- if(_bottomSheet is null || _overlayGrid is null)
+ if(_bottomSheet is null)
{
return;
}
@@ -1275,7 +1280,7 @@ public void Close()
AnimateBottomSheet(Height, onFinish: () =>
{
_bottomSheet.IsVisible = false;
- _overlayGrid.IsVisible = false;
+ RemoveOverlayFromView();
});
if (_isSheetOpen)
@@ -1356,9 +1361,8 @@ void InitializeLayout()
InitializeBottomSheetBorder();
InitializeContentBorder();
- if (_bottomSheet is not null && _overlayGrid is not null)
+ if (_bottomSheet is not null)
{
- Children.Add(_overlayGrid);
Children.Add(_bottomSheet);
_bottomSheet.IsVisible = false;
}
@@ -1370,6 +1374,7 @@ void InitializeLayout()
void UpdateContentView()
{
Children.Clear();
+ _isOverlayAdded = false; // Reset overlay state
UpdateAllChild();
}
@@ -1379,7 +1384,6 @@ void UpdateContentView()
void UpdateAllChild()
{
AddChild(Content);
- AddChild(_overlayGrid);
AddChild(_bottomSheet);
}
@@ -1404,7 +1408,7 @@ void InitializeOverlayGrid()
{
BackgroundColor = OverlayBackgroundColor,
Opacity = DefaultOverlayOpacity,
- IsVisible = false
+ IsVisible = true
};
var tapGestureRecognizer = new TapGestureRecognizer();
@@ -1485,6 +1489,36 @@ void InitializeBottomSheetBorder()
};
}
+ ///
+ /// Adds the overlay grid to the view hierarchy if it's not already added and modal is enabled.
+ ///
+ void AddOverlayToView()
+ {
+ if (_overlayGrid is not null && IsModal && !_isOverlayAdded)
+ {
+ if (!Children.Contains(_overlayGrid))
+ {
+ Children.Insert(Children.Count - 1, _overlayGrid); // Insert before bottom sheet
+ }
+ _isOverlayAdded = true;
+ }
+ }
+
+ ///
+ /// Removes the overlay grid from the view hierarchy.
+ ///
+ void RemoveOverlayFromView()
+ {
+ if (_overlayGrid is not null && _isOverlayAdded)
+ {
+ if (Children.Contains(_overlayGrid))
+ {
+ Children.Remove(_overlayGrid);
+ }
+ _isOverlayAdded = false;
+ }
+ }
+
///
/// Calculates the initial height for the half-expanded state.
///
@@ -2040,7 +2074,7 @@ void RegisterSizeChangedEvent()
///
void SetupBottomSheetForShow()
{
- if (_isSheetOpen || _bottomSheet is null || _overlayGrid is null)
+ if (_isSheetOpen || _bottomSheet is null)
{
return;
}
@@ -2048,8 +2082,12 @@ void SetupBottomSheetForShow()
// Position the bottom sheet just below the visible area
_bottomSheet.TranslationY = Height;
_bottomSheet.IsVisible = true;
- _overlayGrid.IsVisible = IsModal;
- _overlayGrid.Opacity = 0;
+
+ // Add overlay to view if modal
+ if (IsModal)
+ {
+ AddOverlayToView();
+ }
}
@@ -2133,11 +2171,6 @@ void AnimateBottomSheet(double targetPosition, Action? onFinish = null)
_bottomSheet.AbortAnimation("bottomSheetAnimation");
}
- if (_overlayGrid.AnimationIsRunning("overlayGridAnimation"))
- {
- _overlayGrid.AbortAnimation("overlayGridAnimation");
- }
-
int animationDuration = this.GetClampedAnimationDuration();
const int topPadding = 2;
_isSheetOpen = true;
@@ -2159,46 +2192,45 @@ void AnimateBottomSheet(double targetPosition, Action? onFinish = null)
///
void AnimateOverlay(int animationDuration)
{
- if (_overlayGrid is not null)
+ if (_overlayGrid is null || !IsModal)
{
- double startValue = 0;
- double endValue = 0;
- _overlayGrid.IsVisible = IsModal;
+ return;
+ }
- if (IsModal)
+ // Ensure overlay is added to view when needed
+ bool shouldShowOverlay = State is not (BottomSheetState.Collapsed or BottomSheetState.Hidden);
+
+ if (shouldShowOverlay)
+ {
+ AddOverlayToView();
+ }
+
+ if (_overlayGrid.AnimationIsRunning("overlayGridAnimation"))
+ {
+ _overlayGrid.AbortAnimation("overlayGridAnimation");
+ }
+
+ double startValue = _overlayGrid.Opacity;
+ double endValue = shouldShowOverlay ? DefaultOverlayOpacity : 0;
+
+ var overlayGridAnimation = new Animation(d =>
+ {
+ if (!double.IsNaN(d))
{
- if (State is BottomSheetState.Collapsed || State is BottomSheetState.Hidden)
- {
- startValue = _overlayGrid.Opacity;
- endValue = 0;
- }
- else
- {
- startValue = _overlayGrid.Opacity;
- endValue = DefaultOverlayOpacity;
- }
+ _overlayGrid.Opacity = d;
+ }
+ }, startValue, endValue);
- var overlayGridAnimation = new Animation(d =>
+ _overlayGrid.Animate("overlayGridAnimation", overlayGridAnimation,
+ length: (uint)animationDuration,
+ easing: Easing.Linear,
+ finished: (v, c) =>
+ {
+ if (!shouldShowOverlay)
{
- // Ensure the opacity is only updated with valid numeric values to avoid rendering issues.
- if (!double.IsNaN(d))
- {
- _overlayGrid.Opacity = d;
- }
+ RemoveOverlayFromView();
}
- , startValue, endValue);
- _overlayGrid.Animate("overlayGridAnimation", overlayGridAnimation,
- length: (uint)animationDuration,
- easing: Easing.Linear,
- finished: (e, v) =>
- {
- if (State is BottomSheetState.Collapsed || State is BottomSheetState.Hidden)
- {
- _overlayGrid.IsVisible = false;
- }
- });
- }
- }
+ });
}
///
@@ -2342,7 +2374,7 @@ AllowedState is BottomSheetAllowedState.HalfExpanded &&
/// The current Y coordinate of the touch point.
void UpdateBottomSheetPosition(double newTranslationY, double touchY)
{
- if (_bottomSheet is null || _overlayGrid is null)
+ if (_bottomSheet is null)
{
return;
}
@@ -2350,8 +2382,21 @@ void UpdateBottomSheetPosition(double newTranslationY, double touchY)
_bottomSheet.TranslationY = newTranslationY;
_initialTouchY = touchY;
_bottomSheet.HeightRequest = Height - newTranslationY;
- _overlayGrid.IsVisible = IsModal && (_bottomSheet.HeightRequest > CollapsedHeight);
- _overlayGrid.Opacity = CalculateOverlayOpacity(_bottomSheet.HeightRequest);
+ // Manage overlay visibility during touch
+ bool shouldShowOverlay = IsModal && (_bottomSheet.HeightRequest > CollapsedHeight);
+
+ if (shouldShowOverlay)
+ {
+ AddOverlayToView();
+ if (_overlayGrid is not null)
+ {
+ _overlayGrid.Opacity = CalculateOverlayOpacity(_bottomSheet.HeightRequest);
+ }
+ }
+ else
+ {
+ RemoveOverlayFromView();
+ }
}
///
@@ -2517,12 +2562,18 @@ static void OnIsModalPropertyChanged(BindableObject bindable, object oldValue, o
{
if (bindable is SfBottomSheet sheet)
{
- if (sheet._overlayGrid is not null && (sheet.State is BottomSheetState.FullExpanded || sheet.State is BottomSheetState.HalfExpanded))
- {
- sheet._overlayGrid.IsVisible = sheet.IsModal;
+ bool isModal = (bool)newValue;
+
+ if (isModal && (sheet.State is BottomSheetState.FullExpanded or BottomSheetState.HalfExpanded))
+ {
+ sheet.AddOverlayToView();
sheet.AnimateOverlay(150);
- }
- }
+ }
+ else if (!isModal)
+ {
+ sheet.RemoveOverlayFromView();
+ }
+ }
}
diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Navigation/SfBottomSheetUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Navigation/SfBottomSheetUnitTests.cs
index 28c58c3c..d2c224a1 100644
--- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Navigation/SfBottomSheetUnitTests.cs
+++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Navigation/SfBottomSheetUnitTests.cs
@@ -38,7 +38,7 @@ public void Constructor_InitializesDefaultsCorrectly()
Assert.Equal(4d, _bottomSheet.GrabberHeight);
Assert.Equal(32d, _bottomSheet.GrabberWidth);
Assert.Equal(12d, _bottomSheet.GrabberCornerRadius);
- Assert.Equal(150d, _bottomSheet.AnimationDuration);
+ Assert.Equal(150d,_bottomSheet.AnimationDuration);
if (_bottomSheet.GrabberBackground is SolidColorBrush grabberBrush)
{
var grabberColor = grabberBrush.Color;
@@ -564,7 +564,7 @@ public void InitializeLayout()
var bottomSheet = GetPrivateField(_bottomSheet, "_bottomSheet");
var overlayGrid = GetPrivateField(_bottomSheet, "_overlayGrid");
Assert.True(_bottomSheet.Children?.Contains(bottomSheet));
- Assert.True(_bottomSheet.Children?.Contains(overlayGrid));
+ Assert.False(_bottomSheet.Children?.Contains(overlayGrid));
}
[Fact]
@@ -592,7 +592,7 @@ public void InitializeOverlayGrid()
Grid? overlayGrid = (Grid?)GetPrivateField(_bottomSheet, "_overlayGrid");
Assert.Equal(overlayGrid?.BackgroundColor, Color.FromArgb("#80000000"));
Assert.Equal(overlayGrid?.Opacity, 0.5);
- Assert.Equal(overlayGrid?.IsVisible, false);
+ Assert.Equal(overlayGrid?.IsVisible, true);
}
[Fact]
@@ -852,7 +852,7 @@ public void UpdateStateChanged(BottomSheetState oldState, BottomSheetState newSt
[Theory]
[InlineData(true, true)]
- [InlineData(false, false)]
+ [InlineData(false, true)]
public void SetupBottomSheetForShow(bool input, bool expected)
{
_bottomSheet.IsModal = input;
@@ -860,7 +860,7 @@ public void SetupBottomSheetForShow(bool input, bool expected)
SfGrid? overlay = (SfGrid?)GetPrivateField(_bottomSheet, "_overlayGrid");
SfBorder? bottomsheet = (SfBorder?)GetPrivateField(_bottomSheet, "_bottomSheet");
Assert.True(bottomsheet?.IsVisible);
- Assert.Equal(0, overlay?.Opacity);
+ Assert.Equal(0.5, overlay?.Opacity);
Assert.Equal(expected, overlay?.IsVisible);
}
@@ -868,8 +868,8 @@ public void SetupBottomSheetForShow(bool input, bool expected)
public void GetCollapsedPosition()
{
InvokePrivateMethod(_bottomSheet, "GetCollapsedPosition");
- SfGrid? overlay = (SfGrid?)GetPrivateField(_bottomSheet, "_overlayGrid");
- Assert.False(overlay?.IsVisible);
+ var overlay = GetPrivateField(_bottomSheet, "_overlayGrid");
+ Assert.False(_bottomSheet.Children?.Contains(overlay));
}
[Fact]