Flutter : Adding item from one list view to another list view - flutter

I am trying to select one item from phone contacts list (List view widget)
class PhoneContacts extends StatefulWidget {
const PhoneContacts({Key? key}) : super(key: key);
#override
State<PhoneContacts> createState() => _PhoneContactsState();
}
class _PhoneContactsState extends State<PhoneContacts> {
List<Contact> _contacts = [];
late PermissionStatus _permissionStatus;
late Customer _customer;
#override
void initState(){
super.initState();
getAllContacts();
}
void getAllContacts() async {
_permissionStatus = await Permission.contacts.request();
if(_permissionStatus.isGranted) {
List<Contact> contacts = await ContactsService.getContacts(withThumbnails: false);
setState(() {
_contacts = contacts;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Phone Contacts"),
backgroundColor: Colors.indigo[600],
),
body: Container(
padding: const EdgeInsets.all(5),
child: ListView.builder(
itemCount: _contacts.length,
itemBuilder: (BuildContext context, int index) {
Contact contact = _contacts[index];
return contactItem(contact);
}
),
),
);
}
Widget contactItem(Contact contact){
return ListTile(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>Dashboard(contact)));
},
leading: const CircleAvatar(
backgroundColor: Colors.pinkAccent,
child: Icon(Icons.person_outline_outlined)),
title : Text(contact.displayName.toString()),
subtitle: Text(contact.phones!.first.value.toString()),
);
}
}
and insert and display it to dashboard list (another List view widget)
class Dashboard extends StatefulWidget {
final Contact? contact;
const Dashboard([this.contact]);
#override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final Color? themeColor = Colors.indigo[600];
late GlobalKey<RefreshIndicatorState> refreshKey;
late List<CardGenerator> existingCustomerContactList = getCustomerContactList();
#override
void initState(){
super.initState();
refreshKey=GlobalKey<RefreshIndicatorState>();
}
void addCustomerContact() {
existingCustomerContactList.add(
CardGenerator(
Text(widget.contact!.displayName.toString()),
const Icon(Icons.account_circle),
Text(widget.contact!.phones!.first.value.toString())));
}
List<CardGenerator> getCustomerContactList () {
existingCustomerContactList = [
CardGenerator(
const Text('Dave', style: TextStyle(fontSize: 24.0), textAlign: TextAlign.start,),
const Icon(Icons.account_circle, size: 100, color: Colors.white,),
const Text('Address 1')),
CardGenerator(
const Text('John', style: TextStyle(fontSize: 24.0)),
const Icon(Icons.account_circle, size: 100, color: Colors.white),
const Text('Address 2')),
CardGenerator(
const Text('Richard', style: TextStyle(fontSize: 24.0)),
const Icon(Icons.account_circle, size: 100, color: Colors.white),
const Text('Address 3')),
];
return existingCustomerContactList;
}
Future<void> refreshList() async {
await Future.delayed(const Duration(seconds: 1));
setState(() => {
addCustomerContact(),
getCustomerContactList()
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
title: const Text("Dashboard"),
backgroundColor: themeColor,
),
body: RefreshIndicator(
key: refreshKey,
onRefresh: () async {
await refreshList();
},
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: existingCustomerContactList.length,
key: UniqueKey(),
itemBuilder: (BuildContext context, int index) {
return OpenContainer(
closedColor: Colors.transparent,
closedElevation: 0.0,
openColor: Colors.transparent,
openElevation: 0.0,
transitionType: ContainerTransitionType.fadeThrough,
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return Card(
color: Colors.white,
child: GestureDetector(
onTap: openContainer,
child: SizedBox(
height: 140,
child: Row(
children: [
Container(
decoration: const BoxDecoration(
color: Colors.indigo,
borderRadius: BorderRadius.only(topLeft: Radius.circular(7.0),bottomLeft: Radius.circular(7.0))
),
height: 140,
width: 120,
child: existingCustomerContactList[index].icon,
),
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: existingCustomerContactList[index].title,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: existingCustomerContactList[index].address,
),
],
)
],
),
),
),
);
},
openBuilder: (BuildContext _, VoidCallback openContainer) {
return ConsumerHome();
}
);
}),
),
],
),
),
);
}
}
I found the
selected item has been added to the Dashboard items list but when I refresh it it doesn't newly added item in the dashboard list view.
I am a newcomer in flutter please bare with me. I already did my search for this problem unfortunately, no luck.

