Skip to content

Commit

Permalink
Implemnt touch interception on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
mattleibow committed Sep 6, 2023
1 parent 3c1d3ba commit 040c1a5
Show file tree
Hide file tree
Showing 9 changed files with 402 additions and 21 deletions.
176 changes: 176 additions & 0 deletions src/Controls/samples/Controls.Sample.Sandbox/MainPage.xaml
Expand Up @@ -3,4 +3,180 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.MainPage"
xmlns:local="clr-namespace:Maui.Controls.Sample">

<ScrollView>
<VerticalStackLayout Background="White" Spacing="20">

<VerticalStackLayout Padding="20" Background="Pink">

<Label Text="CollectionView Items" />

<Label x:Name="collectionViewLabel" />

<CollectionView SelectionChanged="CollectionView_SelectionChanged"
SelectionMode="Single"
HeightRequest="200">
<CollectionView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Wednesday</x:String>
<x:String>Friday</x:String>
</x:Array>
</CollectionView.ItemsSource>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="20" Background="Orange">
<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Background="Red" Opacity="0.2" Margin="10,10,0,10"/>
</Grid>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink">

<Label Text="ListView Items" />

<Label x:Name="listViewLabel" />

<ListView ItemSelected="ListView_ItemSelected"
SelectionMode="Single"
HeightRequest="200">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Wednesday</x:String>
<x:String>Friday</x:String>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="20" Background="Orange">
<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Background="Red" Opacity="0.2" Margin="10,10,0,10"/>
</Grid>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Grid" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Margin="10,10,0,10"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Grid (InputTransparent=True)" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Margin="10,10,0,10" InputTransparent="True"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Grid (InputTransparent=False)" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Margin="10,10,0,10" InputTransparent="False"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Grid with Backgound" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Grid Background="Red" Opacity="0.2" Margin="10,10,0,10"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Image" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Image Source="dotnet_bot.png" Opacity="0.2" Margin="10,10,0,10" HorizontalOptions="Center"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Image (InputTransparent=True)" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Image Source="dotnet_bot.png" Opacity="0.2" Margin="10,10,0,10" HorizontalOptions="Center" InputTransparent="True"/>
</Grid>

</VerticalStackLayout>

<VerticalStackLayout Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Image (InputTransparent=False)" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Image Source="dotnet_bot.png" Opacity="0.2" Margin="10,10,0,10" HorizontalOptions="Center" InputTransparent="False"/>
</Grid>

</VerticalStackLayout>

<Grid Padding="20" Background="Pink" HeightRequest="100">

<Label Text="Image with Background" />

<Grid HeightRequest="50" >
<Grid Margin="0,0,10,0">
<Button Text="Clicker" Clicked="myButton_Click" />
</Grid>
<Image Source="dotnet_bot.png" Opacity="0.2" Margin="10,10,0,10" Background="Cyan" HorizontalOptions="Center"/>
</Grid>

</Grid>

</VerticalStackLayout>

</ScrollView>

</ContentPage>
15 changes: 15 additions & 0 deletions src/Controls/samples/Controls.Sample.Sandbox/MainPage.xaml.cs
Expand Up @@ -14,5 +14,20 @@ public MainPage()
{
InitializeComponent();
}

private void myButton_Click(object sender, EventArgs e)
{
(sender as Button).Text = DateTime.Now.ToString();
}

private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
collectionViewLabel.Text = e.CurrentSelection[0].ToString();
}

private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
listViewLabel.Text = e.SelectedItem.ToString();
}
}
}
Expand Up @@ -374,7 +374,7 @@ bool IViewHandler.HasContainer
}

void SetupContainer() =>
WrapperView.SetupContainer(this, Context, _wrapperView, (cv) => _wrapperView = cv);
WrapperView.SetupContainer(Element, this, Context, _wrapperView, (cv) => _wrapperView = cv);

