Various Widgets - wurzelsand/flutter-memos GitHub Wiki
If a widget wants to be built differently, depending on the space available to it, a LayoutBuilder could be used. For example, a widget wants to display image and text if there is enough space. And if the space is not enough, it wants to display only the image instead.
Here I'm using a LayoutBuilder that shows the maximum space available to it as a red rectangle. A green rectangle above it represents how big it should be at least.

The red rectangle is 300x400, the green one 100x200.
import 'package:flutter/material.dart';
void main() {
runApp(const TestApp());
}
class TestApp extends StatelessWidget {
const TestApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Container(
constraints: const BoxConstraints(
minWidth: 100, minHeight: 200, maxWidth: 300, maxHeight: 400),
child: LayoutBuilder(builder: (context, constraints) {
return Stack(
children: [
Container(
color: Colors.red,
width: constraints.maxWidth,
height: constraints.maxHeight),
Container(
color: Colors.green,
width: constraints.minWidth,
height: constraints.minHeight),
],
);
}),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'untitled',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late final AnimationController _controller =
AnimationController(duration: const Duration(seconds: 2), vsync: this);
late final Animation<Offset> _animation =
Tween<Offset>(begin: Offset.zero, end: const Offset(1, 0)).animate( // #1
CurvedAnimation(parent: _controller, curve: Curves.easeOutQuint));
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SlideTransition(
position: _animation,
child: InkWell(
onTap: () async {
try {
await _controller.forward().orCancel;
} on TickerCanceled {
// the animation got canceled, probably because it was disposed of
}
_controller.reset();
},
child: Container(
width: 100,
height: 100,
margin: const EdgeInsets.all(50),
color: Colors.red,
),
),
),
);
}
}-
Offset(1, 0)means: 1 unit to the right, where the size of a unit depends on the size ofSlideTransitionschild: In this case 200 pixels (Containerswidth + 2 *margin).

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: MyCustomPainter(),
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
);
}
}
class MyCustomPainter extends CustomPainter {
double _radius = 0;
@override
void paint(Canvas canvas, Size size) {
_radius = size.shortestSide / 2;
canvas.drawCircle(Offset(size.width / 2, size.height / 2), _radius,
Paint()..color = Colors.green);
}
@override
bool shouldRepaint(covariant MyCustomPainter oldDelegate) {
return false; // #1
}
}- Usually we should compare
thiswitholdDelegate. But in this case, it does not seem necessary:paintis always called anyway when the window size changes, withoutshouldRepaintbeing called at all.

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: MyWidget(),
),
);
}
}
class MyWidget extends StatelessWidget {
MyWidget({super.key});
final Future<String> hello =
Future.delayed(const Duration(seconds: 4), () => 'Hello');
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: hello,
builder: ((context, snapshot) {
final text = snapshot.connectionState == ConnectionState.done
? snapshot.data ?? ''
: 'waiting';
return Text(text, style: const TextStyle(fontSize: 64));
}),
);
}
}flutter.dev/BottomNavigationBar

import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelesslWidget(),
);
}
}
class MyStatelesslWidget extends StatelessWidget {
const MyStatelesslWidget({super.key});
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('TabBar Sample'),
bottom: const TabBar(tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.business), text: 'Business'),
Tab(icon: Icon(Icons.school), text: 'School'),
]),
),
body: TabBarView(children: [
for (int i = 0; i < 3; i++)
Center(
child: _widgetOptions[i],
)
]),
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('NavigationRail Sample'),
),
body: Row(
children: [
NavigationRail(
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.business),
label: Text('Business'),
),
NavigationRailDestination(
icon: Icon(Icons.school),
label: Text('School'),
),
],
selectedIndex: _selectedIndex,
labelType: NavigationRailLabelType.all,
onDestinationSelected: _onItemTapped,
),
Expanded(
child: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index, BuildContext context) {
setState(() {
_selectedIndex = index;
});
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Drawer Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
drawer: Drawer(
child: ListView(
children: [
ListTile(
title: const Text('Home'),
leading: const Icon(Icons.home),
onTap: () => _onItemTapped(0, context),
),
ListTile(
title: const Text('Business'),
leading: const Icon(Icons.business),
onTap: () => _onItemTapped(1, context),
),
ListTile(
title: const Text('School'),
leading: const Icon(Icons.school),
onTap: () => _onItemTapped(2, context),
),
],
),
),
);
}
}flutter.dev/cookbook/validation

import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const appTitle = 'Form Validation Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
),
body: const MyCustomForm(),
),
);
}
}
// Create a Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
@override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyCustomFormState>.
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 100,
child: TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
icon: Icon(Icons.text_fields),
),
// The validator receives the text that the user has entered.
validator: validateNotEmpty,
),
),
SizedBox(
height: 100,
child: TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
icon: Icon(Icons.numbers),
),
validator: validateNotEmpty
.then(validateIsNumber)
.then(validateIsInteger),
),
),
ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},
child: const Text('Submit'),
),
],
),
),
);
}
String? validateNotEmpty(String? value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
}
String? validateIsNumber(String? value) {
if (value == null) {
return '';
}
if (double.tryParse(value) == null) {
return 'Please enter a number';
}
return null;
}
String? validateIsInteger(String? value) {
if (value == null) {
return '';
}
if (int.tryParse(value) == null) {
return 'Please enter a valid integer number';
}
return null;
}
}
typedef ValidatorFunction = String? Function(String?);
extension Concatenation on ValidatorFunction {
ValidatorFunction then(ValidatorFunction validator) {
return (value) {
final messageText = this(value);
if (messageText == null) {
return validator(value);
}
return messageText;
};
}
}-
I wanted to chain the validators:
validator: validateNotEmpty .then(validateIsNumber) .then(validateIsInteger),
therefore:
typedef ValidatorFunction = String? Function(String?); extension Concatenation on ValidatorFunction { ValidatorFunction then(ValidatorFunction validator) { return (value) { final messageText = this(value); if (messageText == null) { return validator(value); } return messageText; }; } }
A scrollable table should consist of 30 rows with 2 columns each. The columns are to be headed with Name and Age. The Name column shall occupy 80 percent of the row width. The rows shall consist of input fields.

import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const appTitle = 'Form Validation Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: SizedBox(
child: Table(
columnWidths: const {
0: FractionColumnWidth(0.8),
1: FractionColumnWidth(0.2)
},
border: TableBorder.all(),
children: [
const TableRow(
decoration: BoxDecoration(color: Colors.lightBlue),
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Name:',
style: TextStyle(fontSize: 16),
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Age:',
style: TextStyle(fontSize: 16),
),
),
],
),
...List<TableRow>.generate(
30,
(index) {
return const TableRow(
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
decoration: null,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
decoration: null,
),
),
],
);
},
)
],
),
),
),
),
),
);
}
}