Skip to content

Commit

Permalink
Version 3.1.0, fixes touch events when unloading/reloading
Browse files Browse the repository at this point in the history
  • Loading branch information
roubachof committed Oct 18, 2024
1 parent 7c800e3 commit c60990f
Show file tree
Hide file tree
Showing 35 changed files with 597 additions and 318 deletions.
48 changes: 22 additions & 26 deletions Maui.Tabs/BottomTabItem.xaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>

<tabs:TabTextItem
x:Class="Sharpnado.Tabs.BottomTabItem"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:effects="clr-namespace:Sharpnado.Tabs.Effects"
xmlns:tabs="clr-namespace:Sharpnado.Tabs"
x:Name="RootLayout">
<tabs:TabTextItem x:Class="Sharpnado.Tabs.BottomTabItem"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:effects="clr-namespace:Sharpnado.Tabs.Effects"
xmlns:tabs="clr-namespace:Sharpnado.Tabs"
x:Name="RootLayout">

<ContentView.Resources>
<ResourceDictionary>
Expand All @@ -24,32 +23,29 @@
</ContentView.Resources>

<ContentView.Content>
<Grid
x:Name="Grid"
BackgroundColor="Transparent"
ColumnSpacing="0"
RowSpacing="0">
<Grid x:Name="Grid"
BackgroundColor="Transparent"
ColumnSpacing="0"
RowSpacing="0">

<Grid.RowDefinitions>
<RowDefinition x:Name="IconRowDefinition" Height="8*" />
<RowDefinition x:Name="TextRowDefinition" Height="5*" />
</Grid.RowDefinitions>

<Image
x:Name="Icon"
Grid.Row="0"
HeightRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
Source="{Binding Source={x:Reference RootLayout}, Path=IconImageSource}"
Style="{StaticResource TabIcon}"
WidthRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}" />
<Image x:Name="Icon"
Grid.Row="0"
Style="{StaticResource TabIcon}"
WidthRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
HeightRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
Source="{Binding Source={x:Reference RootLayout}, Path=IconImageSource}" />

<Label
x:Name="IconText"
Grid.Row="1"
FontFamily="{Binding Source={x:Reference RootLayout}, Path=FontFamily}"
FontSize="{Binding Source={x:Reference RootLayout}, Path=LabelSize}"
Style="{StaticResource TabIconLabel}"
Text="{Binding Source={x:Reference RootLayout}, Path=Label}" />
<Label x:Name="IconText"
Grid.Row="1"
Style="{StaticResource TabIconLabel}"
FontFamily="{Binding Source={x:Reference RootLayout}, Path=FontFamily}"
FontSize="{Binding Source={x:Reference RootLayout}, Path=LabelSize}"
Text="{Binding Source={x:Reference RootLayout}, Path=Label}" />
</Grid>
</ContentView.Content>
</tabs:TabTextItem>
13 changes: 12 additions & 1 deletion Maui.Tabs/Effects/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ public static object GetLongTapParameter(BindableObject view) {
return view.GetValue(LongTapParameterProperty);
}

public static void UnregisterEffect(BindableObject bindable)
{
if (!(bindable is View view))
return;

var eff = view.Effects.FirstOrDefault(e => e is CommandsRoutingEffect);

if (eff == null) return;
view.Effects.Remove(eff);
}

