I have created a textfield, which has a dropdown button with the history of the textfield. What concerns me is that this field will be used to display IP address, which does not fit as I want in the history dropdown:
as you can see, the address is on two lines instead of one, which is as big as the textfield for example (200px in this case). I tried wrapping the DropdownMenuItem
in a SizedBox
and fixing its width to 200px for example but did not work.. Here is my Widget:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HistoryTextField extends StatefulWidget {
final String fieldType;
final String hintText;
const HistoryTextField(
{super.key, required this.fieldType, required this.hintText});
@override
State<HistoryTextField> createState() => _HistoryTextFieldState();
}
class _HistoryTextFieldState extends State<HistoryTextField> {
final TextEditingController _controller = TextEditingController();
final List<String> _history = [];
String? _selectedHistory;
@override
void initState() {
super.initState();
// Load history from storage
_loadHistory();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _loadHistory() async {
// Load history from storage
final preferences = await SharedPreferences.getInstance();
setState(() {
_history.addAll(preferences.getStringList(widget.fieldType) ?? []);
if (_history.isNotEmpty) {
_selectedHistory = _history.first;
_controller.text = _selectedHistory!;
}
});
}
Future<void> _saveHistory() async {
// Save history to storage
final preferences = await SharedPreferences.getInstance();
preferences.setStringList(widget.fieldType, _history);
}
void _addToHistory(String text) {
if (text.isNotEmpty && !_history.contains(text)) {
_history.insert(0, text);
// Save history to storage
_saveHistory();
}
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
border: Border.all(color: Theme.of(context).dividerColor),
borderRadius: BorderRadius.circular(5),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Row(
children: [
Expanded(
child: TextField(
cursorColor: Theme.of(context).dividerColor,
decoration: InputDecoration(
border: InputBorder.none, hintText: widget.hintText),
controller: _controller,
onChanged: (value) {
setState(() {
_selectedHistory = null;
});
},
onSubmitted: (value) {
_addToHistory(value);
},
),
),
SizedBox(
width: 50,
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
isExpanded: true,
value: _selectedHistory,
onChanged: (String? newValue) {
setState(() {
_selectedHistory = newValue;
_controller.text = newValue!;
});
},
selectedItemBuilder: (BuildContext context) {
return _history.map<Widget>((String value) {
return Container();
}).toList();
},
items: _history.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
textAlign: TextAlign.left,
),
);
}).toList(),
),
),
),
],
),
);
}
}
and here is how I have it used:
class _IpSelection extends StatelessWidget {
const _IpSelection();
@override
Widget build(BuildContext context) {
return const Row(
children: [
Text("IP Адрес: ", style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(width: 20),
// IP Address text field
SizedBox(
width: 200,
child: HistoryTextField(
fieldType: "ipField",
hintText: "Въведете IP адрес",
))
],
);
}
}
The reason why your content fit 2 strings inside dropdown, is that you explicitly wrap your DropdownButtonHideUnderline
inside SizedBox
with width: 50
(in your first code sample). That width
controls your DropdownButton's width.
Also There is a menuWidth
inside DropdownButton
widget. Its documentation says:
If it is not provided, the width of the menu is the width of the button.
So you can provide menuWidth
with desired size, or provide double.infinite
to make it fill all available space.