How to add a texfield inside the App bar in Flutter? - flutter

I'am having trouble in having a TextField on the AppBar so the user can enter input similarly to using a search bar. I need to take the user input and do something with it so it's not a search within my app. This is why it makes senses to use a TextField.
Now, I've succeeded in having the TextField on the left side of my AppBar . The problem is that the TextField is a square and doesn't take enough space so you can see what you're writing.
Link to what it looks like:
In code this is how it was made:
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Myseum',
theme: new ThemeData(
primarySwatch: Colors.blue,
fontFamily: 'Raleway',
),
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"Myseum",
style: TextStyle(
fontFamily: 'Raleway',
fontStyle: FontStyle.italic,
fontSize: 25,
),
),
leading: prefix0.TextBox(), // TextBox is the widget I made.
backgroundColor: Colors.black,
),
Now the widget TextBox()
class TextBox extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
color: Colors.white,
child: TextField(
decoration:
InputDecoration(border: InputBorder.none, hintText: 'Search'),
),
);
}
}

Like mentioned in the comments - put your text field in title widget... I converted your code to a simple stateful widget to give you an idea.
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool typing = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: typing ? TextBox() : Text("Title"),
leading: IconButton(
icon: Icon(typing ? Icons.done : Icons.search),
onPressed: () {
setState(() {
typing = !typing;
});
},
),
),
body: Center(
child: Text("Your app content"),
),
);
}
}
class TextBox extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
color: Colors.white,
child: TextField(
decoration:
InputDecoration(border: InputBorder.none, hintText: 'Search'),
),
);
}
}

Related

flutter: is there an easy way to layout my app bar?