Change the order of execution. You are adding the item in the list and then making a new list again in the current order
addCustomerContact(),
getCustomerContactList()
change this to
getCustomerContactList()
addCustomerContact(),

Related

Deleting Item out of List, Listview.build shows wrong data

I have a Stateful widget that i pass a list to (for example 2 items).
After I delete an item, the widget should rebuild itself.
Unfortunately, the deleted item is still displayed and the other one is not.
When I re-enter the widget, the correct item is loaded.
There is a similar problem List not updating on deleting item
but maybe someone can explain me what i did wrong and why provider is helping me here instead of setState?
My code is:
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:trip_planner/util/dialog_box.dart';
import 'package:trip_planner/util/previewUrl.dart';
class BookingPage extends StatefulWidget {
final List toDoList;
BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//text controller
final _controller = TextEditingController();
final _database = FirebaseDatabase.instance.ref();
//Liste is an example what i have in my list
List toDoList2 = [
["https://www.booking.com/Share-Rnv2Kf", true],
["https://www.booking.com/Share-3hKQ0r", true],
];
void initState(){
super.initState();
}
void deleteTask(int index){
setState(() {
widget.toDoList.removeAt(index);
});
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
}
//save new Item
void saveNewItem(){
setState(() {
widget.toDoList.add([_controller.text, false]);
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
_controller.clear();
});
Navigator.of(context).pop();
}
void createNewItem(){
showDialog(
context: context,
builder: (context){
return DialogBox(
controller: _controller,
onSave: saveNewItem,
onCancel: () => Navigator.of(context).pop(),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Booking Seiten'),
elevation: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: createNewItem,
child: Icon(Icons.add),
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index){
return PreviewUrl(
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);
},
),
);
}
}
i thought setState does the same thing as when i re-enter the widget, but it doesn't.
import 'package:any_link_preview/any_link_preview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:url_launcher/url_launcher.dart';
class PreviewUrl extends StatelessWidget {
final String url2;
//Function(bool?)? onChanged;
Function(BuildContext)? deleteFunction;
PreviewUrl({
super.key,
required this.url2,
required this.deleteFunction,
//required this.onChanged,
});
Future openBrowserURL({
required String url,
bool inApp = false,
}) async {
if(await canLaunch(url)){
await launch(
url,
forceSafariVC: inApp, //iOS
forceWebView: inApp, //Android
enableJavaScript: true, //Android
);
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(1.0),
child: Slidable(
endActionPane: ActionPane(
motion: StretchMotion(),
children: [
SlidableAction(
onPressed: deleteFunction,
icon: Icons.delete,
backgroundColor: Colors.red.shade300,
borderRadius: BorderRadius.circular(12),
)
],
),
child: Container(
child: AnyLinkPreview.builder(
link: url2,
itemBuilder: (context, metadata, imageProvider) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (imageProvider != null)
GestureDetector(
onTap: () async {
final url = url2;
openBrowserURL(url: url, inApp: true);
},
child: Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.width *0.25,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
),
Container(
width: double.infinity,
color: Theme.of(context).primaryColor.withOpacity(0.6),
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (metadata.title != null)
Text(
metadata.title!,
maxLines: 1,
style:
const TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 5),
if (metadata.desc != null)
Text(
metadata.desc!,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
Text(
metadata.url ?? url2,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
],
),
),
),
),
);
}
}
If you run the simplified version of your code in DartPad - it will work:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
List toDoList = [
["Button 1", true],
["Button 2", true],
];
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: BookingPage(toDoList: toDoList),
),
),
);
}
}
class BookingPage extends StatefulWidget {
final List toDoList;
const BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//Liste is an example what i have in my list
List toDoList2 = [
["Button 1", true],
["Button 2", true],
];
#override
void initState() {
super.initState();
}
void deleteTask(int index) {
setState(() {
widget.toDoList.removeAt(index);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Booking Seiten'),
elevation: 0,
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.lightBlue,
padding: const EdgeInsets.all(12),
textStyle: const TextStyle(fontSize: 22),
),
child: Text(widget.toDoList[index][0]!),
onPressed: () => setState(() => deleteTask(index)),
);
},
),
);
}
}
Which tells me that the problem is your PreviewUrl. My guess is - it is a statful widget, and when the tree rebuilds - it will link the old State object to the first item.
Using Keys might help, something like:
return PreviewUrl(
key: ObjectKey(widget.toDoList[index]),
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

How to fix "Too many positional arguments: 1 expected, but 3 found." issue in flutter

I'm new to flutter.
I need to get product information through a form using flutter provider.
I can get one object(like String name value only). But when I add multiple parameters, it shows the following error.
Too many positional arguments: 1 expected, but 3 found.
This is the code I wrote.
Model class
class Item {
String itemName;
String description;
double itemPrice;
Item(this.itemName, this.description, this.itemPrice);
}
ChangeNotifier class
class ItemAddNotifier extends ChangeNotifier {
List<Item> itemList = [];
addItem(String itemName, String description, double itemPrice) {
Item item = Item(itemName, description, itemPrice);
itemList.add(item);
notifyListeners();
}
}
Add items
class AddItems extends StatelessWidget {
final TextEditingController _itemNameTextEditing = TextEditingController();
final TextEditingController _itemDescriptionTextEditing =
TextEditingController();
final TextEditingController _itemPriceTextEditing = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
TextField(
controller: _itemNameTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Name',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemDescriptionTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Description',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemPriceTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Price',
),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('ADD ITEM'),
onPressed: () async {
if (_itemNameTextEditing.text.isEmpty) {
return;
}
await Provider.of<ItemAddNotifier>(context, listen: false)
.addItem(
_itemNameTextEditing.text,
_itemDescriptionTextEditing.text,
_itemPriceTextEditing.text);
Navigator.pop(context);
},
),
],
),
),
);
}
}
Home Screen
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return AddItems();
},
),
);
},
icon: Icon(Icons.add))
],
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
Consumer<ItemAddNotifier>(builder: (context, itemAddNotifier, _) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: itemAddNotifier.itemList.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
itemAddNotifier.itemList[index].itemName,
style:
TextStyle(fontSize: 20.0, color: Colors.black),
),
],
),
);
});
})
],
),
),
);
}
}
Main
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) {
return ItemAddNotifier();
},
child: MaterialApp(
home: Container(
color: Colors.white,
child: HomeScreen(),
),
),
);
}
}
It shows the error in Item item = Item(itemName, description, itemPrice); line.
If someone can help me to fix this issue.
Thank you.