static void PropertyChanged(BindableObject bindable, object oldValue, object newValue) {
if (!(bindable is View view))
return;
Expand All @@ -93,7 +104,7 @@ static void PropertyChanged(BindableObject bindable, object oldValue, object new
}
}
else {
if (eff == null || view.BindingContext == null) return;
if (eff == null) return;
view.Effects.Remove(eff);
if (EffectsConfig.AutoChildrenInputTransparent && bindable is Layout &&
EffectsConfig.GetChildrenInputTransparent(view)) {
Expand Down
19 changes: 16 additions & 3 deletions Maui.Tabs/Effects/TouchEffect.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace Sharpnado.Tabs.Effects {
using Microsoft.Maui.Controls;

namespace Sharpnado.Tabs.Effects {

Check warning on line 3 in Maui.Tabs/Effects/TouchEffect.cs

View workflow job for this annotation

GitHub Actions / winBuild

public static class TouchEffect {

public static readonly BindableProperty ColorProperty =
BindableProperty.CreateAttached(
"Color",
typeof(Color),
typeof(TouchEffect),
Colors.Transparent,
KnownColor.Accent,
propertyChanged: PropertyChanged
);

Expand All @@ -18,6 +20,17 @@ public static Color GetColor(BindableObject view) {
return (Color)view.GetValue(ColorProperty);
}

public static void UnregisterEffect(BindableObject bindable)
{
if (!(bindable is View view))
return;

var eff = view.Effects.FirstOrDefault(e => e is TouchRoutingEffect);

if (eff == null) return;
view.Effects.Remove(eff);
}

static void PropertyChanged(BindableObject bindable, object oldValue, object newValue) {
if (!(bindable is View view))
return;
Expand All @@ -34,7 +47,7 @@ static void PropertyChanged(BindableObject bindable, object oldValue, object new
}
}
else {
if (eff == null || view.BindingContext == null) return;
if (eff == null) return;
view.Effects.Remove(eff);
if (EffectsConfig.AutoChildrenInputTransparent && bindable is Layout &&
EffectsConfig.GetChildrenInputTransparent(view)) {
Expand Down
56 changes: 25 additions & 31 deletions Maui.Tabs/MaterialUnderlinedTabItem.xaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>

<tabs:UnderlinedTabItemBase
x:Class="Sharpnado.Tabs.MaterialUnderlinedTabItem"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabs="clr-namespace:Sharpnado.Tabs"
x:Name="RootLayout">
<tabs:UnderlinedTabItemBase x:Class="Sharpnado.Tabs.MaterialUnderlinedTabItem"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabs="clr-namespace:Sharpnado.Tabs"
x:Name="RootLayout">

<ContentView.Resources>
<ResourceDictionary>
Expand Down Expand Up @@ -44,33 +43,28 @@
<Grid x:Name="Grid" RowSpacing="0">

<StackLayout x:Name="MainLayout" Style="{StaticResource LayoutIconWithText}">
<Path
x:Name="IconPath"
Data="{Binding Source={x:Reference RootLayout}, Path=GeometryIcon}"
Style="{StaticResource TabIconPath}" />
<Image
x:Name="IconImage"
HeightRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
Source="{Binding Source={x:Reference RootLayout}, Path=IconImageSource}"
Style="{StaticResource TabIconImage}"
WidthRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}" />
<Label
x:Name="InnerLabel"
FontFamily="{Binding Source={x:Reference RootLayout}, Path=FontFamily}"
FontSize="{Binding Source={x:Reference RootLayout}, Path=LabelSize}"
Style="{StaticResource TabTextHeader}"
Text="{Binding Source={x:Reference RootLayout}, Path=Label}" />
<Path x:Name="IconPath"
Style="{StaticResource TabIconPath}"
Data="{Binding Source={x:Reference RootLayout}, Path=GeometryIcon}" />
<Image x:Name="IconImage"
Style="{StaticResource TabIconImage}"
WidthRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
HeightRequest="{Binding Source={x:Reference RootLayout}, Path=IconSize}"
Source="{Binding Source={x:Reference RootLayout}, Path=IconImageSource}" />
<Label x:Name="InnerLabel"
Style="{StaticResource TabTextHeader}"
FontFamily="{Binding Source={x:Reference RootLayout}, Path=FontFamily}"
FontSize="{Binding Source={x:Reference RootLayout}, Path=LabelSize}"
Text="{Binding Source={x:Reference RootLayout}, Path=Label}" />
</StackLayout>
<BoxView
x:Name="Underline"
HeightRequest="0"
HorizontalOptions="Center"
VerticalOptions="End">
<BoxView x:Name="Underline"
HeightRequest="0"
HorizontalOptions="Center"
VerticalOptions="End">
<BoxView.Triggers>
<DataTrigger
Binding="{Binding Source={x:Reference RootLayout}, Path=IsSelected}"
TargetType="BoxView"
Value="true">
<DataTrigger Binding="{Binding Source={x:Reference RootLayout}, Path=IsSelected}"
TargetType="BoxView"
Value="true">
<Setter Property="HeightRequest" Value="{Binding Source={x:Reference RootLayout}, Path=UnderlineHeight}" />
</DataTrigger>
</BoxView.Triggers>
Expand Down
8 changes: 4 additions & 4 deletions Maui.Tabs/Maui.Tabs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

<PropertyGroup>
<Product>$(AssemblyName) ($(TargetFramework))</Product>
<AssemblyVersion>3.0.1</AssemblyVersion>
<AssemblyFileVersion>3.0.1</AssemblyFileVersion>
<Version>3.0.1</Version>
<AssemblyVersion>3.1.0</AssemblyVersion>
<AssemblyFileVersion>3.1.0</AssemblyFileVersion>
<Version>3.1.0</Version>
<PackOnBuild>true</PackOnBuild>
<NeutralLanguage>en</NeutralLanguage>

Expand All @@ -41,7 +41,7 @@
<PackageReadmeFile>docs\ReadMe.md</PackageReadmeFile>
<PackageTags>maui dotnetmaui xamarin.forms android ios uwp netstandard tabs segmented control bottombar fixed tabs scrollable tabs badge</PackageTags>
<PackageReleaseNotes>
First MAUI release \o/
Fixes for touch effects on tabs
</PackageReleaseNotes>

<Title>"Pure" MAUI Tabs (no renderers)</Title>
Expand Down
7 changes: 4 additions & 3 deletions Maui.Tabs/Platforms/Android/CommandsPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
namespace Sharpnado.Tabs.Effects.Droid {
public class CommandsPlatform : PlatformEffect {
public View View => Control ?? Container;
public bool IsDisposed => (Container as IVisualElementRenderer)?.Element == null;
public bool IsDisposed => Container is null
|| (Container is Java.Lang.Object javaContainer) && javaContainer.Handle == IntPtr.Zero;

DateTime _tapTime;
readonly Rect _rect = new Rect();
Expand All @@ -33,7 +34,7 @@ protected override void OnAttached() {
View.Clickable = true;
View.LongClickable = true;
View.SoundEffectsEnabled = true;
TouchCollector.Add(View, OnTouch);
TouchCollector.Add(View, OnTouch, ActionType.Tap);
}

void OnTouch(View.TouchEventArgs args) {
Expand Down Expand Up @@ -83,7 +84,7 @@ void LongClickHandler() {

protected override void OnDetached() {
if (IsDisposed) return;
TouchCollector.Delete(View, OnTouch);
TouchCollector.Delete(View, OnTouch, ActionType.Tap);
}
}
}
41 changes: 30 additions & 11 deletions Maui.Tabs/Platforms/Android/TouchCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,52 @@
using View = Android.Views.View;

namespace Sharpnado.Tabs.Effects.Droid.GestureCollectors {
enum ActionType
{
Ripple = 0,
Tap = 1,
}

record ActionSource(ActionType ActionType, Action<View.TouchEventArgs> Action);

internal static class TouchCollector {
static Dictionary<View, List<Action<View.TouchEventArgs>>> Collection { get; } =
new Dictionary<View, List<Action<View.TouchEventArgs>>>();
static Dictionary<View, List<ActionSource>> Collection { get; } =
new ();

static View _activeView;

public static void Add(View view, Action<View.TouchEventArgs> action) {
public static void Add(View view, Action<View.TouchEventArgs> action, ActionType actionType) {
if (Collection.ContainsKey(view)) {
Collection[view].Add(action);
Collection[view].Add(new ActionSource(actionType, action));
}
else {
view.Touch += ActionActivator;
Collection.Add(view, new List<Action<View.TouchEventArgs>> { action });
Collection.Add(view, [ new(actionType, action) ] );
}
}

public static void Delete(View view, Action<View.TouchEventArgs> action) {
public static void Delete(View view, Action<View.TouchEventArgs> action, ActionType actionType) {
if (!Collection.ContainsKey(view)) return;

var actions = Collection[view];
actions.Remove(action);
actions.Remove(new ActionSource(actionType, action));

if (actions.Count != 0) return;
view.Touch -= ActionActivator;
Collection.Remove(view);
}

static void ActionActivator(object sender, View.TouchEventArgs e) {
static async void ActionActivator(object sender, View.TouchEventArgs e) {
var view = (View)sender;
if (!Collection.ContainsKey(view) || (_activeView != null && _activeView != view)) return;

var actions = Collection[view].ToArray();
bool rippleRan = false;
foreach (var valueAction in actions.Where(source => source.ActionType == ActionType.Ripple)) {
valueAction?.Action.Invoke(e);
rippleRan = true;
}

switch (e.Event.Action) {
case MotionEventActions.Down:
_activeView = view;
Expand All @@ -55,9 +70,13 @@ static void ActionActivator(object sender, View.TouchEventArgs e) {
break;
}

var actions = Collection[view].ToArray();
foreach (var valueAction in actions) {
valueAction?.Invoke(e);
if (rippleRan)
{
await Task.Delay(200);
}

foreach (var valueAction in actions.Where(source => source.ActionType == ActionType.Tap)) {
valueAction?.Action.Invoke(e);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Maui.Tabs/Platforms/Android/TouchEffectPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected override void OnAttached() {
_viewOverlay.Background = CreateRipple(_color);

SetEffectColor();
TouchCollector.Add(View, OnTouch);
TouchCollector.Add(View, OnTouch, ActionType.Ripple);

group.AddView(_viewOverlay);
_viewOverlay.BringToFront();
Expand All @@ -78,7 +78,7 @@ protected override void OnDetached() {
if (EnableRipple)
_ripple?.Dispose();

TouchCollector.Delete(View, OnTouch);
TouchCollector.Delete(View, OnTouch, ActionType.Ripple);
}

protected override void OnElementPropertyChanged(PropertyChangedEventArgs e) {
Expand Down
2 changes: 1 addition & 1 deletion Maui.Tabs/Platforms/iOS/TintableImageEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private void UpdateColor()
private async Task DelayedPost(int milliseconds, Action action)
{
await Task.Delay(milliseconds);
Device.BeginInvokeOnMainThread(action);
MainThread.BeginInvokeOnMainThread(action);
}
}
}
4 changes: 2 additions & 2 deletions Maui.Tabs/Platforms/iOS/TouchEffectPlatform.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.ComponentModel;
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Platform;
using ObjCRuntime;
using Sharpnado.Tabs.Effects.iOS.GestureCollectors;
using Sharpnado.Tabs.Effects.iOS.GestureRecognizers;
Expand Down Expand Up @@ -80,7 +80,7 @@ void UpdateEffectColor() {

InternalLogger.Debug($"UpdateEffectColor");
_alpha = color.Alpha < 1.0 ? 1 : (float)0.3;
_layer.BackgroundColor = color.ToUIColor();
_layer.BackgroundColor = color.ToPlatform();
}

void BringLayer() {
Expand Down
Loading

0 comments on commit c60990f

Please sign in to comment.