我正在尝试将 SearchAnchor 的视图大小调整为其内容。假设我有一些基本代码(取自此处):https://api.flutter.dev/flutter/material/SearchAnchor-class.html。我不知道我需要提前显示多少建议(我首先需要进行 API 调用)。
import 'package:flutter/material.dart';
/// Flutter code sample for [SearchAnchor].
const Duration fakeAPIDuration = Duration(seconds: 1);
void main() => runApp(const SearchAnchorAsyncExampleApp());
class SearchAnchorAsyncExampleApp extends StatelessWidget {
const SearchAnchorAsyncExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('SearchAnchor - async'),
),
body: const Center(
child: _AsyncSearchAnchor(),
),
),
);
}
}
class _AsyncSearchAnchor extends StatefulWidget {
const _AsyncSearchAnchor();
@override
State<_AsyncSearchAnchor> createState() => _AsyncSearchAnchorState();
}
class _AsyncSearchAnchorState extends State<_AsyncSearchAnchor> {
// The query currently being searched for. If null, there is no pending
// request.
String? _searchingWithQuery;
// The most recent options received from the API.
late Iterable<Widget> _lastOptions = <Widget>[];
@override
Widget build(BuildContext context) {
return SearchAnchor(
builder: (BuildContext context, SearchController controller) {
return IconButton(
icon: const Icon(Icons.search),
onPressed: () {
controller.openView();
},
);
}, suggestionsBuilder:
(BuildContext context, SearchController controller) async {
_searchingWithQuery = controller.text;
final List<String> options =
(await _FakeAPI.search(_searchingWithQuery!)).toList();
// If another search happened after this one, throw away these options.
// Use the previous options instead and wait for the newer request to
// finish.
if (_searchingWithQuery != controller.text) {
return _lastOptions;
}
_lastOptions = List<ListTile>.generate(options.length, (int index) {
final String item = options[index];
return ListTile(
title: Text(item),
);
});
return _lastOptions;
});
}
}
// Mimics a remote API.
class _FakeAPI {
static const List<String> _kOptions = <String>[
'aardvark',
'bobcat',
'chameleon',
];
// Searches the options, but injects a fake "network" delay.
static Future<Iterable<String>> search(String query) async {
await Future<void>.delayed(fakeAPIDuration); // Fake 1 second delay.
if (query == '') {
return const Iterable<String>.empty();
}
return _kOptions.where((String option) {
return option.contains(query.toLowerCase());
});
}
}
上面的代码可以运行,但是建议列表太大了。即使填满建议列表后,它仍然显示太多空白。我想在开始时显示一个较短(且空)的建议列表,并且在第一次 API 调用之后,我希望该列表调整其大小以适应其内容。
你知道该怎么做吗?
要实现您所描述的行为,您可以首先为建议列表设置固定高度,然后在 API 调用后根据内容动态调整高度。尝试这样的事情:
import 'package:flutter/material.dart';
const Duration fakeAPIDuration = Duration(seconds: 1);
void main() => runApp(const SearchAnchorAsyncExampleApp());
class SearchAnchorAsyncExampleApp extends StatelessWidget {
const SearchAnchorAsyncExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('SearchAnchor - async'),
),
body: const Center(
child: _AsyncSearchAnchor(),
),
),
);
}
}
class _AsyncSearchAnchor extends StatefulWidget {
const _AsyncSearchAnchor();
@override
State<_AsyncSearchAnchor> createState() => _AsyncSearchAnchorState();
}
class _AsyncSearchAnchorState extends State<_AsyncSearchAnchor> {
String? _searchingWithQuery;
late List<Widget> _lastOptions;
@override
Widget build(BuildContext context) {
return SearchAnchor(
builder: (BuildContext context, SearchController controller) {
return IconButton(
icon: const Icon(Icons.search),
onPressed: () {
controller.openView();
},
);
},
suggestionsBuilder: (BuildContext context, SearchController controller) async {
_searchingWithQuery = controller.text;
final List<String> options = (await _FakeAPI.search(_searchingWithQuery!)).toList();
// If another search happened after this one, throw away these options.
// Use the previous options instead and wait for the newer request to
// finish.
if (_searchingWithQuery != controller.text) {
return _lastOptions;
}
_lastOptions = List<Widget>.generate(options.length, (int index) {
final String item = options[index];
return ListTile(
title: Text(item),
);
});
return _lastOptions.isNotEmpty
? _lastOptions
: [Container(height: 50)]; // Set a fixed height initially
},
);
}
}
class _FakeAPI {
static const List<String> _kOptions = <String>[
'aardvark',
'bobcat',
'chameleon',
];
static Future<Iterable<String>> search(String query) async {
await Future<void>.delayed(fakeAPIDuration); // Fake 1 second delay.
if (query.isEmpty) {
return const Iterable<String>.empty();
}
return _kOptions.where((String option) {
return option.contains(query.toLowerCase());
});
}
}