I'm new to flutter so please bear with me. When I implement an app bar, sometimes it only has a title, some other time it has a title and returns button on the left of the bar, also, sometimes it adds another button on the right of the bar. I have to layout differently to suit different situations which are quite troublesome. Is there a convenient widget that provides three optional properties to allow me to set my title, left button, and right button or any good layout strategy? What I have done is below.
AppBar(
backgroundColor: Colors.gray,
elevation: 0.0,
title: Container(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(bottom: ScreenUtil.dp(11)),
height: ScreenUtil.dp(22),
width: ScreenUtil.dp(160),
child: Text(
'title',
style: TextStyle(
fontSize: ScreenUtil.sp(17), fontFamily: FontFamily.family, color: Colors.black, fontWeight: FontWeight.w600
)
),
alignment: Alignment.center,
),
),
),
),
```
You should learn more about the Appbar with other properties to assist with the things you need like leading, trailing, ...
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: _title,
home: MyStatelessWidget(),
);
}
}
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
final SnackBar snackBar = const SnackBar(content: Text('Showing Snackbar'));
void openPage(BuildContext context) {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Next page'),
),
body: const Center(
child: Text(
'This is the next page',
style: TextStyle(fontSize: 24),
),
),
);
},
));
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
leading: Icon(Icons.navigate_next),
title: const Text('AppBar Demo'),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
scaffoldKey.currentState.showSnackBar(snackBar);
},
),
IconButton(
icon: const Icon(Icons.navigate_next),
tooltip: 'Next page',
onPressed: () {
openPage(context);
},
),
],
),
body: const Center(
child: Text(
'This is the home page',
style: TextStyle(fontSize: 24),
),
),
);
}
}

Method setState() is not updating the UI (Flutter)

My home screen is a Scaffold with a ListView at its body and a floating action button at the bottom. The action button takes the user to a second screen, where he can type a text into a text input and press save. The save button calls a method at the home screen that adds the text to the List variable over which ListView is based. The problem is: the List variable is being updated (I can see on the log), but the setState is not updating the ListView. What am I doing wrong?
Here's the code from the Home Screen:
import 'package:flutter/material.dart';
import 'addCounter.dart';
class Home extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
List lista = <Widget>[];
void incrementLista(newItem) {
print('$lista');
setState(() {
lista.add(Box('newItem'));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List of Counters'),
backgroundColor: Colors.deepPurple[1000],
),
body: Builder(
builder: (context)=>
Center(
child: ListView(children: lista),
),),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.grey[1000],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddCounter(f: incrementLista)));
},
child: Icon(Icons.add, color: Colors.white)),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.grey[700],
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('Lista'),
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text('Gráfico'),
),
],
selectedItemColor: Colors.blue,
),
);
}
}
And here is the code from the addCounter.dart:
import 'package:flutter/material.dart';
class AddCounter extends StatefulWidget {
final Function f;
AddCounter({#required this.f});
#override
_AddCounterState createState() => _AddCounterState();
}
class _AddCounterState extends State<AddCounter> {
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add a counter'),
backgroundColor: Colors.blue,
),
body: Column(children: [
Padding(
padding: EdgeInsets.all(15),
child: TextField(
controller: myController,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2)),
hintText: 'Type a name for the counter'),
),
),
RaisedButton(
color: Colors.green,
onPressed: () {
widget.f(myController.text);
Navigator.pop(context);
},
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
)
]));
}
}
I don't think the code for the Box widget is relevant. It is basically a card with a title.
#pskink gave me an answer that worked perfectly. Here it is:
basically you should not use such a list of widgets, data and presentation layers should be separated, instead you should use a list of data only, see https://flutter.dev/docs/cookbook/gestures/dismissible for more info

type '(String) => dynamic' is not a subtype of type 'Widget'

I am trying to navigate to a page using named route.
Routes in the main file:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterShare',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepPurple,
accentColor: Colors.teal,
),
home: Home(),
routes: {
'/search': (BuildContext context) => Search(),
},
);
}
}
Pushing to the page:
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('BookClub'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).pushNamed('/search');
})
],
),
drawer: AppDrawer(),
);
}
}
Error:
type '(String) => dynamic' is not a subtype of type 'Widget'
The relevant error-causing widget was
Search lib\main.dart:21
This is my first time building an app and i am not getting a solution.
Error is in the routes in main.dart file.
Search code:
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
TextEditingController searchController = TextEditingController();
Future<QuerySnapshot> searchResultsFuture;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.8),
appBar: buildSearchField(),
body: buildNoContent()
);
}
}
AppBar buildSearchField() {
return AppBar(
backgroundColor: Colors.white,
title: TextFormField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search for a book",
filled: true,
prefixIcon: Icon(
Icons.account_box,
size: 28.0,
),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: null,
),
),
onFieldSubmitted: null,
),
);
}
Container buildNoContent() {
final Orientation orientation = MediaQuery.of(context).orientation;
return Container(
child: Center(
child: ListView(
shrinkWrap: true,
children: <Widget>[
SvgPicture.asset(
'assets/images/search.svg',
height: orientation == Orientation.portrait ? 300.0 : 200.0,
),
Text(
"Find Users",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w600,
fontSize: 60.0,
),
),
],
),
),
);
}
Hopefully this helps. I am stuck at this from past 3 hours and could not find anything to solve this.
main.dart. You have to add the start page to initialRoute. You can remove the 'home' parameter.
initialRoute: HomeScreen(),
routes: {
"/search" (context) => Search()
},
So, home.dart file in;
Navigator.of(context).pushNamed('/search');

How to dynamically generate and store state of a custom stateful widget in the parent class?

I am currently stuck with dynamic generation of widget and its state maintenance.
This is my code.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark().copyWith(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
DescriptionTextField(),
DividerAddDescription(onPressed: () => print('Add another description'))
],
),
),
),
);
}
}
class DescriptionTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white38),
child: TextField(
minLines: 1,
maxLines: null,
style: TextStyle(
fontSize: 16,
),
decoration: InputDecoration(
hintText: 'Enter description',
hintStyle: TextStyle(
fontSize: 16,
),
contentPadding: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: InputBorder.none,
),
),
);
}
}
class DividerAddDescription extends StatelessWidget {
DividerAddDescription({#required this.onPressed});
final Function onPressed;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Divider(
thickness: 1,
),
),
FloatingActionButton(
onPressed: onPressed,
child: Icon(
Icons.add,
color: Color(0xFF232F34),
),
backgroundColor: Colors.orange,
),
],
);
}
}
This is how the screen looks like.
What I am trying to achieve:
when clicking on the plus button, another DescriptionTextField will be added to the Column widget.
as a new DescriptionTextField is added, if the previous DescriptionTextField has description text in it, the text should be preserved.
What I don't know how to do:
where should the description text be stored? Is it in DescriptionTextField's state? i.e. do I need to make it a Stateful widget instead?
when I have multiple DescriptionTextField, how am I supposed to store the state? e.g. the description text
You should create a List variable in your State, add the new elements there and call the setState method when adding.
class _HomeScreenState extends State<HomeScreen> {
//Create a field which hold the elements
List<DescriptionTextField> myDescriptions = List<DescriptionTextField>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
...myDescriptions, //Add the elements to the Column using the spread operator
DividerAddDescription(onPressed: () => setState(() => myDescriptions.add(DescriptionTextField(key: UniqueKey()))) //Adding new widget
],
),
),
),
);
}
}
I recommend you to use a key value in your DescriptionTextField widgets, because you will be adding widget dynamically and Flutter could struggle to match the respectively their states.
There are of course many improvements, but from my perspective and what I understand from your description, this may help you.

How to make flutter TextField at bottom of screen show over IME

My page is a SingleChildScrollView,it's has a column as child .And I have a TextField at bottom of the screen.
How can I make the TextField show over of IME when IME is expend.
now the TextField is covered by IME. And it is invisible,util scroll manually.
demo code
import 'package:flutter/material.dart';
class Demo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
elevation: 0.0,
title: new Text(
'title',
),
),
body: new Home(),
),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SingleChildScrollView(
child: new Column(
children: <Widget>[
new ImageZone(),
new Div(),
new TextEditZone(),
new Div(),
],
),
);
}
}
class ImageZone extends StatefulWidget {
#override
State<StatefulWidget> createState() => new ImageZoneState();
}
class ImageZoneState extends State<ImageZone> {
#override
Widget build(BuildContext context) {
return new Material(
elevation: 1.0,
color: Colors.white,
child: new Container(
height: 380.0,
width: double.infinity,
child: new Icon(
Icons.access_time,
size: 360.0,
),
),
);
}
}
class Div extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 12.0,
);
}
}
class TextEditZone extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new TextEditZoneState();
}
}
class TextEditZoneState extends State<TextEditZone> {
#override
Widget build(BuildContext context) {
return new Material(
elevation: 1.0,
child: new Container(
width: double.infinity,
color: Colors.white,
padding: new EdgeInsets.all(16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
new Div(),
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
new Div(),
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
],
),
),
);
}
}
screen Shot:
What I want:
TextField auto scroll over IME when I click one of TextField.
Your problem was solved in this example here
, Please go through and wrap all your TextField 's inside EnsureVisibleWhenFocused and this will bring the TextField just above the keyboard.
Regards,
Mahi