I cannot fix the buttons in the project

I'm developing an application with flutter. But I cannot fix the buttons in the project. On my chat page, the button goes up. I'm new to the Flutter language, can you help me?
Hello, I'm developing an application with flutter. But I cannot fix the buttons in the project. On my chat page, the button goes up. I'm new to the Flutter language, can you help me?
Screenshot:
My Button Code :
class HomePage extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<HomePage> {
final _scrollController = ScrollController();
List<TabItem> tabItems = List.of([
new TabItem(Icons.home, "Anasayfa", Colors.blue),
new TabItem(Icons.message, "Sohbet Odası", Colors.orange),
new TabItem(Icons.person, "Profil", Colors.red),
]);
int seciliPozisyon = 0;
CircularBottomNavigationController _navigationController;
#override
void initState() {
super.initState();
_navigationController =
new CircularBottomNavigationController(seciliPozisyon);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
centerTitle: true,
title: Text("Crypto App"),
),
body: Stack(
children: <Widget>[
Padding(
child: bodyContainer(),
padding: EdgeInsets.only(bottom: 60),
),
Align(alignment: Alignment.bottomCenter, child: bottomNav())
],
),
);
}
Widget bodyContainer() {
String activeUserId =
Provider.of<AuthorizationService>(context, listen: false).activeUserId;
Color selectedColor = tabItems[seciliPozisyon].color;
switch (seciliPozisyon) {
case 0:
return HomeScreen();
break;
case 1:
return FriendlyChatApp();
break;
case 2:
return Profile(
profileId: activeUserId,
);
break;
}
}
Widget bottomNav() {
return CircularBottomNavigation(
tabItems,
controller: _navigationController,
barHeight: 60,
barBackgroundColor: Colors.white,
animationDuration: Duration(milliseconds: 300),
selectedCallback: (int selectedPos) {
setState(() {
seciliPozisyon = selectedPos;
});
},
);
}
}
ChatApp Code :
void main() {
runApp(
FriendlyChatApp(),
);
}
final ThemeData kIOSTheme = ThemeData(
primarySwatch: Colors.blue,
primaryColor: Colors.grey[100],
primaryColorBrightness: Brightness.light,
);
final ThemeData kDefaultTheme = ThemeData(
primarySwatch: Colors.orange,
accentColor: Colors.orangeAccent,
);
String _name = '';
class FriendlyChatApp extends StatelessWidget {
const FriendlyChatApp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: ChatScreen(),
);
}
}
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.animationController});
final String text;
final AnimationController animationController;
#override
Widget build(BuildContext context) {
return SizeTransition(
sizeFactor:
CurvedAnimation(parent: animationController, curve: Curves.easeOut),
axisAlignment: 0.0,
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: Text(_name[0])),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_name, style: Theme.of(context).textTheme.headline4),
Container(
margin: EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
],
),
),
);
}
}
class ChatScreen extends StatefulWidget {
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
final List<ChatMessage> _messages = [];
final _textController = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool _isComposing = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: Theme.of(context).platform == TargetPlatform.iOS //new
? BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey[200]),
),
)
: null,
child: Column(
children: [
Flexible(
child: ListView.builder(
padding: EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
),
),
Divider(height: 1.0),
Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: _buildTextComposer(),
),
],
),
),
);
}
Widget _buildTextComposer() {
return IconTheme(
data: IconThemeData(color: Theme.of(context).accentColor),
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: [
Flexible(
child: TextField(
controller: _textController,
onChanged: (String text) {
setState(() {
_isComposing = text.isNotEmpty;
});
},
onSubmitted: _isComposing ? _handleSubmitted : null,
decoration: InputDecoration.collapsed(
hintText: 'Mesajınızı Buraya Yazınız:'),
focusNode: _focusNode,
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 4.0),
child: Theme.of(context).platform == TargetPlatform.iOS
? CupertinoButton(
onPressed: _isComposing
? () => _handleSubmitted(_textController.text)
: null,
child: Text('Gönder'),
)
: IconButton(
icon: const Icon(Icons.send),
onPressed: _isComposing
? () => _handleSubmitted(_textController.text)
: null,
))
],
),
),
);
}
void _handleSubmitted(String text) {
_textController.clear();
setState(() {
_isComposing = false;
});
var message = ChatMessage(
text: text,
animationController: AnimationController(
duration: const Duration(milliseconds: 700),
vsync: this,
),
);
setState(() {
_messages.insert(0, message);
});
_focusNode.requestFocus();
message.animationController.forward();
}
#override
void dispose() {
for (var message in _messages) {
message.animationController.dispose();
}
super.dispose();
}
}
You need to add :
resizeToAvoidBottomInset: false,
Here as shown:
Scaffold(
//here
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.black,
centerTitle: true,
title: Text("Crypto App"),
),
body: Stack(
children: <Widget>[
Padding(
child: bodyContainer(),
padding: EdgeInsets.only(bottom: 60),
),
Align(alignment: Alignment.bottomCenter, child: bottomNav())
],
),
);
}
Here using this whenever user will type something setting value to false will make keyboard overlap the bottom navigation bar.
Hope this is what you wanted to achieve.

