Flutter / Dart - I have a number of text input boxes on my app, but I still need more rows but haven't got the room, so need to make each one smaller. I have found the command "isDense: true," works to reduce the size slightly, but I need to reduce them much more, what's my best option? The labelText and hintText still need to show in each box.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Diabetic insulin dosage';
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.green,
foregroundColor: Colors.black,
),
body: const AddTwoNumbers(),
backgroundColor: Colors.white,
),
);
}
}
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({super.key});
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
Color _fillColor = Colors.white;
TextEditingController numR1C1controller =
TextEditingController(); //Changed name of the texteditingcontroller as Row as R and Column as C
TextEditingController numR1C2controller = TextEditingController();
TextEditingController numR1C3controller = TextEditingController();
TextEditingController numR2C1controller = TextEditingController();
TextEditingController numR2C2controller = TextEditingController();
TextEditingController numR2C3controller = TextEditingController();
TextEditingController numR3C1controller = TextEditingController();
TextEditingController numR3C2controller = TextEditingController();
TextEditingController numR3C3controller = TextEditingController();
TextEditingController numR4C1controller = TextEditingController();
TextEditingController numR4C2controller = TextEditingController();
TextEditingController numR4C3controller = TextEditingController();
String result = "0";
String result2 = "0";
String result3 = "0";
String result4 = "0";
// MAKE LIST OF MAP TO KEEP TRACK OF EACH BUTTONS
List<Map> buttons = [
{"name": "BreakFast", "active": false, "value": 1.0},
{"name": "Lunch", "active": false, "value": 0.6},
{"name": "Tea", "active": false, "value": 0.55},
];
// YOU CAN SET VARIABLE TO CURRENT MEAL NAME AND CAN CHECK WHETHER IT'S (breakFast) OR NOT
String? currentMealType;
// TOGGLE BUTTON FUNCTION
toggleButtons(Map obj) {
for (var i in buttons) {
if (i['name'] == obj['name']) {
i['active'] = !i['active'];
numR2C2controller.text = obj['value'].toString();
_calculateR2();
} else {
i['active'] = false;
}
}
setState(() {});
}
_calculateR1() {
if (numR1C1controller.text.isNotEmpty &&
numR1C2controller.text.isNotEmpty) {
double sum = double.parse(numR1C1controller.text) -
double.parse(numR1C2controller.text);
numR4C2controller.text = numR1C2controller.text;
numR2C1controller.text = numR1C1controller.text; // <-- add this
WidgetsBinding.instance.addPostFrameCallback((_) {
_calculateR3();
_calculateR2();
});
result = sum.toStringAsFixed(1);
}
if (numR1C2controller.text.isNotEmpty) {
setState(() {
_fillColor = double.parse(numR1C2controller.text) < 5
? Colors.red
: double.parse(numR1C2controller.text) > 9.1
? Colors.orange
: Colors.green;
});
} else {
setState(() {
_fillColor = Colors.white;
});
}
}
_calculateR2() {
if (numR2C1controller.text.isNotEmpty &&
numR2C2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(numR2C2controller.text) *
double.parse(numR2C1controller.text);
numR2C3controller.text = sum.toStringAsFixed(1);
numR3C1controller.text = numR2C3controller.text;
WidgetsBinding.instance.addPostFrameCallback((_) {
_calculateR3();
});
result2 = sum.toStringAsFixed(1);
});
}
}
_calculateR3() {
if (numR3C1controller.text.isNotEmpty &&
numR3C2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(numR3C1controller.text) /
double.parse(numR3C2controller.text);
numR3C3controller.text = sum.toStringAsFixed(1);
numR4C1controller.text = numR3C3controller.text;
WidgetsBinding.instance.addPostFrameCallback((_) {
_calculateR3();
_calculateR4();
});
result3 = sum.toStringAsFixed(1);
});
}
}
_calculateR4() {
if (numR4C1controller.text.isNotEmpty &&
numR4C2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(numR4C1controller.text) -
double.parse(numR4C2controller.text);
numR4C3controller.text = sum.toStringAsFixed(1);
result4 = sum.toStringAsFixed(1);
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
const Padding(
padding: EdgeInsets.all(6.0),
child: Text('Please pick a meal'),
),
// HERE IS THE VIEW FOR BUTTONS
//******************************
Row(
children: buttons
.map(
(btn) => Expanded(
child: GestureDetector(
onTap: () => toggleButtons(btn),
child: Container(
padding: const EdgeInsets.all(20.0),
margin: const EdgeInsets.only(bottom: 10, right: 10),
decoration: BoxDecoration(
color: btn['active'] ? Colors.red : Colors.white,
border: Border.all(color: Colors.grey[300]!)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(btn['name'],
style: TextStyle(
color: btn['active']
? Colors.white
: Colors.black)),
Text(btn['value'].toString(),
style: TextStyle(
color: btn['active']
? Colors.white
: Colors.black))
],
),
),
),
),
)
.toList(),
),
const Padding(
padding: EdgeInsets.all(6.0),
child: Text('Input Data'),
),
//******************************
Row(
children: <Widget>[
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14.0),
controller: numR1C1controller,
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,1}'))
],
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Carbs in Meal',
isDense: true,
hintText: 'Enter First Number',
fillColor: _fillColor,
filled: false),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14.0),
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR1C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,1}'))
],
decoration: InputDecoration(
border: const OutlineInputBorder(),
filled: true,
labelText: 'Current B/G Level',
isDense: true,
hintText: 'Enter Second Number',
fillColor: _fillColor),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14.0),
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR1C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Excercise Factor',
isDense: true,
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
const SizedBox(
height: 8,
),
const Padding(
padding: EdgeInsets.all(6.0),
child: Text('Calculations'),
),
Row(
children: [
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0, height: 1.0),
onChanged: (value) => _calculateR2(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C1controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'T Carbs in meal',
isDense: true,
hintText: 'Enter Third Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR2(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'T Meal Ratio',
isDense: true,
hintText: 'Enter Fourth Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR3(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Result 2',
isDense: true,
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
const SizedBox(
height: 8,
),
Row(
children: [
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR3(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR3C1controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'T Result 2',
// isDense: true,
hintText: 'Enter Fifth Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR3(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR3C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Correction Factor',
// isDense: true,
hintText: 'Enter Sixth Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR3(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR3C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Result 3',
// isDense: true,
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
const SizedBox(
height: 8,
),
Row(
children: [
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR4(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR4C1controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'T Target Level',
// isDense: true,
hintText: 'Enter Seventh Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR4(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR4C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'T Current B/G Level',
// isDense: true,
hintText: 'Enter Eighth Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR4(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR4C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^(\d+)?\.?\d{0,2}'))
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Result 4',
// isDense: true,
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
],
),
);
}
}
Simply wrap your your widget with sizedbox for height and width & for inner padding use content padding
SizedBox(
height: 10, // Increase the size as per your requirement
width: 10,
child: TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10), // Increase this for inner padding
),
)
Set contentPadding to zero in the decoration of TextField i.e.
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
),
If you want to make it even smaller, you can wrap it in SizedBox and give it some height (and width).
SizedBox(
height: 50,
width: 50,
child: TextField(),
)
DropdownSearch<T>(
dropdownBuilder: (context, data) {
return AutoSizeText(
displayProperty(data) ?? "",
maxLines: 1,
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16),
);
},
popupProps: PopupProps.menu(
fit: FlexFit.loose,
// showSelectedItems: true,
// interceptCallBacks: true,
itemBuilder: popupItemBuilder ??
(context, data, selected) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12)),
),
child: ListTile(
title: Text(
displayProperty(data) ?? "",
maxLines: 1,
style: AppTheme.subtitle1,
),
),
);
},
showSearchBox: showSearchBox,
emptyBuilder: (context, data) => Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text("No Data in $label was found."),
),
),
),
asyncItems: (String? data) => getData(),
// focusNode: focusNode,
onSaved: onSaved,
selectedItem: value,
validator: !isRequired
? null
: validator ??
(value) => value == null ? "$label can't be empty" : null,
// mode: Mode.MENU,
// showClearButton: enable,
key: keyX,
enabled: enable,
// maxHeight: maxHeight,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
labelText: label,
errorMaxLines: 2,
isDense: false,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45)),
// border: const OutlineInputBorder(),
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightGreen),
),
),
),
itemAsString: (data) => displayProperty(data) ?? "",
onChanged: onChanged,
);
I added mine like this and it worked.
DropdownSearch<dynamic>(
popupProps: const PopupProps.menu(
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
border: OutlineInputBorder(),
contentPadding:
EdgeInsets.fromLTRB(12, 12, 8, 0),
hintText: "search staff...",
),
)),
its empty because you build the field with empty string.
displayProperty(data) ?? "", this is return empty string when data is null.
DropdownSearch<T>(
dropdownBuilder: (context, data) {
return AutoSizeText(
displayProperty(data) ?? "your Hint Text here",
maxLines: 1,
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16),
);
},
.......
UPDATE
if you want to add hint text on popup search field you can add this to you code
searchBoxDecoration: InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.fromLTRB(12, 12, 8, 0),
hintText: "hint goes here",
)
you can found it from plugin owner : https://github.com/salim-lachdhaf/searchable_dropdown/issues/138#issuecomment-808702346
This is my current code:
Widget _buildContent(TextStyle _textStyle6) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Focus(
onFocusChange: (hasFocus) => setState(() => focused = hasFocus),
child: widget.scrollController != null
? Scrollbar(
controller: widget.scrollController,
thickness: 10,
trackVisibility: true,
thumbVisibility: true,
radius: Radius.circular(8),
child: _buildTextField(_textStyle6),
)
: _buildTextField(_textStyle6),
),
if (widget.outerHintText != null) Padding(
padding: const EdgeInsets.only(left: 18, top: 6),
child: Text(widget.outerHintText!, style: widget.outerHintStyle),
),
],
);
}
Widget _buildTextField(TextStyle _textStyle6) {
return TextFormField(
style: _textStyle6,
maxLength: widget.maxLength,
minLines: widget.minLines,
maxLines: widget.maxLines,
keyboardType: widget.keyboardType,
scrollController: widget.scrollController,
// scrollPadding: EdgeInsets.all(30),
decoration: InputDecoration(
alignLabelWithHint: widget.alignLabelWithHint,
border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade300, width: 0.8),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xff1a73e8), width: 2),
),
labelText: widget.label,
labelStyle: TextStyle(color: focused ? Color(0xff1a73e8) : Colors.black),
contentPadding: EdgeInsets.symmetric(horizontal: 18, vertical: 20),
prefixIcon: widget.prefixIcon,
prefixIconColor: widget.prefixIconColor,
constraints: widget.constraints,
),
);
}
Widget returned like this:
I wanna add some padding between the right border of TextField and the scrollbar. How to get it?
Container(
padding: const EdgeInsets.only(
right: 10.0,
),
decoration: BoxDecoration(
color: Color(),
border: Border.all(
color: Color(),
),
),
child: Scrollbar(
thickness: 5.0,
controller: _scrollController,
trackVisibility: true,
thumbVisibility: true,
child: TextFormField(
maxLines: 8,
textCapitalization: TextCapitalization.words,
scrollController: _scrollController,
decoration: const InputDecoration(
hintText: '....',
hintStyle: TextStyles.bodyTextLight,
isDense: true,
border: InputBorder.none,
filled: true,
fillColor: Color(),
),
),
),
),
You can do something like this, wrap your textfield and scrollbar to a container and give that container the same border and background style to it which you are giving to the textfield. And give it padding on the right side of the container.
https://i.stack.imgur.com/B2XIg.png
I need a Text Area with an enforced maxLength of 250 chars and its label aligned with the hint text. My code is below.
However, the widget is rendering the text on top of the hint. Does anyone know a solution?
It's like if the counter widget forces the actual text field to move upwards.
TextField with maxLength = 250 and alignLabelWithHint = true
TextField(
expands: false,
minLines: null,
maxLines: null,
maxLengthEnforced: maxLengthEnforced,
maxLength: maxLength,
controller: controller,
onChanged: (String value){
print(value);
},
cursorColor: Colors.deepOrange,
keyboardType: keyboardType,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: text,
labelStyle: TextStyle(color: Colors.grey),
hintText: text,
prefixIcon: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 15.0),
child: Material(
elevation: 0,
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Icon(
icon,
color: Colors.red,
),
),
),
],
),
),
border: InputBorder.none,
contentPadding: EdgeInsets.only(right: 10, top: 5, bottom: 5)),
)
The purpose of a hint is to disappear when the user start typing I tried your code and it worked with no problem.
TextField(
expands: false,
minLines: null,
maxLines: null,
maxLengthEnforced: true,
maxLength: 250,
// controller: controller,
onChanged: (String value) {
print(value);
},
cursorColor: Colors.deepOrange,
// keyboardType: keyboardType,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: "hi",
labelStyle: TextStyle(color: Colors.grey),
hintText: "hi",
prefixIcon: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 15.0),
child: Material(
elevation: 0,
color: Colors.white,
borderRadius:
BorderRadius.all(Radius.circular(30)),
child: Icon(
Icons.highlight,
color: Colors.red,
),
),
),
],
),
),
border: InputBorder.none,
contentPadding:
EdgeInsets.only(right: 10, top: 5, bottom: 5)),
),