Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit fac80b2

Browse files
AndreiMisiukevichjsuarezruiz
authored andcommitted
[Android] Fix SideMenuView + Slider issue (#824)
* [Android] Allow using slider inside SideMenu with disabled gestures #810 * Refactored gesture default threshold #810 * Cleaned code. Added linker safety code * Fixed build Co-authored-by: Javier Suárez <[email protected]>
1 parent cec8472 commit fac80b2

File tree

4 files changed

+86
-61
lines changed

4 files changed

+86
-61
lines changed

samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,32 @@
1616

1717
<xct:SideMenuView x:Name="SideMenuView">
1818
<!-- MainView -->
19-
<StackLayout
20-
Orientation="Horizontal"
21-
BackgroundColor="Gold">
19+
<StackLayout BackgroundColor="Gold">
20+
<StackLayout
21+
Orientation="Horizontal">
2222

23-
<Button Style="{StaticResource BaseMenuButtonStyle}"
24-
Clicked="OnLeftButtonClicked" />
23+
<Button Style="{StaticResource BaseMenuButtonStyle}"
24+
Clicked="OnLeftButtonClicked" />
2525

26-
<Button Style="{StaticResource BaseMenuButtonStyle}"
27-
HorizontalOptions="EndAndExpand"
28-
Clicked="OnRightButtonClicked" />
26+
<Button Style="{StaticResource BaseMenuButtonStyle}"
27+
HorizontalOptions="EndAndExpand"
28+
Clicked="OnRightButtonClicked" />
29+
30+
</StackLayout>
31+
<Slider />
2932
</StackLayout>
3033

3134
<!-- LeftMenu -->
3235
<BoxView
33-
BackgroundColor="Orange"
3436
xct:SideMenuView.Position="LeftMenu"
35-
xct:SideMenuView.MenuWidthPercentage=".5" />
37+
xct:SideMenuView.MenuWidthPercentage=".5"
38+
BackgroundColor="Orange"/>
3639

3740
<!-- RightMenu -->
3841
<BoxView
39-
BackgroundColor="LightGreen"
4042
xct:SideMenuView.Position="RightMenu"
41-
xct:SideMenuView.MenuWidthPercentage=".3" />
43+
xct:SideMenuView.MenuWidthPercentage=".3"
44+
BackgroundColor="LightGreen" />
4245

4346
</xct:SideMenuView>
4447

src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,11 @@ public static readonly BindableProperty CurrentGestureShiftProperty
6767
= BindableProperty.Create(nameof(CurrentGestureShift), typeof(double), typeof(SideMenuView), 0.0, BindingMode.OneWayToSource);
6868

6969
public static readonly BindableProperty GestureThresholdProperty
70-
= BindableProperty.Create(nameof(GestureThreshold), typeof(double), typeof(SideMenuView), 7.0);
70+
= BindableProperty.Create(nameof(GestureThreshold), typeof(double), typeof(SideMenuView), -1.0);
7171

7272
public static readonly BindableProperty CancelVerticalGestureThresholdProperty
7373
= BindableProperty.Create(nameof(CancelVerticalGestureThreshold), typeof(double), typeof(SideMenuView), 1.0);
7474

75-
public static readonly BindableProperty AllowInterceptGestureProperty
76-
= BindableProperty.Create(nameof(AllowInterceptGesture), typeof(bool), typeof(SideMenuView), false);
77-
7875
public static readonly BindableProperty StateProperty
7976
= BindableProperty.Create(nameof(State), typeof(SideMenuState), typeof(SideMenuView), SideMenuState.MainViewShown, BindingMode.TwoWay, propertyChanged: OnStatePropertyChanged);
8077

@@ -90,36 +87,15 @@ public static readonly BindableProperty MenuWidthPercentageProperty
9087
public static readonly BindableProperty MenuGestureEnabledProperty
9188
= BindableProperty.CreateAttached(nameof(GetMenuGestureEnabled), typeof(bool), typeof(SideMenuView), true);
9289

93-
internal void OnPanUpdated(object sender, PanUpdatedEventArgs e)
90+
public SideMenuView()
9491
{
95-
var shift = e.TotalX;
96-
var verticalShift = e.TotalY;
97-
switch (e.StatusType)
98-
{
99-
case GestureStatus.Started:
100-
OnTouchStarted();
101-
return;
102-
case GestureStatus.Running:
103-
OnTouchChanged(shift, verticalShift);
104-
return;
105-
case GestureStatus.Canceled:
106-
case GestureStatus.Completed:
107-
if (Device.RuntimePlatform == Device.Android)
108-
OnTouchChanged(shift, verticalShift);
109-
110-
OnTouchEnded();
111-
return;
112-
}
113-
}
114-
115-
internal async void OnSwiped(SwipeDirection swipeDirection)
116-
{
117-
await Task.Delay(1);
118-
if (isGestureStarted)
119-
return;
120-
121-
var state = ResolveSwipeState(swipeDirection == SwipeDirection.Right);
122-
UpdateState(state, true);
92+
#if __ANDROID__
93+
if (System.DateTime.Now.Ticks < 0)
94+
_ = new Xamarin.CommunityToolkit.Android.UI.Views.SideMenuViewRenderer(null);
95+
#elif __IOS__
96+
if (System.DateTime.Now.Ticks < 0)
97+
_ = new Xamarin.CommunityToolkit.iOS.UI.Views.SideMenuViewRenderer();
98+
#endif
12399
}
124100

125101
public new ISideMenuList<View> Children
@@ -149,12 +125,6 @@ public double CancelVerticalGestureThreshold
149125
set => SetValue(CancelVerticalGestureThresholdProperty, value);
150126
}
151127

