Skip to content

Commit 6a7ced1

Browse files
committed
Add latest KEyboardScrollFixes and android flyout fix
1 parent 52e6dd1 commit 6a7ced1

File tree

8 files changed

+165
-30
lines changed

8 files changed

+165
-30
lines changed

Shandler.Samples/MainFlyoutPage.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Shandler.Samples;
2+
3+
public class MainFlyoutPage : FlyoutPage
4+
{
5+
public MainFlyoutPage()
6+
{
7+
Detail = new NavigationPage(new MainPage());
8+
Flyout = new ContentPage()
9+
{
10+
Content = new VerticalStackLayout()
11+
{
12+
new Label()
13+
{
14+
Text = "label"
15+
}
16+
},
17+
Title = "rabbits of mercy"
18+
};
19+
}
20+
}

Shandler.Samples/Shandler.Samples.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
<ItemGroup>
5252
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
53-
<PackageReference Include="PureWeen.Maui.FixesAndWorkarounds" Version="1.0.5" />
53+
<PackageReference Include="PureWeen.Maui.FixesAndWorkarounds" Version="1.3.0" />
5454
</ItemGroup>
5555

5656
</Project>

ShanedlerSamples/Library/Common/ViewExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Reflection;
67
using System.Text;
78
using System.Threading.Tasks;
89

