您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
346 行
14 KiB
346 行
14 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using uiwidgets;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.material;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
using UnityEngine;
|
|
|
|
namespace UIWidgetsGallery.gallery {
|
|
public class SearchDemo : StatefulWidget {
|
|
public const string routeName = "/material/search";
|
|
|
|
public override State createState() {
|
|
return new _SearchDemoState();
|
|
}
|
|
}
|
|
|
|
class _SearchDemoState : State<SearchDemo> {
|
|
readonly _SearchDemoSearchDelegate _delegate = new _SearchDemoSearchDelegate();
|
|
readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key();
|
|
int? _lastIntegerSelected;
|
|
|
|
public override Widget build(BuildContext context) {
|
|
return new Scaffold(
|
|
key: this._scaffoldKey,
|
|
appBar: new AppBar(
|
|
leading: new IconButton(
|
|
tooltip: "Navigation menu",
|
|
icon: new AnimatedIcon(
|
|
icon: AnimatedIcons.arrow_menu,
|
|
color: Colors.white,
|
|
progress: this._delegate.transitionAnimation
|
|
),
|
|
onPressed: () => { this._scaffoldKey.currentState.openDrawer(); }
|
|
),
|
|
title: new Text("Numbers"),
|
|
actions: new List<Widget> {
|
|
new IconButton(
|
|
tooltip: "Search",
|
|
icon: new Icon(Icons.search),
|
|
onPressed: () => {
|
|
SearchUtils.showSearch(
|
|
context: context,
|
|
del: this._delegate
|
|
).then_((selected) => {
|
|
if (selected != null && (int) selected != this._lastIntegerSelected) {
|
|
this.setState(() => { this._lastIntegerSelected = (int) selected; });
|
|
}
|
|
});
|
|
}
|
|
),
|
|
new MaterialDemoDocumentationButton(SearchDemo.routeName),
|
|
new IconButton(
|
|
tooltip: "More (not implemented)",
|
|
icon: new Icon(
|
|
Theme.of(context).platform == RuntimePlatform.IPhonePlayer
|
|
? Icons.more_horiz
|
|
: Icons.more_vert
|
|
),
|
|
onPressed: () => { }
|
|
)
|
|
}
|
|
),
|
|
body: new Center(
|
|
child: new Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: new List<Widget> {
|
|
new Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: new List<Widget> {
|
|
new Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: new List<Widget> {
|
|
new Text("Press the "),
|
|
new Tooltip(
|
|
message: "search",
|
|
child: new Icon(
|
|
Icons.search,
|
|
size: 18.0f
|
|
)
|
|
),
|
|
new Text(" icon in the AppBar")
|
|
}
|
|
),
|
|
new Text("and search for an integer between 0 and 100,000.")
|
|
}
|
|
),
|
|
new SizedBox(height: 64.0f),
|
|
new Text(
|
|
this._lastIntegerSelected == null
|
|
? $"Last selected integer: {this._lastIntegerSelected}."
|
|
: $"Last selected integer: NONE."
|
|
),
|
|
}
|
|
)
|
|
),
|
|
floatingActionButton: FloatingActionButton.extended(
|
|
tooltip: "Back", // Tests depend on this label to exit the demo.
|
|
onPressed: () => { Navigator.of(context).pop<object>(); },
|
|
label:
|
|
new Text("Close demo"),
|
|
icon:
|
|
new Icon(Icons.close)
|
|
),
|
|
drawer: new Drawer(
|
|
child: new Column(
|
|
children: new List<Widget> {
|
|
new UserAccountsDrawerHeader(
|
|
accountName: new Text("Peter Widget"),
|
|
accountEmail: new Text("peter.widget@example.com"),
|
|
currentAccountPicture: new CircleAvatar(
|
|
backgroundImage: new FileImage(
|
|
"gallery/people/square/peter.png"
|
|
)
|
|
),
|
|
margin: EdgeInsets.zero
|
|
),
|
|
MediaQuery.removePadding(
|
|
context: context,
|
|
// DrawerHeader consumes top MediaQuery padding.
|
|
removeTop: true,
|
|
child: new ListTile(
|
|
leading: new Icon(Icons.payment),
|
|
title: new Text("Placeholder")
|
|
)
|
|
)
|
|
}
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SearchDemoSearchDelegate : SearchDelegate<int>
|
|
{
|
|
static List<int> listGenerate(int count, Func<int, int> func) {
|
|
var list = new List<int>();
|
|
for (int i = 0; i < count; i++) {
|
|
list.Add(func(i));
|
|
}
|
|
|
|
list.Reverse();
|
|
return list;
|
|
}
|
|
|
|
readonly List<int> _data = listGenerate(100001, (int i) => i);
|
|
|
|
readonly List<int> _history = new List<int> {42607, 85604, 66374, 44, 174};
|
|
|
|
public override Widget buildLeading(BuildContext context) {
|
|
return new IconButton(
|
|
tooltip: "Back",
|
|
icon: new AnimatedIcon(
|
|
icon: AnimatedIcons.arrow_menu,
|
|
progress: this.transitionAnimation
|
|
),
|
|
onPressed: () => { this.close(context, null); }
|
|
);
|
|
}
|
|
|
|
public override Widget buildSuggestions(BuildContext context) {
|
|
List<int> suggestions;
|
|
if (this.query.isEmpty()) {
|
|
suggestions = this._history;
|
|
}
|
|
else {
|
|
suggestions = new List<int>();
|
|
foreach (var item in this._data) {
|
|
var str = item.ToString();
|
|
var flag = true;
|
|
if (str.Length < this.query.Length) {
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < this.query.Length; i++) {
|
|
if (str[i] != this.query[i]) {
|
|
flag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (flag) {
|
|
suggestions.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
List<string> suggestionStrings = new List<string>();
|
|
foreach (var item in suggestions) {
|
|
suggestionStrings.Add(item.ToString());
|
|
}
|
|
|
|
return new _SuggestionList(
|
|
query: this.query,
|
|
suggestions: suggestionStrings,
|
|
onSelected: (string suggestion) => {
|
|
this.query = suggestion;
|
|
this.showResults(context);
|
|
}
|
|
);
|
|
}
|
|
|
|
public override Widget buildResults(BuildContext context) {
|
|
int searched;
|
|
try {
|
|
searched = int.Parse(this.query);
|
|
}
|
|
catch (Exception) {
|
|
return new Center(
|
|
child: new Text(
|
|
$"{this.query}\n is not a valid integer between 0 and 100,000.\nTry again.",
|
|
textAlign: TextAlign.center
|
|
)
|
|
);
|
|
}
|
|
|
|
if (!this._data.Contains(searched)) {
|
|
return new Center(
|
|
child: new Text(
|
|
$"{this.query}\n is not a valid integer between 0 and 100,000.\nTry again.",
|
|
textAlign: TextAlign.center
|
|
)
|
|
);
|
|
}
|
|
|
|
return new ListView(
|
|
children: new List<Widget> {
|
|
new _ResultCard(
|
|
title: "This integer",
|
|
integer: searched,
|
|
searchDelegate: this
|
|
),
|
|
new _ResultCard(
|
|
title: "Next integer",
|
|
integer: searched + 1,
|
|
searchDelegate: this
|
|
),
|
|
new _ResultCard(
|
|
title: "Previous integer",
|
|
integer: searched - 1,
|
|
searchDelegate: this
|
|
)
|
|
}
|
|
);
|
|
}
|
|
|
|
public override List<Widget> buildActions(BuildContext context) {
|
|
return new List<Widget> {
|
|
this.query.isEmpty()
|
|
? new IconButton(
|
|
tooltip: "Voice Search",
|
|
icon: new Icon(Icons.mic),
|
|
onPressed: () => { this.query = "TODO: implement voice input"; }
|
|
)
|
|
: new IconButton(
|
|
tooltip: "Clear",
|
|
icon: new Icon(Icons.clear),
|
|
onPressed:
|
|
() => {
|
|
this.query = "";
|
|
this.showSuggestions(context);
|
|
}
|
|
)
|
|
};
|
|
}
|
|
}
|
|
|
|
class _ResultCard : StatelessWidget {
|
|
public _ResultCard(
|
|
int integer, string title, SearchDelegate<int> searchDelegate
|
|
) {
|
|
this.integer = integer;
|
|
this.title = title;
|
|
this.searchDelegate = searchDelegate;
|
|
}
|
|
|
|
public readonly int integer;
|
|
public readonly string title;
|
|
public readonly SearchDelegate<int> searchDelegate;
|
|
|
|
public override Widget build(BuildContext context) {
|
|
ThemeData theme = Theme.of(context);
|
|
return new GestureDetector(
|
|
onTap: () => { this.searchDelegate.close(context, this.integer); },
|
|
child:
|
|
new Card(
|
|
child: new Padding(
|
|
padding: EdgeInsets.all(8.0f),
|
|
child: new Column(
|
|
children: new List<Widget> {
|
|
new Text(this.title),
|
|
new Text(this.integer.ToString(),
|
|
style: theme.textTheme.headline.copyWith(fontSize: 72.0f)
|
|
),
|
|
}
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SuggestionList : StatelessWidget {
|
|
public _SuggestionList(
|
|
List<string> suggestions, string query, ValueChanged<string> onSelected
|
|
) {
|
|
this.suggestions = suggestions;
|
|
this.query = query;
|
|
this.onSelected = onSelected;
|
|
}
|
|
|
|
public readonly List<string> suggestions;
|
|
public readonly string query;
|
|
public readonly ValueChanged<string> onSelected;
|
|
|
|
public override Widget build(BuildContext context) {
|
|
ThemeData theme = Theme.of(context);
|
|
return ListView.builder(
|
|
itemCount: this.suggestions.Count,
|
|
itemBuilder: (BuildContext _context, int i) => {
|
|
string suggestion = this.suggestions[i];
|
|
return new ListTile(
|
|
leading: this.query.isEmpty() ? new Icon(Icons.history) : new Icon(null),
|
|
title: new RichText(
|
|
text: new TextSpan(
|
|
text: suggestion.Substring(0, this.query.Length),
|
|
style: theme.textTheme.subhead.copyWith(fontWeight: FontWeight.bold),
|
|
children: new List<InlineSpan>
|
|
{
|
|
new TextSpan(
|
|
text: suggestion.Substring(this.query.Length),
|
|
style: theme.textTheme.subhead
|
|
)
|
|
}
|
|
)
|
|
),
|
|
onTap: () => { this.onSelected(suggestion); }
|
|
);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|