Xamarin.Forms Shell 搜索
Xamarin.Forms Shell 包含 SearchHandler
类提供的集成搜索功能。 通过将 Shell.SearchHandler
附加属性设置为子类化的 SearchHandler
对象,可将搜索功能添加到页面。 这会将搜索框添加到页面顶部:
将查询输入到搜索框时,Query
属性将更新,每次更新时均将执行 OnQueryChanged
方法。 可以重写此方法来使用数据填充搜索建议区:
然后,从搜索建议区选择一个结果后,将执行 OnItemSelected
方法。 可以重写此方法来相应地进行响应,例如通过导航到详细信息页。
创建 SearchHandler
可按照以下步骤将搜索功能添加到 Shell 应用程序:创建 SearchHandler
类的子类,然后重写 OnQueryChanged
和 OnItemSelected
方法:
public class AnimalSearchHandler : SearchHandler
{
public IList<Animal> Animals { get; set; }
public Type SelectedItemNavigationTarget { get; set; }
protected override void OnQueryChanged(string oldValue, string newValue)
{
base.OnQueryChanged(oldValue, newValue);
if (string.IsNullOrWhiteSpace(newValue))
{
ItemsSource = null;
}
else
{
ItemsSource = Animals
.Where(animal => animal.Name.ToLower().Contains(newValue.ToLower()))
.ToList<Animal>();
}
}
protected override async void OnItemSelected(object item)
{
base.OnItemSelected(item);
// Let the animation complete
await Task.Delay(1000);
ShellNavigationState state = (App.Current.MainPage as Shell).CurrentState;
// The following route works because route names are unique in this application.
await Shell.Current.GoToAsync($"{GetNavigationTarget()}?name={((Animal)item).Name}");
}
string GetNavigationTarget()
{
return (Shell.Current as AppShell).Routes.FirstOrDefault(route => route.Value.Equals(SelectedItemNavigationTarget)).Key;
}
}
OnQueryChanged
重写包含两个参数:包含旧搜索查询的 oldValue
,以及包含当前搜索查询的 newValue
。 通过将 SearchHandler.ItemsSource
属性设置为 IEnumerable
集合(其中包含与当前搜索查询匹配的项),可以更新搜索建议区。
用户选择一个搜索结果后,将执行 OnItemSelected
重写,并设置 SelectedItem
属性。 在此示例中,此方法导航到另一个显示选定的 Animal
相关数据的页面。 有关导航的详细信息,请参阅 Xamarin.Forms Shell 导航。
注意
可设置其他的 SearchHandler
属性以控制搜索框的外观。
使用 SearchHandler
通过在“使用”页上将 Shell.SearchHandler
附加属性设置为子类类型对象,可以使用子类化的 SearchHandler
:
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:AnimalSearchHandler Placeholder="Enter search term"
ShowsResults="true"
DisplayMemberName="Name" />
</Shell.SearchHandler>
...
</ContentPage>
等效 C# 代码如下:
Shell.SetSearchHandler(this, new AnimalSearchHandler
{
Placeholder = "Enter search term",
ShowsResults = true,
DisplayMemberName = "Name"
});
AnimalSearchHandler.OnQueryChanged
方法返回 Animal
对象的 List
。 将 DisplayMemberName
属性设置为各个 Animal
对象的 Name
属性,这样建议区所显示的数据将为各个动物的名称。
将 ShowsResults
属性设置为 true
,这样当用户输入搜索查询时即可显示搜索建议:
搜索查询更改时,将更新搜索建议区:
选择某个搜索结果后,将导航到 MonkeyDetailPage
,并显示有关所选猴子的详细信息页面:
定义搜索结果项外观
除了在搜索结果中显示 string
数据外,还可以通过将 SearchHandler.ItemTemplate
属性设置为 DataTemplate
来定义每个搜索结果项的外观:
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:AnimalSearchHandler Placeholder="Enter search term"
ShowsResults="true">
<controls:AnimalSearchHandler.ItemTemplate>
<DataTemplate>
<Grid Padding="10"
ColumnDefinitions="0.15*,0.85*">
<Image Source="{Binding ImageUrl}"
HeightRequest="40"
WidthRequest="40" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
VerticalOptions="Center" />
</Grid>
</DataTemplate>
</controls:AnimalSearchHandler.ItemTemplate>
</controls:AnimalSearchHandler>
</Shell.SearchHandler>
...
</ContentPage>
等效 C# 代码如下:
Shell.SetSearchHandler(this, new AnimalSearchHandler
{
Placeholder = "Enter search term",
ShowsResults = true,
ItemTemplate = new DataTemplate(() =>
{
Grid grid = new Grid { Padding = 10 };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.15, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.85, GridUnitType.Star) });
Image image = new Image { HeightRequest = 40, WidthRequest = 40 };
image.SetBinding(Image.SourceProperty, "ImageUrl");
Label nameLabel = new Label { FontAttributes = FontAttributes.Bold, VerticalOptions = LayoutOptions.Center };
nameLabel.SetBinding(Label.TextProperty, "Name");
grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
return grid;
})
});
DataTemplate
中指定的元素定义建议区各个项的外观。 在此示例中,由 Grid
管理 DataTemplate
内的布局。 Grid
包含 Image
对象和 Label
对象,两者均绑定到各个 Monkey
对象的属性。
下面的屏幕截图显示建议区内各个项模板化后的结果:
有关数据模板的详细信息,请参阅 Xamarin.Forms 数据模板。
搜索框可见性
默认情况下,将 SearchHandler
添加到页面顶部后,将显示并完全展开该搜索框。 但是,可以通过将 SearchHandler.SearchBoxVisibility
属性设置为 SearchBoxVisibility
枚举成员之一来更改此行为:
Hidden
– 搜索框不可见或不可访问。Collapsible
– 隐藏搜索框,直到用户执行操作来显示搜索框。 在 iOS 上,通过纵向弹跳页面内容来显示搜索框;在 Android 上,通过点击问号图标显示搜索框。Expanded
– 搜索框可见,并且完全展开。 这是SearchBoxVisibility
属性的默认值。
重要
在 iOS 上,可折叠搜索框需要 iOS 11 或更高版本。
下面的示例演示了如何隐藏搜索框:
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:AnimalSearchHandler SearchBoxVisibility="Hidden"
... />
</Shell.SearchHandler>
...
</ContentPage>
搜索框焦点
点击搜索框可调用屏幕键盘,使搜索框获得输入焦点。 也可以通过调用 Focus
方法(尝试在搜索框上设置输入焦点,并在成功时返回 true
)来以编程方式实现。 当搜索框获得焦点时,会触发 Focused
事件并调用可重写的 OnFocused
方法。
当搜索框具有输入焦点时,点击屏幕上的其他位置可关闭屏幕键盘,并且搜索框失去输入焦点。 也可以通过调用 Unfocus
方法来以编程方式实现。 当搜索框失去焦点时,会触发 Unfocused
事件并调用可重写的 OnUnfocus
方法。
可以通过 IsFocused
属性检索搜索框的焦点状态,如果 SearchHandler
当前具有输入焦点,则会返回 true
。
SearchHandler 键盘
用户与 SearchHandler
交互时显示的键盘可以通过 Keyboard
属性以编程方式设置为 Keyboard
类中的以下属性之一:
Chat
– 用于可使用表情符号的文本和位置。Default
– 默认键盘。Email
– 输入电子邮件地址时使用。Numeric
– 输入数字时使用。Plain
– 输入文本时使用,无需指定任何KeyboardFlags
。Telephone
– 输入电话号码时使用。Text
– 输入文本时使用。Url
– 用于输入文件路径和 Web 地址。
这可以通过以下操作以 XAML 实现:
<SearchHandler Keyboard="Email" />
等效 C# 代码如下:
SearchHandler searchHandler = new SearchHandler { Keyboard = Keyboard.Email };
Keyboard
类还具有 Create
工厂方法,可用于通过指定大小写、拼写检查和建议行为来自定义键盘。 KeyboardFlags
枚举值指定为方法的参数,并返回自定义的 Keyboard
。 KeyboardFlags
枚举包含以下值:
None
– 无功能添加到键盘。CapitalizeSentence
– 指示自动大写输入的每句话的第一个词的首字母。Spellcheck
– 指示对输入的文本执行拼写检查。Suggestions
– 指示对输入的文本执行单词自动完成。CapitalizeWord
– 指示自动大写每个词的首字母。CapitalizeCharacter
– 指示自动大写每个字符。CapitalizeNone
– 指示不执行自动大写。All
– 指示对输入的文本执行拼写检查、单词自动完成和句子首字母大写。
以下 XAML 代码示例演示如何自定义默认 Keyboard
来执行单词自动完成并将输入的每个字符的首字母大写:
<SearchHandler Placeholder="Enter search terms">
<SearchHandler.Keyboard>
<Keyboard x:FactoryMethod="Create">
<x:Arguments>
<KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
</x:Arguments>
</Keyboard>
</SearchHandler.Keyboard>
</SearchHandler>
等效 C# 代码如下:
SearchHandler searchHandler = new SearchHandler { Placeholder = "Enter search terms" };
searchHandler.Keyboard = Keyboard.Create(KeyboardFlags.Suggestions | KeyboardFlags.CapitalizeCharacter);