Reputation: 900
Is there a way to prevent the propagation of swipe gestures from a control onto its parent control in .NET MAUI?
For this project I'm using a DXRangeSlider
within a TabView
. Both are free MAUI controls (at the time of writing) created by DevExpress. Nonetheless, any swipable control that is defined as content for the tab view, causes this issue.
When TabView.SwipeEnabled = True
you can swipe left or right on the tab content to navigate to the previous or next tab in the sequence. When any of the tab contents contain swipable controls, you cannot swipe these controls without calling the tab swipe action.
I'd like the TabView
to ignore my swipe gesture when the swipe gesture is targeting a child control.
Is there any way to achieve this?
The XAML setup is nothing too complicated:
<dxcontrols:TabView>
<dxcontrols:TabViewItem>
...
</dxcontrols:TabViewItem>
<!-- Parent swipable control: -->
<dxcontrols:TabViewItem>
...
<!-- Child swipable control: -->
<dxeditors:DXRangeSlider/>
...
</dxcontrols:TabViewItem>
<dxcontrols:TabViewItem>
...
</dxcontrols:TabViewItem>
</dxcontrols:TabView>
I believe the same issue would exist when using a MAUI Slider
or any control with swipe gesture recognizers within a CarouselView
that has swipe enabled.
Upvotes: 1
Views: 432
Reputation: 900
In addition to LiyunZhangs' answer:
I figured out specificially for DX Slider controls (thanks to their support center), that they have TapPressed
and TapReleased
events, that you can use to set the TabView.SwipeEnabled
property to false
while using the slider and back to true
when the tap is released.
1. Simply set the events on the DXSlider
or DXRangeSlider
control:
<dxcontrols:TabView x:Name="FilterTabView">
<dxcontrols:TabViewItem>
<!-- ... content ... -->
</dxcontrols:TabViewItem>
<dxcontrols:TabViewItem>
<dxeditors:DXRangeSlider
TapPressed="DXRangeSlider_TapPressed"
TapReleased="DXRangeSlider_TapReleased"/>
</dxcontrols:TabViewItem>
<dxcontrols:TabViewItem>
<!-- ... content ... -->
</dxcontrols:TabViewItem>
</dxcontrols:TabView>
2. Then use the event handlers to change TabView.SwipeEnabled
in code-behind:
private void DXRangeSlider_TapPressed(object sender, DevExpress.Maui.Core.DXTapEventArgs e)
{
FilterTabView.SwipeEnabled = false;
}
private void DXRangeSlider_TapReleased(object sender, DevExpress.Maui.Core.DXTapEventArgs e)
{
FilterTabView.SwipeEnabled = true;
}
For MVVM you can use MCT EventToCommandBehavior
to use commanding instead:
<dxeditors:DXRangeSlider>
<dxeditors:DXRangeSlider.Behaviors>
<toolkit:EventToCommandBehavior
EventName="TapPressed"
Command="{Binding TapPressedCommand}"/>
<toolkit:EventToCommandBehavior
EventName="TapReleased"
Command="{Binding TapReleasedCommand}"/>
</dxeditors:DXRangeSlider.Behaviors>
</dxeditors:DXRangeSlider>
I believe LiyunZhangs' answer gets closer to the ideal solution, because it is a more generic approach for all MAUI controls. I just thought this might be useful for others who use the same DX controls.
Upvotes: 1
Reputation: 14434
I believe the same issue would exist when using a MAUI Slider or any control with swipe gesture recognizers within a CarouselView that has swipe enabled.
Yes, there is the same issue. And I can resolve it by adding IOnTouchListener
for the android native view. And prevent passing the swipe event from the child view to the parent view.
The Listener:
public class SliderListener : Java.Lang.Object, IOnTouchListener
{
public bool OnTouch(global::Android.Views.View v, MotionEvent e)
{
if (e.Action == MotionEventActions.Down || e.Action == MotionEventActions.Move)
{
v.Parent.RequestDisallowInterceptTouchEvent(true);
// prevent the parent view get the swipe event
}
else
{
v.Parent.RequestDisallowInterceptTouchEvent(false);
}
return false;
}
}
And then you can add the Listener
for the Slider in the code behind or custom handler.
1. In the code behind: the slider have a name in the xaml such as : <Slider x:Name="slider">
. And in the code behind:
protected override void OnHandlerChanged()
{
base.OnHandlerChanged();
#if ANDROID
(slider.Handler.PlatformView as Android.Widget.Seekbar)
.SetOnTouchListener(new SliderListener());
#endif
}
2. Set it in the custom handler: You can refer to the official document about Customize controls with handlers. And do this in the Custom Handler's ConnectHandler
method.
protected override void ConnectHandler(SeekBar platformView)
{
base.ConnectHandler(platformView);
platformView.SetOnTouchListener(new SliderListener());
}
You can check the source code about the DXRangeSlider
or just debug to get the platform view. And then using the same method to resolve the issue.
Upvotes: 1