Skip to content

Commit

Permalink
Convert to platform specific behaviours for improved handling
Browse files Browse the repository at this point in the history
  • Loading branch information
DevFromDownUnder committed Mar 26, 2024
1 parent 42355ff commit 26b40c5
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,5 @@ public partial class TextField
typeof(bool),
typeof(TextField),
false,
propertyChanged: (bindable, oldValue, newValue) => {
(bindable as TextField).ValidateClearButtonFocus();
});
BindingMode.TwoWay);
}
33 changes: 2 additions & 31 deletions src/UraniumUI.Material/Controls/TextField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public TextField()
EntryView.SetBinding(Entry.IsEnabledProperty, new Binding(nameof(IsEnabled), source: this));
EntryView.SetBinding(Entry.IsReadOnlyProperty, new Binding(nameof(IsReadOnly), source: this));

iconClear.SetBinding(StatefulContentView.IsNotFocusableProperty, new Binding(nameof(DisallowClearButtonFocus), BindingMode.TwoWay, source: this));

AfterConstructor();
}

Expand All @@ -67,13 +69,11 @@ protected override void OnHandlerChanged()
{
EntryView.TextChanged -= EntryView_TextChanged;
EntryView.Completed -= EntryView_Completed;
iconClear.Focused -= IconClear_Focused;
}
else
{
EntryView.TextChanged += EntryView_TextChanged;
EntryView.Completed += EntryView_Completed;
iconClear.Focused -= IconClear_Focused;

ApplyAttachedProperties();
}
Expand Down Expand Up @@ -109,11 +109,6 @@ private void EntryView_Completed(object sender, EventArgs e)
Completed?.Invoke(this, e);
}

private void IconClear_Focused(object sender, FocusEventArgs e)
{
ValidateClearButtonFocus();
}

public void ClearValue()
{
if (IsEnabled)
Expand Down Expand Up @@ -157,28 +152,4 @@ public override void ResetValidation()
EntryView.Text = string.Empty;
base.ResetValidation();
}

#region DisallowClearButtonFocus Logic

protected void ValidateClearButtonFocus()
{
if (DisallowClearButtonFocus)
{
var controlToFocus = GetNextExternalFocusableControl();

if (controlToFocus != null)
{
//Attempt to focus, I guess just ignore failures for now
//Maybe loop to next until we find ourselves?
controlToFocus.Focus();
}
}
}

protected IView GetNextExternalFocusableControl()
{
return UraniumUI.Extensions.ViewExtensions.GetNextElement(this.Parent, this) as IView;
}

#endregion DisallowClearButtonFocus Logic
}
4 changes: 2 additions & 2 deletions src/UraniumUI/Extensions/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static bool IsRtl(this VisualElement element)
return CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;
}

public static IVisualTreeElement GetNextElement(IVisualTreeElement parent, IVisualTreeElement startAfterElement)
public static IVisualTreeElement GetNextFocusableElement(IVisualTreeElement parent, IVisualTreeElement startAfterElement)
{
if (parent == null || startAfterElement == null)
{
Expand Down Expand Up @@ -169,7 +169,7 @@ public static IVisualTreeElement GetNextElement(IVisualTreeElement parent, IVisu
else
{
//Go up the stack
return GetNextElement(parent.GetVisualParent(), parent);
return GetNextFocusableElement(parent.GetVisualParent(), parent);
}
}

Expand Down
100 changes: 100 additions & 0 deletions src/UraniumUI/Views/StatefulContentView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,102 @@ public class StatefulContentView : ContentView, IStatefulView
public event EventHandler<EventArgs> HoverExited;
public event EventHandler<EventArgs> Tapped;

#region Focus Handling

protected override void OnHandlerChanged()
{
base.OnHandlerChanged();

UpdateFocus();
}

protected void UpdateFocus()
{
if (UpdateFocusWindows()) return;
if (UpdateFocusMACorIOS()) return;
if (UpdateFocusAndroid26OrHigher()) return;
UpdateFocusGeneric();
}

protected bool UpdateFocusWindows()
{
#if WINDOWS
var view = Handler?.PlatformView as Microsoft.Maui.Platform.ContentPanel;

if (view != null)
{
view.IsTabStop = !IsNotFocusable;

return true;
}

#endif
return false;
}

protected bool UpdateFocusMACorIOS()
{
#if IOS || MACCATALYST
var view = Handler?.PlatformView as UIKit.UIView;

if (view != null)
{
view.ExclusiveTouch = IsNotFocusable;

return true;
}
#endif
return false;
}

protected bool UpdateFocusAndroid26OrHigher()
{

#if ANDROID26_0_OR_GREATER
var view = Handler?.PlatformView as PlatformContentViewGroup;

if (view != null)
{
#pragma warning disable CA1416 // Validate platform compatibility
view.SetFocusable(IsNotFocusable ? Android.Views.ViewFocusability.NotFocusable : Android.Views.ViewFocusability.FocusableAuto);

return true;
#pragma warning restore CA1416 // Validate platform compatibility
}
#endif
return false;
}

protected void UpdateFocusGeneric()
{
//Fallback to focused event
if (Handler == null)
{
Focused -= StatefulContentView_Focused;
}
else
{
Focused += StatefulContentView_Focused;
}
}

private void StatefulContentView_Focused(object sender, FocusEventArgs e)
{
if (IsNotFocusable)
{
var controlToFocus = UraniumUI.Extensions.ViewExtensions.GetNextFocusableElement(Parent, this) as IView;

if (controlToFocus != null)
{
//Attempt to focus, I guess just ignore failures for now
//Maybe loop to next until we find ourselves?
controlToFocus.Focus();
}
}
}

#endregion Focus Handling

internal void InvokePressed() => Pressed?.Invoke(this, EventArgs.Empty);

internal void InvokeLongPressed() => LongPressed?.Invoke(this, EventArgs.Empty);
Expand Down Expand Up @@ -42,4 +138,8 @@ public class StatefulContentView : ContentView, IStatefulView
public object CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); }

public static BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(StatefulContentView));

public bool IsNotFocusable { get => (bool)GetValue(IsNotFocusableProperty); set => SetValue(IsNotFocusableProperty, value); }

public static BindableProperty IsNotFocusableProperty = BindableProperty.Create(nameof(IsNotFocusable), typeof(bool), typeof(StatefulContentView), false, BindingMode.TwoWay);
}

0 comments on commit 26b40c5

Please sign in to comment.