搜索栏
SearchBar不像Input和Editor那样从InputView派生,也没有Keyboard属性。 SearchBar在获取输入焦点时显示的键盘是特定于平台的,适用于搜索命令。 SearchBar本身类似于Entry视图,但根据平台,它可能装饰有一些其他图形并包含一个删除键入文本的按钮。
SearchBar定义了两个事件:
- TextChanged
- SearchButtonPressed
TextChanged事件允许您的程序访问正在进行的文本条目。 也许您的程序实际上可以在用户完成键入之前开始搜索或提供特定于上下文的建议。 SearchButtonPressed事件等同于Entry触发的Completed事件。 它由键盘上的特定按钮触发,与完成的Entry按钮位置相同但可能标记不同。
SearchBar定义了五个属性:
- Text - 用户输入的文本
- Placeholder - 在用户开始输入之前显示的提示文本
- UsingButtonColor - 类型为Color
- SearchCommand - 用于数据绑定
- SearchCommandParameter - 用于数据绑定
SearchBarDemo程序仅使用Text和Placeholder,但XAML文件为两个事件附加处理程序:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SearchBarDemo.SearchBarDemoPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="10, 20, 10, 0"
Android="10, 0"
WinPhone="10, 0" />
</ContentPage.Padding>
<StackLayout>
<SearchBar x:Name="searchBar"
Placeholder="Search text"
TextChanged="OnSearchBarTextChanged"
SearchButtonPressed="OnSearchBarButtonPressed" />
<ScrollView x:Name="resultsScroll"
VerticalOptions="FillAndExpand">
<StackLayout x:Name="resultsStack" />
</ScrollView>
</StackLayout>
</ContentPage>
该程序使用名为resultsStack的可滚动StackLayout来显示搜索结果。
这是三个平台的SearchBar和键盘。 请注意所有三个平台上的搜索图标和删除按钮,以及iOS和Android键盘上的特殊搜索键:
您可以从三个SearchBar视图中的条目猜测该程序允许搜索Herman Melville的Moby-Dick文本。 那是真实的! 整个小说作为嵌入式资源存储在Portable Class Library项目的Texts文件夹中,名称为MobyDick.txt。 该文件是纯文本,每段一行格式,源自Gutenberg.net网站上的文件。
代码隐藏文件的构造函数将整个文件读入名为bookText的字符串字段。 TextChanged处理程序清除任何先前搜索结果的resultsStack,以便在SearchBar中输入的文本与此列表之间没有差异。 SearchButtonPressed事件启动搜索:
public partial class SearchBarDemoPage : ContentPage
{
const double MaxMatches = 100;
string bookText;
public SearchBarDemoPage()
{
InitializeComponent();
// Load embedded resource bitmap.
string resourceID = "SearchBarDemo.Texts.MobyDick.txt";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
using (StreamReader reader = new StreamReader(stream))
{
bookText = reader.ReadToEnd();
}
}
}
void OnSearchBarTextChanged(object sender, TextChangedEventArgs args)
{
resultsStack.Children.Clear();
}
void OnSearchBarButtonPressed(object sender, EventArgs args)
{
// Detach resultsStack from layout.
resultsScroll.Content = null;
resultsStack.Children.Clear();
SearchBookForText(searchBar.Text);
// Reattach resultsStack to layout.
resultsScroll.Content = resultsStack;
}
void SearchBookForText(string searchText)
{
int count = 0;
bool isTruncated = false;
using (StringReader reader = new StringReader(bookText))
{
int lineNumber = 0;
string line;
while (null != (line = reader.ReadLine()))
{
lineNumber++;
int index = 0;
while (-1 != (index = (line.IndexOf(searchText, index,
StringComparison.OrdinalIgnoreCase))))
{
if (count == MaxMatches)
{
isTruncated = true;
break;
}
index += 1;
// Add the information to the StackLayout.
resultsStack.Children.Add(
new Label
{
Text = String.Format("Found at line {0}, offset {1}",
lineNumber, index)
});
count++;
}
if (isTruncated)
{
break;
}
}
}
// Add final count to the StackLayout.
resultsStack.Children.Add(
new Label
{
Text = String.Format("{0} match{1} found{2}",
count,
count == 1 ? "" : "es",
isTruncated ? " - stopped" : "")
});
}
}
SearchBookForText方法使用搜索文本和IndexOf方法应用于本书的每一行,以进行不区分大小写的比较,并为每个匹配添加一个Label到resultsStack。 但是,此过程存在性能问题,因为添加到StackLayout的每个Label都可能触发新的布局计算。 那是不必要的。 因此,在开始搜索之前,程序通过将其父级的Content属性(ScrollView)设置为null来从可视树中分离StackLayout:
resultsScroll.Content = null;
将所有Label视图添加到StackLayout后,StackLayout将添加回可视树:
resultsScroll.Content = resultsStack;
但即便如此,对于某些搜索而言,这并不是一个足够的性能提升,这就是为什么该计划将自己限制在前100场比赛中。 (注意在类顶部定义的MaxMatches常量。)这是显示您之前看到的搜索结果的程序:
您需要引用实际文件以查看这些匹配项。
会在第二个执行线程中运行搜索速度吗? 不。实际的文本搜索非常快。 性能问题涉及用户界面。 如果SearchBookForText方法在辅助线程中运行,那么它需要使用Device.BeginInvokeOnMainThread将每个Label添加到StackLayout。 如果该StackLayout附加到可视树,这将使程序更加动态地运行 - 在添加到列表中的每个项目之后,各个项目将出现在屏幕上 - 但是在线程之间来回切换将减慢整个操作。