I'm trying to do a "search contact list" feature with some chips representing selected contacts, and a user can type on text field to filter and add more contacts:
This is done with a Wrap
widget, wrapping a list of Chip
widgets, and ending the list with a Container
of a TextField
widget.
What I've tried:
If I do not set the width of the TextField
, it defaults to occupy a whole line. Let's make it red for clarity:
I do not want a whole line for it, so I set it to a small value, 50. But this doesn't work if the text is long:
Question:
Is it possible to make the TextField
starts small, and auto expands to a whole line when needed? I've tried "minWidth" in BoxConstraint
but since the TextField
defaults to a whole line, that doesn't work. Is using Wrap and TextField the correct way here?
Here's how you wrap text on overflow in Flutter:Step 1: Make sure your Text widget is inside the Row widget. Step 2: Wrap your Text widget inside the Expanded widget. Step 3: Run your app.
To change the TextField height by changing the Font Size: Step 1: Inside the TextField, Add the style parameter and assign the TextStyle(). Step 2: Inside the TextStyle(), Add the fontSize parameter and set the appropriate value. Step 3: Run the app.
You can control the TextField in your Flutter App. The TextField widget of Flutter has an inbuilt method TextEditingController. clear() which is used to clear or empty the typed text inside the Text Input widget. The clear() method would empty the entered string text and set its default value is empty.
Use IntrinsicWidth
widget to size a child to the child's maximum intrinsic width. In this case, effectively shrink wrapping the TextField:
IntrinsicWidth(
child: TextField(),
)
However, this will make the TextField too small when it's empty. To fix that, we can use ConstrainedBox
to force a minimum width constraint. For example:
ConstrainedBox(
constraints: BoxConstraints(minWidth: 48),
child: IntrinsicWidth(
child: TextField(),
),
)
End result:
I tried but failed. I have issues figuring out when the TextField overflows. This solution cannot work with dynamically changing chips since tp.layout(maxWidth: constraints.maxWidth/2);
is hard coded.
There are two options to fix this solution:
TextController has a overflow flag
In tp.layout(maxWidth: constraints.maxWidth/2)
, LayoutBuilder can figure out the width left over from chips.
Here is my attempt
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController _controller;
String _text = "";
bool _textOverflow = false;
@override
void initState() {
// TODO: implement initState
super.initState();
_textOverflow = false;
_controller = TextEditingController();
_controller.addListener((){
setState(() {
_text = _controller.text;
});
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_controller.dispose();
}
Widget chooseChipInput(BuildContext context, bool overflow, List<Widget> chips) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
overflow ? Wrap(children: chips, alignment: WrapAlignment.start,): Container(),
Container(
color: Colors.red,
child: TextField(
controller: _controller,
maxLines: overflow ? null : 1,
decoration: InputDecoration(icon: overflow ? Opacity(opacity: 0,) : Wrap(children: chips,)),
),
)
]
);
}
@override
Widget build(BuildContext context) {
const _counter = 0;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
LayoutBuilder(builder: (context, constraints){
var textStyle = DefaultTextStyle.of(context).style;
var span = TextSpan(
text: _text,
style: textStyle,
);
// Use a textpainter to determine if it will exceed max lines
var tp = TextPainter(
maxLines: 1,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
text: span,
);
// trigger it to layout
tp.layout(maxWidth: constraints.maxWidth/2);
// whether the text overflowed or not
print("****** ${tp.didExceedMaxLines} ${constraints.maxWidth}");
return chooseChipInput(
context,
tp.didExceedMaxLines,
<Widget>[Chip(label: Text("chip1"),),
Chip(label: Text("chip2")),]
);
},),
],
),
),
);
}
}
This attempt comprised of a few parts:
Edit3: Added picture when you add tons of chips and fix the Column(Warp)
Like I said, the largest problem is that I cannot figure out when the text box overflows.
Anyone else wants try? I think this question needs a custom plugin to solve
Edit2: I found the library but I did not test it https://github.com/danvick/flutter_chips_input
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With