the*_*yer 2 dart flutter flutter2.0
如何使自动完成框与TextField没有特定宽度的自动完成框大小相同,它占用最大宽度。
Autocomplete(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return ['aa', 'bb', 'cc', 'aa', 'bb', 'cc'];
}
return ['aa', 'bb', 'cc', 'aa', 'bb', 'cc']
.where((String option) {
return option
.toString()
.contains(textEditingValue.text.toLowerCase());
});
},
onSelected: (option) {
print(option);
},
),
Run Code Online (Sandbox Code Playgroud)
小智 15
我也经常遇到这个问题,选项生成器非常具体地说明了它希望将大小或填充放置在层次结构中的位置。这是我的工作示例:
optionsViewBuilder: (context, onAutoCompleteSelect, options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
color: Theme.of(context).primaryColorLight,
elevation: 4.0,
// size works, when placed here below the Material widget
child: Container(
// I have the text field wrapped in a container with
// EdgeInsets.all(20) so subtract 40 from the width for the width
// of the text box. You could also just use a padding widget
// with EdgeInsets.only(right: 20)
width: MediaQuery.of(context).size.width - 40,
child: ListView.separated(
shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
itemCount: options.length,
separatorBuilder: (context, i) {
return Divider();
},
itemBuilder: (BuildContext context, int index) {
// some child here
},
)
),
)
);
}
Run Code Online (Sandbox Code Playgroud)
我在尝试基于 RawAutocomplete 制作我自己的自动完成小部件时遇到了同样的问题,我使用布局构建器在我的 optionsViewBuilder 中获得完美的容器宽度大小:
LayoutBuilder(
builder: (context, constraints) => RawAutocomplete<String>(
focusNode: focusNode,
fieldViewBuilder: fieldViewBuilder,
optionsViewBuilder: (context, onSelected, options) => Align(
alignment: Alignment.topLeft,
child: Material(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(4.0)),
),
child: Container(
height: 52.0 * options.length,
width: constraints.biggest.width, // <-- Right here !
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
shrinkWrap: false,
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(option),
),
);
},
),
),
),
),
optionsBuilder: (textEditingValue) =>
suggestions.where((element) => element.contains(textEditingValue.text.trim().toUpperCase())),
textEditingController: controller,
),
)
Run Code Online (Sandbox Code Playgroud)
结果: 我的组件的预期结果
正如此处所指出的,在撰写本文时,最好的选择似乎是更改BoxConstraints默认_AutoCompleteOptions代码中包含的宽度和高度(可以在此处找到),并将其作为optionsViewBuilder的参数传递Autocomplete。不过,这要求您能够提前计算所需的宽度。
贴出我的代码,仅供参考:
Autocomplete<Animal>(
optionsBuilder: (textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<Animal>.empty();
}
return animalsList.where((Animal option) {
return "${option.id}".contains(textEditingValue.text.toLowerCase()) ||
option.nome!.toLowerCase().contains(textEditingValue.text.toLowerCase()) ||
option.ownerCF!.toLowerCase().contains(textEditingValue.text.toLowerCase());
});
},
optionsViewBuilder: (context, onSelected, options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4.0,
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200, maxWidth: 600), //RELEVANT CHANGE: added maxWidth
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Animal option = options.elementAt(index);
return InkWell(
onTap: () {
onSelected(option);
},
child: Builder(builder: (BuildContext context) {
final bool highlight = AutocompleteHighlightedOption.of(context) == index;
if (highlight) {
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
Scrollable.ensureVisible(context, alignment: 0.5);
});
}
return Container(
color: highlight ? Theme.of(context).focusColor : null,
padding: const EdgeInsets.all(16.0),
child: Text(option.getInfo() + " - " + option.getOwnerInfo()),
);
}),
);
},
),
),
),
);
},
displayStringForOption: (option) => option.getInfo() + " - " + option.getOwnerInfo(),
onSelected: (option) => selected = option,
);
Run Code Online (Sandbox Code Playgroud)
小智 5
我有同样的问题并通过使用解决了它ValueListenableBuilder。
小部件的宽度Material取决于返回的小部件的宽度field ViewBuilder(默认为 a ),因此一种解决方案是在一帧完成后TextFormField获取宽度并通知您的自定义TextFormFieldoptionsViewBuilder
示例代码:
import 'package:flutter/material.dart';
class AutocompleteText extends StatefulWidget {
@override
State<StatefulWidget> createState() => AutocompleteTextState();
}
class AutocompleteTextState extends State<AutocompleteText> {
final ValueNotifier<double?> optionsViewWidthNotifier = ValueNotifier(null);
static const List<User> _userOptions = <User>[
User(name: 'Alice', email: 'alice@example.com'),
User(name: 'Bob', email: 'bob@example.com'),
User(name: 'Charlie', email: 'charlie123@gmail.com'),
];
static String _displayStringForOption(User option) => option.name;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20),
child: Autocomplete<User>(
displayStringForOption: _displayStringForOption,
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<User>.empty();
}
return _userOptions.where((User option) {
return option
.toString()
.contains(textEditingValue.text.toLowerCase());
});
},
onSelected: (User selection) {
print('You just selected ${_displayStringForOption(selection)}');
},
fieldViewBuilder: (BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted) {
return OrientationBuilder(builder: (context, orientation) {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
optionsViewWidthNotifier.value =
(context.findRenderObject() as RenderBox).size.width;
});
return TextFormField(
controller: textEditingController,
focusNode: focusNode,
onFieldSubmitted: (String value) {
onFieldSubmitted();
},
);
});
},
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<User> onSelected,
Iterable<User> options,
) {
return ValueListenableBuilder<double?>(
valueListenable: optionsViewWidthNotifier,
builder: (context, width, _child) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4.0,
child: SizedBox(
width: width,
height: 200.0,
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final User option = options.elementAt(index);
return InkWell(
onTap: () {
onSelected(option);
},
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_displayStringForOption(option)),
),
);
},
),
),
),
);
});
},
),
));
}
@override
void dispose() {
optionsViewWidthNotifier.dispose();
super.dispose();
}
}
@immutable
class User {
const User({
required this.email,
required this.name,
});
final String email;
final String name;
@override
String toString() {
return '$name, $email';
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
return other is User && other.name == name && other.email == email;
}
@override
int get hashCode => hashValues(email, name);
}
Run Code Online (Sandbox Code Playgroud)