Related
So I made a CRUD app with Firebase Firestore in Flutter. I have this error where it says
Exception caught by gesture
═══════════════════════
a document path must be a non-empty string
'package:cloud_firestore/src/collection_reference.dart':
package:cloud_firestore/src/collection_reference.dart:1
Failed assertion: line 116 pos 14: 'path.isNotEmpty'
I build this app with various tutorial videos in Youtube. I can make the Create, Read, and Delete features but I face this problem with Update features. Here's the code ...or check this Github https://github.com/rayhanyovi/Dapurku
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:dapurkuu/warna.dart';
import 'package:dapurkuu/widget.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
//=====================================
const Color Red = Color(0xFFDA4040);
const Color Blue = Color(0xFF5F52EE);
const Color Black = Color(0xFF3A3A3A);
const Color Grey = Color(0xFF717171);
const Color BGColor = Color(0xFFEEEFF5);
final controllerName = TextEditingController();
final controllerAge = TextEditingController();
final controllerBirthday = TextEditingController();
final updateName = TextEditingController();
final updateAge = TextEditingController();
final updateBirthday = TextEditingController();
//=====================================
class User {
String id;
final String name;
final int age;
final DateTime birthday;
User({
this.id = '',
required this.name,
required this.age,
required this.birthday,
});
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'age': age,
'birthday': birthday,
};
static User fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
age: json['age'],
birthday: (json['birthday'] as Timestamp).toDate(),
);
}
//=====================================
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent));
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Test",
home: Home(),
);
}
}
//=====================================
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final CollectionReference _users =
FirebaseFirestore.instance.collection('users');
#override
Widget build(BuildContext context) {
Future createUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.set(json);
Future updateUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.update(json);
}
}
Widget buildUser(User user) {
return Container(
margin: EdgeInsets.only(
right: 20,
left: 20,
bottom: 15,
),
child: Material(
child: ListTile(
onTap: () {
print("card");
},
contentPadding:
EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 15),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
tileColor: Colors.white,
title: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text(
user.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jumlah: ${user.age}',
),
Text(
'Kadaluarsa: ${DateFormat('dd MMMM yyyy').format(user.birthday)}')
],
),
trailing: Wrap(spacing: 0, children: [
IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () async {
await Edit(context, createUser);
},
),
IconButton(
icon: Icon(Icons.delete),
iconSize: 24,
color: Colors.red,
onPressed: () {
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
docUser.delete();
},
),
]),
),
),
);
}
return Scaffold(
backgroundColor: BGColor,
appBar: _AppBar(),
body: Column(
children: [
/* JUDUL */
Column(
children: [
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: SearchBox()),
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Text(
'Bahan Dapurmu',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Black,
),
),
)
],
),
/* STREAM BUILDER */
StreamBuilder(
stream: readUsers(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final users = snapshot.data!;
return Expanded(
child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: users.map(buildUser).toList(),
),
);
} else if (snapshot.hasError) {
return Container(
child: Text("data kosong"),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Create(context, createUser);
},
child: Icon(Icons.add),
),
);
}
Edit(BuildContext context, Future<dynamic> updateUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: updateName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: updateAge,
keyboardType: TextInputType.number,
),
TextField(
controller: updateBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
updateBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Ubah Data"),
onPressed: () {
final user = User(
name: updateName.text,
age: int.parse(updateAge.text),
birthday: DateTime.parse(updateBirthday.text),
);
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
updateUser(user);
}),
],
);
});
}
Create(BuildContext context, Future<dynamic> createUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: controllerName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: controllerAge,
keyboardType: TextInputType.number,
),
TextField(
controller: controllerBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
controllerBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Tambahkan"),
onPressed: () {
final user = User(
name: controllerName.text,
age: int.parse(controllerAge.text),
birthday: DateTime.parse(controllerBirthday.text),
);
createUser(user);
}),
],
);
});
}
Stream<List<User>> readUsers() => FirebaseFirestore.instance
.collection('users')
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => User.fromJson(doc.data())).toList());
}
//=====================================
AppBar _AppBar() {
return AppBar(
elevation: 0,
backgroundColor: BGColor,
title: Center(
child: Text(
"Dapurku",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Black,
),
),
),
);
}
//=====================================
class UpdateButton extends StatelessWidget {
const UpdateButton({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () {},
),
);
}
}
//=====================================
class SearchBox extends StatelessWidget {
const SearchBox({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 10),
child: const TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0),
prefixIcon: Icon(
Icons.search,
color: Black,
size: 20,
),
prefixIconConstraints: BoxConstraints(
maxHeight: 20,
minWidth: 25,
),
border: InputBorder.none,
hintText: "Cari Bahan...",
hintStyle: TextStyle(
color: Grey,
)),
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
);
}
}
Can you tell me what I did wrong or help me solve the problem? I've been looking for it anywhere and solving this problem for days. It is for my school assignment :/
I tried to create a task app using flutter, So I created a text field in DialogBox and my aim is when I add some text into the text field and when I clicked the OK button, I need to show that text in the list. but I have no idea how to call a method in another class, I've added my two classes.
ListTask Class
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
const ListTask({Key? key}) : super(key: key);
#override
State<ListTask> createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> _displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
TaskApp Class
import 'package:flutter/material.dart';
import 'package:task_app/Widgets/listtasks.dart';
import 'package:task_app/Widgets/logo.dart';
import 'package:task_app/Widgets/searchbar.dart';
class TaskApp extends StatefulWidget {
const TaskApp({Key? key}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Logo(),
SizedBox(height: 0),
SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
_displayTextInputDialog(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
Calling point of that method in TaskApp Class:
Method:
You can give this a try, it will call a method defined in ListTask(StatefulWidget) from TaskApp(StatefulWidget) widget.
TaskApp.dart
import 'package:flutter/material.dart';
import 'package:vcare/Screens/tetxing1.dart';
class TaskApp extends StatefulWidget {
final ListTask listTask;
const TaskApp({Key? key,required this.listTask}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
// Logo(),
SizedBox(height: 0),
//SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ListTask().method1(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
ListTask.dart
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
method1(context) => createState().displayTextInputDialog(context);
#override
_ListTaskState createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
if you find this solution helpful please mark as accepted answer
I wanted to send Data/images from one page to another. In the Homepage when I tap on the add Icon button image should be passed to the Cart page and if the icon is tapped again image is removed from the Cart page. But, the cart page should be accessed from bottom navigation bar.
but it is showing an error called 1 positional argument(s) expected, but 0 found.
Try adding the missing arguments.. when it calls the cart page.
HomePage.dart file
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: NavBar(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Dish> _dishes = List<Dish>();
List<Dish> _cartList = List<Dish>();
#override
void initState() {
super.initState();
_populateDishes();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0, top: 8.0),
child: GestureDetector(
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Icon(
Icons.shopping_cart,
size: 36.0,
),
if (_cartList.length > 0)
Padding(
padding: const EdgeInsets.only(left: 2.0),
child: CircleAvatar(
radius: 8.0,
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Text(
_cartList.length.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12.0,
),
),
),
),
],
),
onTap: () {
if (_cartList.isNotEmpty)
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Cart(_cartList),
),
);
},
),
)
],
),
body: _buildGridView(),
);
}
ListView _buildListView() {
return ListView.builder(
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 2.0,
),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
);
},
);
}
GridView _buildGridView() {
return GridView.builder(
padding: const EdgeInsets.all(4.0),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Card(
elevation: 4.0,
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
item.icon,
color: (_cartList.contains(item))
? Colors.grey
: item.color,
size: 100.0,
),
Text(
item.name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subhead,
)
],
),
Padding(
padding: const EdgeInsets.only(
right: 8.0,
bottom: 8.0,
),
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
],
));
});
}
void _populateDishes() {
var list = <Dish>[
Dish(
name: 'Chicken Zinger',
icon: Icons.fastfood,
color: Colors.amber,
),
Dish(
name: 'Chicken Zinger without chicken',
icon: Icons.print,
color: Colors.deepOrange,
),
Dish(
name: 'Rice',
icon: Icons.child_care,
color: Colors.brown,
),
Dish(
name: 'Beef burger without beef',
icon: Icons.whatshot,
color: Colors.green,
),
Dish(
name: 'Laptop without OS',
icon: Icons.laptop,
color: Colors.purple,
),
Dish(
name: 'Mac wihout macOS',
icon: Icons.laptop_mac,
color: Colors.blueGrey,
),
];
setState(() {
_dishes = list;
});
}
}
Cart.dart file
import 'package:flutter/material.dart';
import 'dish_object.dart';
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
#override
_CartState createState() => _CartState(this._cart);
}
class _CartState extends State<Cart> {
_CartState(this._cart);
List<Dish> _cart;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: ListView.builder(
itemCount: _cart.length,
itemBuilder: (context, index) {
var item = _cart[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
_cart.remove(item);
});
},
),
),
),
);
},
),
);
}
}
NavBar.dart file
import 'package:flutter/material.dart';
import 'package:sharewallpaper/cart.dart';
import 'package:sharewallpaper/main.dart';
class NavBar extends StatefulWidget {
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
int _currentIndex = 0;
final List<Widget> _children = [
MyHomePage(),
Cart(), ** This line is throwing an error **
];
void onTappedBar(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTappedBar,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.bookmark), title: Text('BookMark')),
],
),
);
}
}
Yep, it will throw an error because the constructor of the Cart class is expecting one parameter to be passed in. You could use a named constructor instead like this:
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
That way, you can call it like so:
Cart(cart: _cartList),
But if you actually need the cart list, I would recommend that you write a provider to keep track of the cart data across screens.
i have setup banner ads in flutter and those are overlapping the bottom navigation bar
I want to display ads below that bottom navigation bar,
is there any way that i can add a margin below the bottom navigation bar ?
i have implemented ads in home.dart (mainpage)
import 'package:provider/provider.dart';
import '../../ui/widgets/bottom_nav_bar.dart';
import '../../core/utils/theme.dart';
import 'search_page.dart';
import 'category.dart';
import 'main_page.dart';
import 'settings.dart';
import 'package:flutter/material.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'for_you.dart';
const String AD_MOB_APP_ID = 'ca-app-pub-3940256099942544~3347511713';
const String AD_MOB_TEST_DEVICE = 'DEC3010B2445165B43EB949F5D97D0F8 - run ad then check device logs for value';
const String AD_MOB_AD_ID = 'ca-app-pub-3940256099942544/6300978111';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
BannerAd _bannerAd;
static final MobileAdTargetingInfo targetingInfo = new MobileAdTargetingInfo(
testDevices: <String>[AD_MOB_TEST_DEVICE],
);
BannerAd createBannerAd() {
return new BannerAd(
adUnitId: AD_MOB_AD_ID,
size: AdSize.banner,
targetingInfo: targetingInfo,
);
}
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedIndex = 0;
final PageController _pageController = PageController();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
_pageController.dispose();
}
#override
Widget build(BuildContext context) {
final stateData = Provider.of<ThemeNotifier>(context);
final ThemeData state = stateData.getTheme();
FirebaseAdMob.instance.initialize(appId: AD_MOB_APP_ID);
_bannerAd = createBannerAd()..load()..show();
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
centerTitle: false,
backgroundColor: state.primaryColor,
elevation: 0,
title: Text(
'RevWalls',
style: state.textTheme.headline,
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: state.textTheme.body1.color,
),
onPressed: () => showSearch(
context: context, delegate: WallpaperSearch(themeData: state)),
)
],
),
body: Container(
color: state.primaryColor,
child: PageView(
controller: _pageController,
physics: BouncingScrollPhysics(),
onPageChanged: (index) {
setState(() {
_selectedIndex = index;
});
},
children: <Widget>[
MainBody(),
Category(),
ForYou(),
SettingsPage(),
],
),
),
bottomNavigationBar: BottomNavyBar(
selectedIndex: _selectedIndex,
unselectedColor: state.textTheme.body1.color,
onItemSelected: (index) {
_pageController.jumpToPage(index);
},
selectedColor: state.accentColor,
backgroundColor: state.primaryColor,
showElevation: false,
items: [
BottomNavyBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavyBarItem(
icon: Icon(Icons.category),
title: Text('Subreddits'),
),
BottomNavyBarItem(
icon: Icon(Icons.phone_android),
title: Text('Exact Fit'),
),
BottomNavyBarItem(
icon: Icon(Icons.settings),
title: Text('Settings'),
),
],
),
);
}
Widget oldBody(ThemeData state) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
return <Widget>[
SliverAppBar(
backgroundColor: state.primaryColor,
elevation: 4,
title: Text(
'reWalls',
style: state.textTheme.headline,
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search, color: state.accentColor),
onPressed: () {
showSearch(
context: context,
delegate: WallpaperSearch(themeData: state));
},
)
],
floating: true,
pinned: _selectedIndex == 0 ? false : true,
snap: false,
centerTitle: false,
),
];
},
body: Container(
color: state.primaryColor,
child: PageView(
controller: _pageController,
onPageChanged: (index) {
setState(() {
_selectedIndex = index;
});
},
children: <Widget>[
MainBody(),
Category(),
ForYou(),
SettingsPage(),
],
),
),
);
}
}
and here is the bottom navigation bar -
library bottom_navy_bar;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class BottomNavyBar extends StatelessWidget {
final int selectedIndex;
final double iconSize;
final Color backgroundColor, selectedColor, unselectedColor;
final bool showElevation;
final Duration animationDuration;
final List<BottomNavyBarItem> items;
final ValueChanged<int> onItemSelected;
BottomNavyBar(
{Key key,
this.selectedIndex = 0,
this.showElevation = true,
this.iconSize = 20,
this.backgroundColor,
this.selectedColor,
this.unselectedColor,
this.animationDuration = const Duration(milliseconds: 250),
#required this.items,
#required this.onItemSelected}) {
assert(items != null);
assert(items.length >= 2 && items.length <= 5);
assert(onItemSelected != null);
}
Widget _buildItem(BottomNavyBarItem item, bool isSelected) {
return AnimatedContainer(
width: isSelected ? 120 : 50,
height: double.maxFinite,
duration: animationDuration,
decoration: BoxDecoration(
color: isSelected ? selectedColor.withOpacity(0.2) : backgroundColor,
borderRadius: BorderRadius.all(Radius.circular(100.0)),
),
alignment: Alignment.center,
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8),
child: IconTheme(
data: IconThemeData(
size: iconSize,
color: isSelected ? selectedColor : unselectedColor),
child: item.icon,
),
),
isSelected
? DefaultTextStyle.merge(
style: TextStyle(
fontSize: 16,
color: selectedColor,
fontWeight: FontWeight.bold),
child: item.title,
)
: SizedBox.shrink()
],
)
],
),
);
}
#override
Widget build(BuildContext context) {
return Container(
color: backgroundColor,
child: Container(
width: double.infinity,
height: 55,
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: items.map((item) {
var index = items.indexOf(item);
return GestureDetector(
onTap: () {
onItemSelected(index);
},
child: _buildItem(item, selectedIndex == index),
);
}).toList(),
),
),
);
}
}
class BottomNavyBarItem {
final Icon icon;
final Text title;
BottomNavyBarItem({
#required this.icon,
#required this.title,
}) {
assert(icon != null);
assert(title != null);
}
}
Please help
adding builder like this will solve the problem
var paddingBottom = 60.0;
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
//
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'World General info',
//theme: ThemeData(primarySwatch: Colors.cyan,),
theme: ThemeData(
primaryColor: Colors.cyan,
accentColor: Colors.green,
textTheme: TextTheme(bodyText2: TextStyle(color: Colors.purple)),
),
home: MyHomePage(title: 'World General Info'),
builder: (BuildContext context, Widget child) {
return new Padding(
child: child,
padding: EdgeInsets.only(bottom: paddingBottom),
);
}
);
}
}
You can use the MediaQuery.of(context) for that.
Wrap the whole Code inside a Container of height: MediaQuery.of(context).size.height - 60 . (the height of ad)
Column(
children: [
Container(
height: MediaQuery.of(context).size.height - 60,
child: HomePage(),
),
BannerAd(),
]
);
Found answer myself
We can use this to set margin in a container with other things like height, width
This code will add margin to bottom of bottom nav bar, as per my need i want to show ads below navbar so this solves my problem
margin: const EdgeInsets.only(bottom: 50)
Add this to your scaffold
bottomNavigationBar: Container(
height: 50.0,
color: Colors.white,
),
Think Simplest bro ... wrap your column ( mainAxisSize : MainAxisSize.min )
Scaffold(
appBar: _appBar,
body: _body,
bottomNavigationBar: Column(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: Colors.amber,
height: 70,
child: Center(child: Text('Banner'))),
BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.add), label: 'Add'),
BottomNavigationBarItem(icon: Icon(Icons.add), label: 'Add'),
BottomNavigationBarItem(icon: Icon(Icons.add), label: 'Add')
],
)
]))
I'm learning Flutter. I have a ListView and I would like to make the list items clickable. My idea is that when the user clicks on an item, it will be directed to another screen. Each buttom should leads to different screen. I'm having trouble implementing it, I don't know what to use: gesture detector or ontap. What should I do? Should I use ListTile instead of ListView?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = "ListView List";
return MaterialApp(
title: title,
home: Scaffold(appBar: AppBar(
title: Text(title),
),
body: new ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: List.generate(choices.length, (index) {
return Center(
child: ChoiceCard(choice: choices[index], item: choices[index]),
);
}
)
)
)
);
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: 'This is a Car', icon: Icons.directions_car),
const Choice(title: 'This is a Bicycle', icon: Icons.directions_bike),
const Choice(title: 'This is a Boat', icon: Icons.directions_boat),
const Choice(title: 'This is a Bus', icon: Icons.directions_bus),
const Choice(title: 'This is a Train', icon: Icons.directions_railway),
];
class ChoiceCard extends StatelessWidget {
const ChoiceCard(
{Key key, this.choice, this.onTap, #required this.item, this.selected: false}
) : super(key: key);
final Choice choice;
final VoidCallback onTap;
final Choice item;
final bool selected;
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return Card(
color: Colors.white,
child: Row(
children: <Widget>[
new Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.topLeft,
child: Icon(choice.icon, size:80.0, color: textStyle.color,)),
new Expanded(
child: new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
child:
Text(choice.title, style: null, textAlign: TextAlign.left, maxLines: 5,),
)
),
],
crossAxisAlignment: CrossAxisAlignment.start,
)
);
}
}
You can copy paste run full code below
Step 1: To allow Navigator.push work, you can move MaterialApp to upper level
Step 2: In onTap pass Navigator.push
ChoiceCard(
choice: choices[index],
item: choices[index],
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(choice: choices[index])),
);
},
),
Step 3: Wrap Card with InkWell and call onTap()
return InkWell(
onTap: () {
onTap();
},
child: Card(
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
class HomePage extends StatelessWidget {
final title = "ListView List";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: new ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: List.generate(choices.length, (index) {
return Center(
child: ChoiceCard(
choice: choices[index],
item: choices[index],
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(choice: choices[index])),
);
},
),
);
})));
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: 'This is a Car', icon: Icons.directions_car),
const Choice(title: 'This is a Bicycle', icon: Icons.directions_bike),
const Choice(title: 'This is a Boat', icon: Icons.directions_boat),
const Choice(title: 'This is a Bus', icon: Icons.directions_bus),
const Choice(title: 'This is a Train', icon: Icons.directions_railway),
];
class ChoiceCard extends StatelessWidget {
const ChoiceCard(
{Key key,
this.choice,
this.onTap,
#required this.item,
this.selected: false})
: super(key: key);
final Choice choice;
final VoidCallback onTap;
final Choice item;
final bool selected;
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return InkWell(
onTap: () {
onTap();
},
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
new Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.topLeft,
child: Icon(
choice.icon,
size: 80.0,
color: textStyle.color,
)),
new Expanded(
child: new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
child: Text(
choice.title,
style: null,
textAlign: TextAlign.left,
maxLines: 5,
),
)),
],
crossAxisAlignment: CrossAxisAlignment.start,
)),
);
}
}
class Detail extends StatelessWidget {
final Choice choice;
Detail({this.choice});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Column(
children: <Widget>[
Text("${choice.title}"),
Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
],
),
);
}
}
import 'package:easy_buss/screen/client.dart';
import 'package:easy_buss/screen/invoice.dart';
import 'package:easy_buss/screen/invoice_settings.dart';
import 'package:easy_buss/screen/payment_info.dart';
import 'package:easy_buss/widgets/payment_info_form.dart';
import 'package:flutter/material.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
List<IconData> _icon = [
Icons.accessible,
Icons.analytics,
Icons.question_answer_sharp,
Icons.message,
Icons.share,
Icons.star_half,
Icons.add_business,
Icons.privacy_tip,
];
List<String> _title = [
'Invoice Settings',
'Reports',
'Frequently Ask Questions',
'Write Us',
'Share With A Friends',
'Rate Us',
'Terms & Conditions',
'Privacy Policy',
];
List<Color> _colors = [
Colors.cyan,
Colors.yellow,
Colors.red,
Colors.purple,
Colors.orange,
Colors.grey,
Colors.pink[300],
Colors.green[200],
];
List _items = [
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
];
#override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: _title.length,
separatorBuilder: (BuildContext context, int index) => Container(
padding: EdgeInsets.only(
left: 10,
right: 10,
),
child: Divider(
thickness: 1,
),
),
itemBuilder: (BuildContext context, int index) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _items[index],
),
);
},
leading: Container(
padding: const EdgeInsets.all(5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: _colors[index],
),
child: Icon(
_icon[index],
color: Colors.white,
size: 20,
),
),
title: Text(
_title[index],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
trailing: Icon(
Icons.chevron_right,
size: 40,
),
),
);
}
}