Unable to open keyboard when checking MediaQuery of bottom insets in flutter

I'm trying to check if the keyboard is visible after tapping on the TextFormField by calling:
if (MediaQuery.of(context).viewInsets.bottom != 0) {
...
}
but as soon as I have this MediaQuery call in my code, the Keyboard doesn't even open anymore after tapping on the TextFormField...
Edited:
This is what happens when tapping on the TextFormField:
I added the code of the page which causes this faulty behavior:
class LearnPage extends StatefulWidget {
final int topicId;
final String topicName;
LearnPage(this.topicId, this.topicName);
#override
_LearnPageState createState() => _LearnPageState();
}
class _LearnPageState extends State<LearnPage> {
final mainCaardIndex = ValueNotifier<int>(0);
PageController _mainCaardController;
PageController _inputCaardController;
List<CaardM> caards;
List<PageM> mainCaardList = [];
List<List<PageM>> inputCaardList = [];
List<List<TextEditingController>> textControllers = [];
Future<void> async_init() async {
List<CaardM> caardList =
await DatabaseProviderCaard.db.getCaards(widget.topicId);
caards = caardList;
setState(() {});
}
bool _keyboardIsVisible() {
return !(MediaQuery.of(context).viewInsets.bottom == 0.0);
}
#override
void initState() {
async_init();
_mainCaardController = PageController();
_inputCaardController = PageController();
super.initState();
}
#override
void dispose() {
_mainCaardController.dispose();
_inputCaardController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
title: Center(
child: Text(
widget.topicName,
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
actions: [
!_keyboardIsVisible()
? IconButton(
icon: Icon(Icons.check_circle_outline),
tooltip: 'Validate',
onPressed: validate,
)
: IconButton(
icon: Icon(Icons.keyboard_hide),
onPressed: () {
FocusManager.instance.primaryFocus.unfocus();
},
),
],
),
body: Column(
children: [
Expanded(
flex: 3,
child: FutureBuilder(
future: getMainContent(),
builder: (context, AsyncSnapshot<int> snapshotMain) {
if (snapshotMain.connectionState == ConnectionState.done) {
return PageView.builder(
itemCount: snapshotMain.data,
controller: _mainCaardController,
onPageChanged: (position) {
mainCaardIndex.value = position;
mainCaardIndex.notifyListeners();
_inputCaardController.jumpToPage(0);
},
itemBuilder: (context, position) {
return LearnMainCaard(
mainCaardList[position].title,
mainCaardList[position].content,
);
},
);
} else {
return CircularProgressIndicator();
}
},
),
),
Expanded(
flex: 5,
child: FutureBuilder(
future: getInputContent(),
builder: (context, AsyncSnapshot<int> snapshotInput) {
if (snapshotInput.connectionState == ConnectionState.done) {
return ValueListenableBuilder(
valueListenable: mainCaardIndex,
builder: (context, value, _) {
return PageView.builder(
itemCount: snapshotInput.data,
controller: _inputCaardController,
itemBuilder: (context, position) {
return LearnInputCaard(
inputCaardList[mainCaardIndex.value][position].title,
textControllers[mainCaardIndex.value][position],
);
},
);
},
);
} else {
return CircularProgressIndicator();
}
},
),
),
],
),
);
}
Future<int> getMainContent() async {
List<PageM> caardPages;
mainCaardList.clear();
for (var i = 0; i < caards.length; i++) {
caardPages = await DatabaseProviderPage.db.getPages(caards[i].id);
if (caards[i].pageAmount > 1) {
mainCaardList.add(caardPages[0]);
}
}
return mainCaardList.length;
}
Future<int> getInputContent() async {
List<PageM> caardPages = [];
List<PageM> list = [];
inputCaardList.clear();
for (var i = 0; i < caards.length; i++) {
caardPages = await DatabaseProviderPage.db.getPages(caards[i].id);
if (caards[i].pageAmount > 1) {
addController(caards[i].pageAmount - 1);
list = [];
for (var i = 1; i < caardPages.length; i++) {
list.add(caardPages[i]);
}
inputCaardList.add(list);
}
}
return inputCaardList[mainCaardIndex.value].length;
}
void addController(int controllerAmount) {
List<TextEditingController> currentTextControllers = [];
print('addController called');
currentTextControllers.clear();
currentTextControllers = List.generate(
controllerAmount, (index) => TextEditingController()
);
textControllers.add(currentTextControllers);
}
And here the LearnInputCaard widget:
import 'package:flutter/material.dart';
class LearnInputCaard extends StatefulWidget {
final String title;
final TextEditingController textController;
LearnInputCaard(
this.title,
this.textController,
);
#override
_LearnInputCaardState createState() => _LearnInputCaardState();
}
class _LearnInputCaardState extends State<LearnInputCaard> {
#override
Widget build(BuildContext context) {
return Container(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
margin: EdgeInsets.all(20),
color: Colors.amberAccent.shade100,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Expanded(
flex: 1,
child: Text(
widget.title,
style: TextStyle(fontSize: 20),
),
),
Divider(color: Colors.black38,),
Expanded(
flex: 10,
child: Container(
padding: EdgeInsets.all(10.0),
child: TextFormField(
controller: widget.textController,
maxLines: 30,
decoration: InputDecoration(
hintText: "Enter content",
border: InputBorder.none,
),
),
),
)
],
),
),
),
);
}
}
you need to check MediaQuery.of(context).viewInsets.bottom == 0.0
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Keyboard Visibility Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_keyboardIsVisible()
? Text(
"Keyboard is visible",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
)
: RichText(
text: TextSpan(children: [
TextSpan(
text: "Keyboard is ",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
),
TextSpan(
text: "not ",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.red),
),
TextSpan(
text: "visible",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
)
]),
),
SizedBox(
height: 20,
),
Container(
width: 200.0,
child: TextField(
style: Theme.of(context).textTheme.display1,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
borderRadius: BorderRadius.circular(10.0),
),
),
),
)
],
),
));
}
bool _keyboardIsVisible() {
return !(MediaQuery.of(context).viewInsets.bottom == 0.0);
}
}
The problem is that you get the context from the parent widget.
If you call:
MediaQuery.of(context);
in the same widget where your forms are, you shouldn't get this behavior.
You need to define a GlobalKey<FormState> in your highest widget and pass this one down. Then it works. I defined it first in my SafeArea and therefore it failed and I had the same problem with the keyboard.
Here are some snippets of my code. I have a PageController and use two different forms on my two pages.
class OnboardingScaffold extends HookConsumerWidget {
OnboardingScaffold({Key? key}) : super(key: key);
// here you define your GlobalKeys
final _formKeyLogin = GlobalKey<FormState>();
final _formKeyApply = GlobalKey<FormState>();
#override
Widget build(BuildContext context, WidgetRef ref) {
final controller = usePageController();
bool isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
body: Container(
padding: !isKeyboard
? const EdgeInsets.only(bottom: 80)
: const EdgeInsets.only(bottom: 0),
child: PageView(
controller: controller,
children: [
// here you pass these keys into your child Widget
LoginSafeArea(
formKey: _formKeyLogin,
),
ApplySafeArea(
formKey: _formKeyApply,
),
],
),
),
bottomSheet: !isKeyboard
? Container(height: 80)
: Container(height: 0),
);
}
}
The child Widget should contain a Form Widget:
class LoginSafeArea extends HookConsumerWidget {
const LoginSafeArea({Key? key, required this.formKey}) : super(key: key);
final GlobalKey<FormState> formKey;
#override
Widget build(BuildContext context, WidgetRef ref) {
return SafeArea(
child: Center(
child: Form(
key: formKey,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
const EmailFieldWidget(),
const SizedBox(height: 8.0),
const PasswordFieldWidget(),
const SizedBox(height: 16.0),
LoginButtonWidget(
formKey: formKey,
),
const SizedBox(height: 8.0),
],
),
),
),
),
);
}
}