void RemoveContainer() =>
WrapperView.RemoveContainer(this, Context, _wrapperView, () => _wrapperView = null);
Expand Down
6 changes: 6 additions & 0 deletions src/Core/src/Handlers/Image/ImageHandler.Android.cs
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Android.Graphics.Drawables;
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.Widget;
using Google.Android.Material.Button;
Expand All @@ -18,12 +19,17 @@ protected override ImageView CreatePlatformView()
// measurement passes.
imageView.SetAdjustViewBounds(true);

// Non-interactive controls also need to "block" touch events if they are covering
// other interactive controls.
TouchEventInterceptor.ConnectListener(VirtualView, imageView);

return imageView;
}

protected override void DisconnectHandler(ImageView platformView)
{
base.DisconnectHandler(platformView);
TouchEventInterceptor.DisconnectListener(platformView);
SourceLoader.Reset();
}

Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs
Expand Up @@ -18,7 +18,7 @@ public partial class ViewHandler<TVirtualView, TPlatformView> : IPlatformViewHan
this.GetDesiredSizeFromHandler(widthConstraint, heightConstraint);

protected override void SetupContainer() =>
WrapperView.SetupContainer(PlatformView, Context, ContainerView, (cv) => ContainerView = cv);
WrapperView.SetupContainer(VirtualView, PlatformView, Context, ContainerView, (cv) => ContainerView = cv);

protected override void RemoveContainer() =>
WrapperView.RemoveContainer(PlatformView, Context, ContainerView, () => ContainerView = null);
Expand Down
28 changes: 19 additions & 9 deletions src/Core/src/Platform/Android/LayoutViewGroup.cs
Expand Up @@ -11,11 +11,15 @@

namespace Microsoft.Maui.Platform
{
public class LayoutViewGroup : ViewGroup, ICrossPlatformLayoutBacking, IVisualTreeElementProvidable
public class LayoutViewGroup : ViewGroup, ICrossPlatformLayoutBacking, IVisualTreeElementProvidable, ITouchInterceptingView
{
readonly ARect _clipRect = new();
readonly Context _context;

WeakReference<IOnTouchListener>? _touchListener;

bool ITouchInterceptingView.TouchEventNotReallyHandled { get; set; }

public bool InputTransparent { get; set; }

public LayoutViewGroup(Context context) : base(context)
Expand Down Expand Up @@ -52,6 +56,8 @@ public LayoutViewGroup(Context context, IAttributeSet attrs, int defStyleAttr, i
get; set;
}

internal IView? VirtualView => CrossPlatformLayout as IView;

Graphics.Size CrossPlatformMeasure(double widthConstraint, double heightConstraint)
{
return CrossPlatformLayout?.CrossPlatformMeasure(widthConstraint, heightConstraint) ?? Graphics.Size.Zero;
Expand Down Expand Up @@ -122,17 +128,21 @@ protected override void OnLayout(bool changed, int l, int t, int r, int b)
}
}

public override bool OnTouchEvent(MotionEvent? e)
public override void SetOnTouchListener(IOnTouchListener? l)
{
if (InputTransparent)
{
return false;
}

return base.OnTouchEvent(e);
_touchListener = l is null ? null : new(l);
base.SetOnTouchListener(l);
}

IVisualTreeElement? IVisualTreeElementProvidable.GetElement()
public override bool OnTouchEvent(MotionEvent? e) =>
base.OnTouchEvent(e) || TouchEventInterceptor.OnTouchEvent(VirtualView, this, e);

public override bool DispatchTouchEvent(MotionEvent? e) =>
TouchEventInterceptor.DispatchingTouchEvent(this, e) &&
base.DispatchTouchEvent(e) &&
TouchEventInterceptor.DispatchedTouchEvent(this, e, _touchListener?.GetTargetOrDefault());

IVisualTreeElement ? IVisualTreeElementProvidable.GetElement()
{
if (CrossPlatformLayout is IVisualTreeElement layoutElement &&
layoutElement.IsThisMyPlatformView(this))
Expand Down

0 comments on commit 040c1a5

Please sign in to comment.