@@ -26,6 +27,22 @@ namespace Maui.FixesAndWorkarounds.Library.Common
2627
{
2728
internal static partial class Extensions
2829
{
30+
31+
internal static void InvokePrivateMethod(this object target, string methodName, object?[]? parameters)
32+
{
33+
var methods =
34+
target.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
35+
36+
foreach (var thing in methods)
37+
{
38+
if (thing.Name == methodName)
39+
{
40+
thing.Invoke(target, parameters);
41+
return;
42+
}
43+
}
44+
}
45+
2946
internal static T? FindParentOfType<T>(this Element element, bool includeThis = false)
3047
where T : IElement
3148
{

ShanedlerSamples/Library/Common/ViewExtensions.iOS.cs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,17 @@ internal static partial class Extensions
8585
if (siblings is null)
8686
break;
8787

88-
nextView = view.FindNextView(siblings.IndexOf(view) + 1, isValidType);
88+
// TableView and ListView cells may not be in order so handle separately
89+
if (view.FindResponder<UITableView>() is UITableView tableView)
90+
{
91+
nextView = view.FindNextInTableView(tableView, isValidType);
92+
93+
if (nextView is null)
94+
view = tableView;
95+
}
96+
97+
else
98+
nextView = view.FindNextView(siblings.IndexOf(view) + 1, isValidType);
8999

90100
view = view.Superview;
91101
}
@@ -99,7 +109,7 @@ internal static partial class Extensions
99109
static UIView? FindNextView(this UIView? view, int index, Func<UIView, bool> isValidType)
100110
{
101111
// search through the view's siblings and traverse down their branches
102-
var siblings = view?.Superview?.Subviews;
112+
var siblings = view is UITableView table ? table.VisibleCells : view?.Superview?.Subviews;
103113

104114
if (siblings is null)
105115
return null;
@@ -122,6 +132,31 @@ internal static partial class Extensions
122132
return null;
123133
}
124134

135+
static UIView? FindNextInTableView(this UIView view, UITableView table, Func<UIView, bool> isValidType)
136+
{
137+
if (isValidType(view))
138+
{
139+
var index = view.FindTableViewCellIndex(table);
140+
141+
return index == -1 ? null : table.FindNextView(index + 1, isValidType);
142+
}
143+
144+
return null;
145+
}
146+
147+
static int FindTableViewCellIndex(this UIView view, UITableView table)
148+
{
149+
var cells = table.VisibleCells;
150+
var viewCell = view.FindResponder<UITableViewCell>();
151+
152+
for (int i = 0; i < cells.Length; i++)
153+
{
154+
if (cells[i] == viewCell)
155+
return i;
156+
}
157+
return -1;
158+
}
159+
125160
internal static void ChangeFocusedView(this UIView view, UIView? newView)
126161
{
127162
if (newView is null)

ShanedlerSamples/Library/Keyboard/KeyboardAutoManagerScroll.iOS.cs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public WorkaroundMauiScrollView()
2626
// while the KeyboardAutoManagerScroll is scrolling.
2727
public override void ScrollRectToVisible(CGRect rect, bool animated)
2828
{
29-
if (!KeyboardAutoManagerScroll.IsCurrentlyScrolling)
29+
if (!KeyboardAutoManagerScroll.IsKeyboardAutoScrollHandling)
3030
base.ScrollRectToVisible(rect, animated);
3131
}
3232
}
@@ -70,9 +70,10 @@ void RemoveKeyboard()
7070

7171

7272

73-
internal static class KeyboardAutoManagerScroll
73+
74+
public static class KeyboardAutoManagerScroll
7475
{
75-
internal static bool IsCurrentlyScrolling;
76+
internal static bool IsKeyboardAutoScrollHandling;
7677
static UIScrollView? LastScrollView;
7778
static CGPoint StartingContentOffset;
7879
static UIEdgeInsets StartingScrollIndicatorInsets;
@@ -93,7 +94,7 @@ internal static class KeyboardAutoManagerScroll
9394
static NSObject? TextFieldToken = null;
9495
static NSObject? TextViewToken = null;
9596

96-
internal static void Connect()
97+
public static void Connect()
9798
{
9899
if (TextFieldToken is not null)
99100
return;
@@ -109,7 +110,7 @@ internal static void Connect()
109110
DidHideToken = NSNotificationCenter.DefaultCenter.AddObserver(new NSString("UIKeyboardDidHideNotification"), DidHideKeyboard);
110111
}
111112

112-
internal static void Disconnect()
113+
public static void Disconnect()
113114
{
114115
if (WillShowToken is not null)
115116
NSNotificationCenter.DefaultCenter.RemoveObserver(WillShowToken);
@@ -122,19 +123,22 @@ internal static void Disconnect()
122123
if (TextViewToken is not null)
123124
NSNotificationCenter.DefaultCenter.RemoveObserver(TextViewToken);
124125

125-
IsCurrentlyScrolling = false;
126+
IsKeyboardAutoScrollHandling = false;
126127
}
127128

128129
static async void DidUITextBeginEditing(NSNotification notification)
129130
{
130-
IsCurrentlyScrolling = true;
131+
IsKeyboardAutoScrollHandling = true;
131132

132133
if (notification.Object is not null)
133134
{
134135
View = notification.Object as UIView;
135136

136-
if (View is null)
137+
if (View is null || View.FindResponder<UIAlertController>() is not null)
138+
{
139+
IsKeyboardAutoScrollHandling = false;
137140
return;
141+
}
138142

139143
CursorRect = null;
140144

@@ -211,7 +215,7 @@ static void WillHideKeyboard(NSNotification notification)
211215

212216
static void DidHideKeyboard(NSNotification notification)
213217
{
214-
IsCurrentlyScrolling = false;
218+
IsKeyboardAutoScrollHandling = false;
215219
}
216220

217221
static NSObject? FindValue(this NSDictionary dict, string key)
@@ -302,11 +306,13 @@ internal static async Task AdjustPositionDebounce()
302306
// main method to calculate and animate the scrolling
303307
internal static void AdjustPosition()
304308
{
305-
if (View is not UITextField field && View is not UITextView)
306-
return;
307-
308-
if (ContainerView is null)
309+
if (ContainerView is null
310+
|| CursorRect is null
311+
|| (View is not UITextField && View is not UITextView))
312+
{
313+
IsKeyboardAutoScrollHandling = false;
309314
return;
315+
}
310316

311317
if (TopViewBeginOrigin == InvalidPoint)
312318
TopViewBeginOrigin = new CGPoint(ContainerView.Frame.X, ContainerView.Frame.Y);
@@ -345,9 +351,6 @@ internal static void AdjustPosition()
345351
if (ContainerView.Superview is UIView v)
346352
rootSuperViewFrameInWindow = v.ConvertRectToView(v.Bounds, window);
347353

348-
if (CursorRect is null)
349-
return;
350-
351354
var cursorRect = (CGRect)CursorRect;
352355

353356
nfloat cursorNotInViewScroll = 0;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#if ANDROID
2+
using Maui.FixesAndWorkarounds.Library.Common;
3+
using Microsoft.Maui.Controls;
4+
using Microsoft.Maui.Controls.Handlers.Compatibility;
5+
6+
using Microsoft.Maui.Handlers;
7+
using Microsoft.Maui.LifecycleEvents;
8+
using System.Reflection;
9+
10+
namespace Maui.FixesAndWorkarounds
11+
{
12+
public static partial class HostExtensions
13+
{
14+
public static MauiAppBuilder ConfigureFlyoutPageWorkarounds(this MauiAppBuilder builder)
15+
{
16+
17+
FlyoutViewHandler.Mapper.AppendToMapping(nameof(IFlyoutView.Detail), OnFixDetailsPage);
18+
FlyoutViewHandler.Mapper.AppendToMapping(nameof(IFlyoutView.Flyout), OnFixDetailsPage);
19+
return builder;
20+
}
21+
22+
static void OnFixDetailsPage(IFlyoutViewHandler arg1, IFlyoutView arg2)
23+
{
24+
var VirtualView = arg1.VirtualView;
25+
26+
if (VirtualView.FlyoutBehavior != FlyoutBehavior.Locked)
27+
return;
28+
29+
arg1.InvokePrivateMethod("UpdateDetailsFragmentView", null);
30+
}
31+
}
32+
33+
}
34+
35+
#endif

ShanedlerSamples/Library/Workarounds/HostExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static MauiAppBuilder ConfigureEntryNextWorkaround(this MauiAppBuilder bu
7676
return builder;
7777
}
7878

79-
79+
#if !ANDROID
8080
public static MauiAppBuilder ConfigureFlyoutPageWorkarounds(this MauiAppBuilder builder)
8181
{
8282
#if IOS || MACCATALYST
@@ -85,10 +85,10 @@ public static MauiAppBuilder ConfigureFlyoutPageWorkarounds(this MauiAppBuilder
8585
{
8686
handlers.AddHandler<FlyoutPage, CustomPhoneFlyoutPageRenderer>();
8787
});
88-
8988
#endif
9089
return builder;
91-
}
90+
}
91+
#endif
9292

9393
public static MauiAppBuilder ConfigureShellWorkarounds(this MauiAppBuilder builder)
9494
{

ShanedlerSamples/MainFlyoutPage.cs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,41 @@ public class MainFlyoutPage : FlyoutPage
55
public MainFlyoutPage()
66
{
77
Detail = new NavigationPage(new MainPage());
8-
Flyout = new ContentPage()
8+
Flyout = new SwappingStuffFlyoutPage();
9+
//Flyout = new ContentPage()
10+
//{
11+
// Content = new VerticalStackLayout()
12+
// {
13+
// new Label()
14+
// {
15+
// Text = "label"
16+
// }
17+
// },
18+
// Title = "rabbits of mercy"
19+
//};
20+
}
21+
22+
class SwappingStuffFlyoutPage : ContentPage
23+
{
24+
public SwappingStuffFlyoutPage()
925
{
10-
Content = new VerticalStackLayout()
26+
Title = "Hi thgere";
27+
28+
var layout = new VerticalStackLayout();
29+
30+
layout.Add(new Button()
1131
{
12-
new Label()
32+
Text = "Swap flyout page",
33+
Command = new Command(() =>
1334
{
14-
Text = "label"
15-
}
16-
},
17-
Title = "rabbits of mercy"
18-
};
35+
if (Application.Current.MainPage is FlyoutPage fp)
36+
{
37+
fp.Detail = new NavigationPage(new MainPage());
38+
}
39+
})
40+
});
41+
42+
Content = layout;
43+
}
1944
}
2045
}

0 commit comments

Comments
 (0)