152-
public bool AllowInterceptGesture
153-
{
154-
get => (bool)GetValue(AllowInterceptGestureProperty);
155-
set => SetValue(AllowInterceptGestureProperty, value);
156-
}
157-
158128
public SideMenuState State
159129
{
160130
get => (SideMenuState)GetValue(StateProperty);
@@ -185,6 +155,46 @@ public static bool GetMenuGestureEnabled(BindableObject bindable)
185155
public static void SetMenuGestureEnabled(BindableObject bindable, bool value)
186156
=> bindable.SetValue(MenuGestureEnabledProperty, value);
187157

158+
internal void OnPanUpdated(object sender, PanUpdatedEventArgs e)
159+
{
160+
var shift = e.TotalX;
161+
var verticalShift = e.TotalY;
162+
switch (e.StatusType)
163+
{
164+
case GestureStatus.Started:
165+
OnTouchStarted();
166+
return;
167+
case GestureStatus.Running:
168+
OnTouchChanged(shift, verticalShift);
169+
return;
170+
case GestureStatus.Canceled:
171+
case GestureStatus.Completed:
172+
if (Device.RuntimePlatform == Device.Android)
173+
OnTouchChanged(shift, verticalShift);
174+
175+
OnTouchEnded();
176+
return;
177+
}
178+
}
179+
180+
internal async void OnSwiped(SwipeDirection swipeDirection)
181+
{
182+
await Task.Delay(1);
183+
if (isGestureStarted)
184+
return;
185+
186+
var state = ResolveSwipeState(swipeDirection == SwipeDirection.Right);
187+
UpdateState(state, true);
188+
}
189+
190+
internal bool CheckGestureEnabled(SideMenuPosition menuPosition)
191+
=> menuPosition switch
192+
{
193+
SideMenuPosition.LeftMenu => CheckMenuGestureEnabled(leftMenu),
194+
SideMenuPosition.RightMenu => CheckMenuGestureEnabled(rightMenu),
195+
_ => true
196+
};
197+
188198
protected override void OnControlInitialized(AbsoluteLayout control)
189199
{
190200
children.CollectionChanged += OnChildrenCollectionChanged;
@@ -548,5 +558,8 @@ void OnLayoutChanged(object sender, EventArgs e)
548558
Control.RaiseChild(mainView);
549559
Control.RaiseChild(overlayView);
550560
}
561+
562+
bool CheckMenuGestureEnabled(View menuView)
563+
=> menuView != null && GetMenuGestureEnabled(menuView);
551564
}
552565
}

src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.android.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212

1313
namespace Xamarin.CommunityToolkit.Android.UI.Views
1414
{
15-
[Preserve(AllMembers = true)]
15+
[Preserve(Conditional = true)]
1616
public class SideMenuViewRenderer : VisualElementRenderer<SideMenuView>
1717
{
18+
const double defaultGestureThreshold = 30.0;
19+
1820
static Guid? lastTouchHandlerId;
1921

2022
readonly float density;
@@ -31,14 +33,12 @@ public SideMenuViewRenderer(Context context)
3133
: base(context)
3234
=> density = context.Resources.DisplayMetrics.Density;
3335

36+
double GestureThreshold => Element.GestureThreshold >= 0
37+
? Element.GestureThreshold
38+
: defaultGestureThreshold;
39+
3440
public override bool OnInterceptTouchEvent(MotionEvent ev)
3541
{
36-
if (Element.AllowInterceptGesture)
37-
{
38-
base.OnInterceptTouchEvent(ev);
39-
return false;
40-
}
41-
4242
if (ev.ActionMasked == MotionEventActions.Move)
4343
{
4444
if (lastTouchHandlerId.HasValue && lastTouchHandlerId != elementId)
@@ -81,7 +81,10 @@ bool CheckIsTouchHandled(float xDelta, float yDelta)
8181
{
8282
var xDeltaAbs = Abs(xDelta);
8383
var yDeltaAbs = Abs(yDelta);
84-
var isHandled = xDeltaAbs > yDeltaAbs && xDeltaAbs > Element.GestureThreshold;
84+
var isHandled = xDeltaAbs > yDeltaAbs
85+
&& xDeltaAbs > GestureThreshold
86+
&& ((xDelta > 0 && Element.CheckGestureEnabled(SideMenuPosition.LeftMenu))
87+
|| (xDelta < 0 && Element.CheckGestureEnabled(SideMenuPosition.RightMenu)));
8588

8689
Parent?.RequestDisallowInterceptTouchEvent(isHandled);
8790
return isHandled;

src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.ios.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
namespace Xamarin.CommunityToolkit.iOS.UI.Views
1212
{
13-
[Preserve(AllMembers = true)]
13+
[Preserve(Conditional = true)]
1414
public class SideMenuViewRenderer : VisualElementRenderer<SideMenuView>
1515
{
16+
const double defaultGestureThreshold = 7.0;
17+
1618
UISwipeGestureRecognizer leftSwipeGestureRecognizer;
1719

1820
UISwipeGestureRecognizer rightSwipeGestureRecognizer;
@@ -32,7 +34,11 @@ public SideMenuViewRenderer()
3234
}
3335

3436
bool IsPanGestureHandled
35-
=> Abs(Element?.CurrentGestureShift ?? 0) >= Element?.GestureThreshold;
37+
=> Element != null && Abs(Element.CurrentGestureShift) >= GestureThreshold;
38+
39+
double GestureThreshold => Element.GestureThreshold >= 0
40+
? Element.GestureThreshold
41+
: defaultGestureThreshold;
3642

3743
public override void AddGestureRecognizer(UIGestureRecognizer gestureRecognizer)
3844
{

0 commit comments

Comments
 (0)