Skip to content

Commit

Permalink
#618 Add option to disallow focus of end icons
Browse files Browse the repository at this point in the history
Limited by MAUI's functionality, will update focus to the next control
  • Loading branch information
DevFromDownUnder committed Mar 24, 2024
1 parent 6b6c99f commit 7892547
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/UraniumUI.Material/Controls/TextField.BindableProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,15 @@ public partial class TextField
defaultValue: EntryProperties.SelectionHighlightColorProperty.DefaultValue,
propertyChanged: (bindable, oldValue, newValue) => EntryProperties.SetSelectionHighlightColor(bindable, (Color)newValue)
);

public bool DisallowEndIconFocus { get => (bool)GetValue(DisallowEndIconFocusProperty); set => SetValue(DisallowEndIconFocusProperty, value); }

public static BindableProperty DisallowEndIconFocusProperty = BindableProperty.Create(
nameof(DisallowEndIconFocus),
typeof(bool),
typeof(TextField),
false,
propertyChanged: (bindable, oldValue, newValue) => {
(bindable as TextField).ValidateFocus();
});
}
25 changes: 25 additions & 0 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));

endIconsContainer.Focused += (s, e) => { ValidateFocus(); };

AfterConstructor();
}

Expand Down Expand Up @@ -148,4 +150,27 @@ public override void ResetValidation()
EntryView.Text = string.Empty;
base.ResetValidation();
}

#region DisallowEndIconsFocus Logic

protected void ValidateFocus()
{
if (DisallowEndIconFocus)
{
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 DisallowEndIconsFocus Logic
}
63 changes: 63 additions & 0 deletions src/UraniumUI/Extensions/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,67 @@ public static bool IsRtl(this VisualElement element)
// Fallback to culture:
return CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;
}

public static IVisualTreeElement GetNextElement(IVisualTreeElement parent, IVisualTreeElement startAfterElement)
{
if (parent == null || startAfterElement == null)
{
//Nothing more to search
return null;
}

var parentControls = parent.GetVisualChildren();

if (parentControls != null)
{
IVisualTreeElement firstFocusableElementBefore = null;
IVisualTreeElement firstFocusableElementAfter = null;

bool startElementFound = false;

foreach (var control in parentControls)
{
if (control.Equals(startAfterElement))
{
startElementFound = true;

continue;
}

if (control is View view && view.IsEnabled && view.IsVisible)
{
if (startElementFound)
{
firstFocusableElementAfter ??= control;
}
else
{
firstFocusableElementBefore ??= control;
}
}

//We have valid candidates, break out
if (firstFocusableElementBefore != null && firstFocusableElementAfter != null)
{
break;
}
}

if (firstFocusableElementAfter != null)
{
return firstFocusableElementAfter;
}
else if (firstFocusableElementBefore != null)
{
return firstFocusableElementBefore;
}
else
{
//Go up the stack
return GetNextElement(parent.GetVisualParent(), parent);
}
}

return null;
}
}

0 comments on commit 7892547

Please sign in to comment.