- Q1: Change Drawer Icon
- Q2: Detect behaviors on any Widgets
- Q3: Limit the number of lines and add ellipsis
- Q3: Create Transparent Appbar & “Floating” TextField
- Q4: Create a Search Bar Using ShowSearch()
- Q5: Vertical Viewport Was Given Unbounded Height
- Q6: Navigator & Route
- Q7 Click the blank space to cancel the TextField focus
Q1: Change Drawer Icon
The drawer has default three horizontal bars as default icon. To change it, use leading property of AppBar.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.accessible),
onPressed: () => Scaffold.of(context).openDrawer(), // will open the Widget defined in property 'drawer'
),
),
drawer: MyDrawer(),
);
Q2: Detect behaviors on any Widgets
see GestureDetector class. Use Padding to constrain child’s size.
Q3: Limit the number of lines and add ellipsis
Text(
'text',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Q3: Create Transparent Appbar & “Floating” TextField
The goal is to create a “floating” textfield at the center position of appbar.
The steps are as follows:
- Add a TextField Widget to AppBar’s title property
- Make a translucent appbar and let the body Widget can go behind the appbar and be visible
- Style the TextField
1. Add a TextField Widget to AppBar’s title property
import 'package:flutter/material.dart';
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: MyCustomTextField(), //add custom textfield
),
body: Container(height: 500.0, color: Colors.purple),
);
}
}
// definition of custom textfield
class MyCustomTextField extends StatefulWidget {
@override
_MyCustomTextFieldState createState() => _MyCustomTextFieldState();
}
class _MyCustomTextFieldState extends State<MyCustomTextField> {
@override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(),
labelText: 'Search',
)
);
}
}
MyCustomTextField
needs to be a stateful widget since we will manage its focus state later.
The page now looks like:
Why use enabledBorder instead of border?
see how Flutter API indicates
If custom BorderSide values are desired for a given state, all four borders – errorBorder, focusedBorder, enabledBorder, disabledBorder – must be set.
I have tried to set border property at first but found it didn’t work.
I suppose the question to be that enabledBorder
has a higher priority to display than border
does – even I have set border
, it will use default enabledBorder
. (Wrong? Help me to correct it!)
2. Make a translucent appbar and let the body Widget can go behind the appbar and be visible
My reference:
Fullscreen page with transparent AppBar in Flutter
You may notice that the appbar seems to have a solid white background. We only want the textfield to be visible – the surroudings should be transparent.
We set backgroundcolor of AppBar to Colors.transparent
.
How to display body under the AppBar of scaffold widget and not below?
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true, // add this line
appBar: AppBar(
backgroundColor: Colors.transparent, // add this line
title: MyCustomTextField(),
),
body: Container(height: 500.0, color: Colors.purple),
);
}
Now the AppBar looks as:
Why is there a grey color background? This is because that AppBar has a none-zero elevation, this grey block is its shadow. Thus, we set elevation
to 0.0.
appBar: AppBar(
elevation: 0.0, // add this line
backgroundColor: Colors.transparent,
title: MyCustomTextField(),
),
The shadow was removed!
Style the TextField
Now we can decoration our textfield. The textfield is supposed to be rounded, white border, white backgroundcolor.
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.transparent,
title: Container(
// height: AppBar().preferredSize.height * 0.8,
child: Material(
// elevation: 5,
borderRadius: BorderRadius.all(Radius.circular(100.0)),
color: Colors.transparent,
child: MyCustomTextField(),
),
),
),
@override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
fillColor: Colors.white, // change from here ...
filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Colors.white,
),
), // to here
labelText: 'Search',
)
);
}
fillColor
: The base fill color of the decoration’s container color. The decoration’s container is the area which is filled if filled is true and bordered per the border.Thus, property
filled
has to be true. Otherwise, the decoration’s container color will not be assigned white.
Additional: How to Add Drop Shadow to TextFormField In Flutter
Done!
Want to modify textfield’s height? Put TextField
in a Container (as the comment), use height
property to modify it!
Q4: Create a Search Bar Using ShowSearch()
To let it navigate to a new screen with a focused textfield(flutter default search textfield) after we click and try to focus the textfield created in Q3.
My reference:
Focus and text fields
Flutter’s Search Support (The Boring Flutter Development Show, Ep. 10)
- Create a FocusNode.
- Pass the FocusNode to a TextField.
- Unfocus the TextField when it is tapped and showSearch()
- Define SearchDelegate
class MyCustomTextField extends StatefulWidget {
@override
_MyCustomTextFieldState createState() => _MyCustomTextFieldState();
}
class _MyCustomTextFieldState extends State<MyCustomTextField> {
// add from here ...
FocusNode myFocusNode;
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
@override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
super.dispose();
}
// to here
@override
Widget build(BuildContext context) {
return TextField(
focusNode: myFocusNode,
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Colors.white,
),
),
labelText: 'Search',
),
//add from here ...
onTap: () {
showSearch(
context: context,
delegate: RecipeSearch(),
);
myFocusNode
.unfocus(); // let this textfield always be the unfocus state -- border unchanged
}, // to here
);
}
}
// add this class
class RecipeSearch extends SearchDelegate<String> {
@override
List<Widget> buildActions(BuildContext context) {
return [ // actions(shown on the right side)
IconButton(
icon: Icon(Icons.clear),
onPressed: () => query = '', // when click, clear the text in the textfield
)
];
}
@override
Widget buildLeading(BuildContext context) {
return IconButton( // leading in the search bar
icon: Icon(Icons.arrow_back),
onPressed: () => close(context, null),
);
}
@override
Widget buildResults(BuildContext context) {
return Container(); // the Widget show below the search bar
}
@override
Widget buildSuggestions(BuildContext context) {
return Text(query); // the Widget show below the search bar when textfield is changed
}
}
Q5: Vertical Viewport Was Given Unbounded Height
Q6: Navigator & Route
Introduction
- push / pop, maybepop / canpop
- pushReplacementNamed / popAndPushNamed
- pushNamedAndRemoveUntil / popUntil
- how to send data and retrieve data?
Steps to Create MyRoute
and Navigate
Clean Navigation in Flutter Using Generated Routes gives a clear steps to create MyRoute
. (Change the classname in this tutorial from Route
to MyRoute
since it will triggle an error – maybe because Route
has been already defined in other dart packages)
You can also use
Navigator.popUntil(
context,
ModalRoute.withName(
Navigator.defaultRouteName,
),
),
to reach the root of the stack.
My reference: How to use popUntil properly to reach the root of the stack?
If after your navigation it returns a black screen, make sure to just use Scaffold as a top widget instead of MaterialApp in all nested screens.
My reference: Flutter Navigator.pop(context) returning a black screen