зеркало из https://github.com/DeGsoft/maui-linux.git
Implement HorizontalTextAlignment in SearchBarHandlers (#508)
* Implement HorizontalTextAlignment in SearchBarHandlers * Clean up, add comments, verify things work with and without RTL support on Android Co-authored-by: E.Z. Hart <hartez@gmail.com>
This commit is contained in:
Родитель
667eb0391b
Коммит
4e01228c45
|
@ -4,6 +4,7 @@ using AGravityFlags = Android.Views.GravityFlags;
|
||||||
|
|
||||||
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
|
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
|
||||||
{
|
{
|
||||||
|
[PortHandler]
|
||||||
internal static class TextAlignmentExtensions
|
internal static class TextAlignmentExtensions
|
||||||
{
|
{
|
||||||
internal static void UpdateHorizontalAlignment(this EditText view, TextAlignment alignment, bool hasRtlSupport, AGravityFlags orMask = AGravityFlags.NoGravity)
|
internal static void UpdateHorizontalAlignment(this EditText view, TextAlignment alignment, bool hasRtlSupport, AGravityFlags orMask = AGravityFlags.NoGravity)
|
||||||
|
|
|
@ -172,6 +172,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
|
||||||
ClearFocus(Control);
|
ClearFocus(Control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[PortHandler]
|
||||||
void UpdateHorizontalTextAlignment()
|
void UpdateHorizontalTextAlignment()
|
||||||
{
|
{
|
||||||
_editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
|
_editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
|
||||||
|
|
|
@ -236,6 +236,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
|
||||||
_textField.AttributedPlaceholder = _textField.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
|
_textField.AttributedPlaceholder = _textField.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[PortHandler]
|
||||||
void UpdateHorizontalTextAlignment()
|
void UpdateHorizontalTextAlignment()
|
||||||
{
|
{
|
||||||
_textField = _textField ?? Control.FindDescendantView<UITextField>();
|
_textField = _textField ?? Control.FindDescendantView<UITextField>();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a View used to initiating a search.
|
/// Represents a View used to initiating a search.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISearchBar : IView, IPlaceholder
|
public interface ISearchBar : IView, IPlaceholder, ITextAlignment
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a string containing the query text in the SearchBar.
|
/// Gets a string containing the query text in the SearchBar.
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
using AndroidX.AppCompat.Widget;
|
using System.Linq;
|
||||||
|
using Android.Widget;
|
||||||
|
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||||
|
|
||||||
namespace Microsoft.Maui.Handlers
|
namespace Microsoft.Maui.Handlers
|
||||||
{
|
{
|
||||||
public partial class SearchBarHandler : AbstractViewHandler<ISearchBar, SearchView>
|
public partial class SearchBarHandler : AbstractViewHandler<ISearchBar, SearchView>
|
||||||
{
|
{
|
||||||
|
EditText? _editText;
|
||||||
|
public EditText? QueryEditor => _editText;
|
||||||
|
|
||||||
protected override SearchView CreateNativeView()
|
protected override SearchView CreateNativeView()
|
||||||
{
|
{
|
||||||
return new SearchView(Context);
|
var searchView = new SearchView(Context);
|
||||||
|
|
||||||
|
_editText = searchView.GetChildrenOfType<EditText>().First();
|
||||||
|
|
||||||
|
return searchView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapText(SearchBarHandler handler, ISearchBar searchBar)
|
public static void MapText(SearchBarHandler handler, ISearchBar searchBar)
|
||||||
|
@ -18,5 +27,10 @@ namespace Microsoft.Maui.Handlers
|
||||||
{
|
{
|
||||||
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
|
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void MapHorizontalTextAlignment(SearchBarHandler handler, ISearchBar searchBar)
|
||||||
|
{
|
||||||
|
handler.QueryEditor?.UpdateHorizontalTextAlignment(searchBar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,5 +8,6 @@ namespace Microsoft.Maui.Handlers
|
||||||
|
|
||||||
public static void MapText(IViewHandler handler, ISearchBar searchBar) { }
|
public static void MapText(IViewHandler handler, ISearchBar searchBar) { }
|
||||||
public static void MapPlaceholder(IViewHandler handler, ISearchBar searchBar) { }
|
public static void MapPlaceholder(IViewHandler handler, ISearchBar searchBar) { }
|
||||||
|
public static void MapHorizontalTextAlignment(IViewHandler handler, ISearchBar searchBar) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,8 @@
|
||||||
public static PropertyMapper<ISearchBar, SearchBarHandler> SearchBarMapper = new PropertyMapper<ISearchBar, SearchBarHandler>(ViewHandler.ViewMapper)
|
public static PropertyMapper<ISearchBar, SearchBarHandler> SearchBarMapper = new PropertyMapper<ISearchBar, SearchBarHandler>(ViewHandler.ViewMapper)
|
||||||
{
|
{
|
||||||
[nameof(ISearchBar.Text)] = MapText,
|
[nameof(ISearchBar.Text)] = MapText,
|
||||||
[nameof(ISearchBar.Placeholder)] = MapPlaceholder
|
[nameof(ISearchBar.Placeholder)] = MapPlaceholder,
|
||||||
|
[nameof(ISearchBar.HorizontalTextAlignment)] = MapHorizontalTextAlignment
|
||||||
};
|
};
|
||||||
|
|
||||||
public SearchBarHandler() : base(SearchBarMapper)
|
public SearchBarHandler() : base(SearchBarMapper)
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
using System;
|
|
||||||
using UIKit;
|
using UIKit;
|
||||||
|
|
||||||
namespace Microsoft.Maui.Handlers
|
namespace Microsoft.Maui.Handlers
|
||||||
{
|
{
|
||||||
public partial class SearchBarHandler : AbstractViewHandler<ISearchBar, UISearchBar>
|
public partial class SearchBarHandler : AbstractViewHandler<ISearchBar, UISearchBar>
|
||||||
{
|
{
|
||||||
protected override UISearchBar CreateNativeView() => new UISearchBar();
|
UITextField? _textField;
|
||||||
|
|
||||||
|
protected override UISearchBar CreateNativeView()
|
||||||
|
{
|
||||||
|
var searchBar = new UISearchBar();
|
||||||
|
|
||||||
|
_textField = searchBar.FindDescendantView<UITextField>();
|
||||||
|
|
||||||
|
return searchBar;
|
||||||
|
}
|
||||||
|
|
||||||
public static void MapText(SearchBarHandler handler, ISearchBar searchBar)
|
public static void MapText(SearchBarHandler handler, ISearchBar searchBar)
|
||||||
{
|
{
|
||||||
|
@ -16,5 +24,10 @@ namespace Microsoft.Maui.Handlers
|
||||||
{
|
{
|
||||||
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
|
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void MapHorizontalTextAlignment(SearchBarHandler handler, ISearchBar searchBar)
|
||||||
|
{
|
||||||
|
handler.TypedNativeView?.UpdateHorizontalTextAlignment(searchBar, handler._textField);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
using AndroidX.AppCompat.Widget;
|
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||||
|
|
||||||
namespace Microsoft.Maui
|
namespace Microsoft.Maui
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using Android.Widget;
|
||||||
|
|
||||||
namespace Microsoft.Maui
|
namespace Microsoft.Maui
|
||||||
{
|
{
|
||||||
public static class LabelExtensions
|
public static class TextViewExtensions
|
||||||
{
|
{
|
||||||
public static void UpdateText(this TextView textView, ILabel label)
|
public static void UpdateText(this TextView textView, ILabel label)
|
||||||
{
|
{
|
||||||
|
@ -40,9 +40,20 @@ namespace Microsoft.Maui
|
||||||
textView.SetTextSize(ComplexUnitType.Sp, sp);
|
textView.SetTextSize(ComplexUnitType.Sp, sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateHorizontalTextAlignment(this TextView textView, ILabel label)
|
public static void UpdateHorizontalTextAlignment(this TextView textView, ITextAlignment text)
|
||||||
{
|
{
|
||||||
textView.Gravity = label.HorizontalTextAlignment.ToHorizontalGravityFlags();
|
if (textView.Context!.HasRtlSupport())
|
||||||
|
{
|
||||||
|
// We want to use TextAlignment where possible because it doesn't conflict with the
|
||||||
|
// overall gravity of the underlying control
|
||||||
|
textView.TextAlignment = text.HorizontalTextAlignment.ToTextAlignment();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// But if RTL support is not available for some reason, we have to resort
|
||||||
|
// to gravity, because Android will simply ignore text alignment
|
||||||
|
textView.Gravity = text.HorizontalTextAlignment.ToHorizontalGravityFlags();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateLineBreakMode(this TextView textView, ILabel label)
|
public static void UpdateLineBreakMode(this TextView textView, ILabel label)
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AView = Android.Views.View;
|
||||||
|
using AViewGroup = Android.Views.ViewGroup;
|
||||||
|
|
||||||
|
namespace Microsoft.Maui
|
||||||
|
{
|
||||||
|
public static class ViewGroupExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<T> GetChildrenOfType<T>(this AViewGroup self) where T : AView
|
||||||
|
{
|
||||||
|
for (var i = 0; i < self.ChildCount; i++)
|
||||||
|
{
|
||||||
|
AView? child = self.GetChildAt(i);
|
||||||
|
|
||||||
|
if (child is T typedChild)
|
||||||
|
yield return typedChild;
|
||||||
|
|
||||||
|
if (child is AViewGroup)
|
||||||
|
{
|
||||||
|
IEnumerable<T>? myChildren = (child as AViewGroup)?.GetChildrenOfType<T>();
|
||||||
|
if (myChildren != null)
|
||||||
|
foreach (T nextChild in myChildren)
|
||||||
|
yield return nextChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,5 +13,23 @@ namespace Microsoft.Maui
|
||||||
{
|
{
|
||||||
uiSearchBar.Placeholder = searchBar.Placeholder;
|
uiSearchBar.Placeholder = searchBar.Placeholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void UpdateHorizontalTextAlignment(this UISearchBar uiSearchBar, ISearchBar searchBar)
|
||||||
|
{
|
||||||
|
UpdateHorizontalTextAlignment(uiSearchBar, searchBar, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateHorizontalTextAlignment(this UISearchBar uiSearchBar, ISearchBar searchBar, UITextField? textField)
|
||||||
|
{
|
||||||
|
textField ??= uiSearchBar.FindDescendantView<UITextField>();
|
||||||
|
|
||||||
|
if (textField == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We don't have a FlowDirection yet, so there's nothing to pass in here.
|
||||||
|
// TODO: Update this when FlowDirection is available
|
||||||
|
// (or update the extension to take an ILabel instead of an alignment and work it out from there)
|
||||||
|
textField.TextAlignment = searchBar.HorizontalTextAlignment.ToNative(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,41 @@
|
||||||
using Microsoft.Maui.Handlers;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Android.Widget;
|
||||||
|
using Microsoft.Maui.DeviceTests.Stubs;
|
||||||
|
using Microsoft.Maui.Handlers;
|
||||||
|
using Xunit;
|
||||||
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||||
|
|
||||||
namespace Microsoft.Maui.DeviceTests
|
namespace Microsoft.Maui.DeviceTests
|
||||||
{
|
{
|
||||||
public partial class SearchBarHandlerTests
|
public partial class SearchBarHandlerTests
|
||||||
{
|
{
|
||||||
|
[Fact(DisplayName = "Horizontal TextAlignment Initializes Correctly")]
|
||||||
|
public async Task HorizontalTextAlignmentInitializesCorrectly()
|
||||||
|
{
|
||||||
|
var xplatHorizontalTextAlignment = TextAlignment.End;
|
||||||
|
|
||||||
|
var searchBarStub = new SearchBarStub()
|
||||||
|
{
|
||||||
|
Text = "Test",
|
||||||
|
HorizontalTextAlignment = xplatHorizontalTextAlignment
|
||||||
|
};
|
||||||
|
|
||||||
|
Android.Views.TextAlignment expectedValue = Android.Views.TextAlignment.ViewEnd;
|
||||||
|
|
||||||
|
var values = await GetValueAsync(searchBarStub, (handler) =>
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
ViewValue = searchBarStub.HorizontalTextAlignment,
|
||||||
|
NativeViewValue = GetNativeTextAlignment(handler)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Equal(xplatHorizontalTextAlignment, values.ViewValue);
|
||||||
|
values.NativeViewValue.AssertHasFlag(expectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
SearchView GetNativeSearchBar(SearchBarHandler searchBarHandler) =>
|
SearchView GetNativeSearchBar(SearchBarHandler searchBarHandler) =>
|
||||||
(SearchView)searchBarHandler.View;
|
(SearchView)searchBarHandler.View;
|
||||||
|
|
||||||
|
@ -13,5 +44,16 @@ namespace Microsoft.Maui.DeviceTests
|
||||||
|
|
||||||
string GetNativePlaceholder(SearchBarHandler searchBarHandler) =>
|
string GetNativePlaceholder(SearchBarHandler searchBarHandler) =>
|
||||||
GetNativeSearchBar(searchBarHandler).QueryHint;
|
GetNativeSearchBar(searchBarHandler).QueryHint;
|
||||||
|
|
||||||
|
Android.Views.TextAlignment GetNativeTextAlignment(SearchBarHandler searchBarHandler)
|
||||||
|
{
|
||||||
|
var searchView = GetNativeSearchBar(searchBarHandler);
|
||||||
|
var editText = searchView.GetChildrenOfType<EditText>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (editText == null)
|
||||||
|
return Android.Views.TextAlignment.Inherit;
|
||||||
|
|
||||||
|
return editText.TextAlignment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,17 +1,57 @@
|
||||||
using Microsoft.Maui.Handlers;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Maui.DeviceTests.Stubs;
|
||||||
|
using Microsoft.Maui.Handlers;
|
||||||
using UIKit;
|
using UIKit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.Maui.DeviceTests
|
namespace Microsoft.Maui.DeviceTests
|
||||||
{
|
{
|
||||||
public partial class SearchBarHandlerTests
|
public partial class SearchBarHandlerTests
|
||||||
{
|
{
|
||||||
UISearchBar GetNativeEntry(SearchBarHandler searchBarHandler) =>
|
[Fact(DisplayName = "Horizontal TextAlignment Updates Correctly")]
|
||||||
|
public async Task HorizontalTextAlignmentInitializesCorrectly()
|
||||||
|
{
|
||||||
|
var xplatHorizontalTextAlignment = TextAlignment.End;
|
||||||
|
|
||||||
|
var searchBarStub = new SearchBarStub()
|
||||||
|
{
|
||||||
|
Text = "Test",
|
||||||
|
HorizontalTextAlignment = xplatHorizontalTextAlignment
|
||||||
|
};
|
||||||
|
|
||||||
|
UITextAlignment expectedValue = UITextAlignment.Right;
|
||||||
|
|
||||||
|
var values = await GetValueAsync(searchBarStub, (handler) =>
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
ViewValue = searchBarStub.HorizontalTextAlignment,
|
||||||
|
NativeViewValue = GetNativeTextAlignment(handler)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Equal(xplatHorizontalTextAlignment, values.ViewValue);
|
||||||
|
values.NativeViewValue.AssertHasFlag(expectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
UISearchBar GetNativeSearchBar(SearchBarHandler searchBarHandler) =>
|
||||||
(UISearchBar)searchBarHandler.View;
|
(UISearchBar)searchBarHandler.View;
|
||||||
|
|
||||||
string GetNativeText(SearchBarHandler searchBarHandler) =>
|
string GetNativeText(SearchBarHandler searchBarHandler) =>
|
||||||
GetNativeEntry(searchBarHandler).Text;
|
GetNativeSearchBar(searchBarHandler).Text;
|
||||||
|
|
||||||
string GetNativePlaceholder(SearchBarHandler searchBarHandler) =>
|
string GetNativePlaceholder(SearchBarHandler searchBarHandler) =>
|
||||||
GetNativeEntry(searchBarHandler).Placeholder;
|
GetNativeSearchBar(searchBarHandler).Placeholder;
|
||||||
|
|
||||||
|
UITextAlignment GetNativeTextAlignment(SearchBarHandler searchBarHandler)
|
||||||
|
{
|
||||||
|
var uiSearchBar = GetNativeSearchBar(searchBarHandler);
|
||||||
|
var textField = uiSearchBar.FindDescendantView<UITextField>();
|
||||||
|
|
||||||
|
if (textField == null)
|
||||||
|
return UITextAlignment.Left;
|
||||||
|
|
||||||
|
return textField.TextAlignment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,5 +7,7 @@
|
||||||
public string Text { get => _text; set => SetProperty(ref _text, value); }
|
public string Text { get => _text; set => SetProperty(ref _text, value); }
|
||||||
|
|
||||||
public string Placeholder { get; set; }
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
|
public TextAlignment HorizontalTextAlignment { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
Загрузка…
Ссылка в новой задаче