Background image is moving when keyboards appears Flutter - flutter

i was searching a lot and reading a lot another threads and nothing work for my case, my background image is moving when keyboards appears. I tried my best, and I am getting frustrated already because I am wasting a lot of time, could someone help me with this?
the image goes up every time I open the textinput and the keyboard appears, I think my mistake is to position the elements in the code, or I am missing something but the truth is I can't figure out what my mistake is.
I want to add that this page" is a page of a PageView, I don't know if that will have something about causing the issue.
Cuz i switch between login and register pages with the buttons, they are a pageview.
import 'package:flutter/material.dart';
import 'package:plantsapp/screens/welcome_page.dart';
import 'package:plantsapp/services/authentication_service.dart';
import 'package:provider/provider.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
AuthenticationService authServ = new AuthenticationService();
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(children: [
_crearfondo2(),
_loginForm()
],),
//_loginForm(),
);
}
Widget _crearfondo2() {
return Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/backgroundlogin.jpg'),
fit: BoxFit.cover,
)));
}
/*Widget _crearFondo() {
return Positioned(
child: Image.asset(
'assets/images/backgroundlogin.jpg',
fit: BoxFit.fill,
),
height: MediaQuery.of(context).size.height,
top: 0.0,
right: 0.0,
left: 0.0,
);
}*/
Widget _loginForm() {
return SingleChildScrollView(
child: Container(
color: Colors.white,
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 130),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 60),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Login',
style: TextStyle(fontSize: 20),
),
_emailForm(),
_passwordForm(),
_button(),
_buttonRegister(),
],
),
),
);
}
Widget _emailForm() {
return TextField(
controller: emailController,
decoration: InputDecoration(hintText: ('Email')),
);
}
Widget _passwordForm() {
return TextField(
controller: passwordController,
decoration: InputDecoration(hintText: ('Password')),
);
}
Widget _button() {
return RaisedButton(
child: Text('Login'),
onPressed: () async {
//Provider.of<AuthenticationService>(context, listen: false).
dynamic result = await authServ.signIn(
email: emailController.text.trim(),
password: passwordController.text.trim());
if (result == null) print('error signing in');
},
);
}
_buttonRegister() {
final navegacionModel = Provider.of<NavegacionModel>(context);
int index = 1;
return RaisedButton(
child: Text('Registrarse'),
onPressed: () {
// Navigator.pushNamed(context, 'registerpage');
navegacionModel.paginaActual = index;
navegacionModel.pageController;
},
);
}
}
WelcomePage:
class WelcomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => new NavegacionModel(),
child: Scaffold(
body: _Paginas(),
),
);
}
}
class _Paginas extends StatelessWidget {
#override
Widget build(BuildContext context) {
final navegacionModel = Provider.of<NavegacionModel>(context);
return PageView(
controller: navegacionModel.pageController,
// physics: BouncingScrollPhysics(),
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
LoginPage(),
RegisterPage(),
],
);
}
}
class NavegacionModel with ChangeNotifier {
int _paginaActual = 0;
PageController _pageController = new PageController();
int get paginaActual => this._paginaActual;
set paginaActual(int valor) {
this._paginaActual = valor;
_pageController.animateToPage(valor, duration: Duration(milliseconds: 235), curve: Curves.easeOut);
notifyListeners();
}
PageController get pageController => this._pageController;
}

Fixed!!! i will share how i fix it for someone need this:
welcome_page.dart
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => new NavegacionModel(),
child: Scaffold(
resizeToAvoidBottomInset: false, // i had to add this here, when i add here the image didnt move anymore by the keyboard
body: _Paginas(),
),
);
}
}
login_page.dart
#override
Widget build(BuildContext context) {
return Stack( // i remove this unnecesary scaffold until i need childrens, for now, i just return the stack
children: [
_crearfondo2(),
Padding( //i add this Padding cuz the form didnt scroll with the "resizeToAvoidBottomInset: false" until i add this padding here.
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: _loginForm(),
),
],
);
}

Try Like This
Widget build(BuildContext context) {
return MaterialApp(
title: 'flutter background',
home: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/background.jpg"), fit: BoxFit.cover)),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text('My App'),
centerTitle: true,
),
),
),
);
}

Use
resizeToAvoidBottomInset: false,
in the welcome page Scaffold
child: Scaffold(
body: _Paginas(),
),

Related

Flutter. GridView inside Container

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'Login.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image:DecorationImage(
image: AssetImage("images/black_background_logo.png"),
fit: BoxFit.cover,
)
),
child: Column(
children: [
CarouselDemo(),
HomePanel()
],
),
);
}
}
List<String> images = [
'https://skalka-app.ru/banners/1.png',
'https://skalka-app.ru/banners/2.png',
'https://skalka-app.ru/banners/3.png',
] ;
class CarouselDemo extends StatelessWidget {
CarouselController buttonCarouselController = CarouselController();
#override
Widget build(BuildContext context) => CarouselSlider(
options: CarouselOptions(
height: MediaQuery.of(context).size.height*0.7,
viewportFraction: 1.0,
enableInfiniteScroll: true,
reverse: false,
autoPlay: true,
autoPlayInterval: Duration(seconds: 8),
autoPlayAnimationDuration: Duration(milliseconds: 800),
autoPlayCurve: Curves.fastOutSlowIn,
),
items: images.map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
//width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height*0.7,
decoration: BoxDecoration(
color: Colors.amber
),
child: Image.network(i,fit: BoxFit.cover, height: MediaQuery.of(context).size.height*0.7,)
);
},
);
}).toList(),
);
}
class HomePanel extends StatelessWidget {
#override
Widget build(BuildContext context) {
final double height = MediaQuery.of(context).size.height;
List<String> data = <String>["Twitter", "Reddit", "YouTube", "Facebook",
"Vimeo", "GitHub", "GitLab", "BitBucket", "LinkedIn", "Medium",
"Tumblr", "Instagram", "Pinterest"];
List<RaisedButton> myWidgets = data.map((item) {
return new RaisedButton(
child: new Text(item),
onPressed: () async {
}
);
}).toList();
GridView myGrid = GridView.count(
crossAxisCount: 3,
children: myWidgets
);
return Container(
height: height*0.3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
child: myGrid
);
}
}
I'm trying to add a GridView to a Container, but an indent appears at the top. Please tell me how to fix this?
I painted the Container red to show that there is a padding on top. I could not find a solution to this problem on the Internet. I'm new to Flutter, maybe I missed an important point in building this widget.
You can try wrap GridView with a MediaQuery.removePadding() then set removeTop property to True.
MediaQuery.removePadding(
context: context,
removeTop: true,
child: GridView(
.......
)
);
I have used your code pretty much, just for the Carousel, I have used the ListView.builder(). Rest is fine.
The catch is to use Expanded class inside your Column() to take the height automatically for the Carousel
Follow the code along, and see the result as well, no extra space in the UI in the GridView
class _MyHomePageState extends State<MyHomePage> {
List<String> images = [
'https://skalka-app.ru/banners/1.png',
'https://skalka-app.ru/banners/2.png',
'https://skalka-app.ru/banners/3.png',
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: double.infinity,
child: Column(
children: [
// Expanded used to take up the space
Expanded(
// ListView.builder, use your carousel here
child: ListView.builder(
shrinkWrap: true,
itemCount: images.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index){
// look at this as well, no height, only width
// given for the image
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(images[index])
)
)
);
}
)
),
HomePanel()
],
),
)
);
}
}
class HomePanel extends StatelessWidget {
#override
Widget build(BuildContext context) {
final double height = MediaQuery.of(context).size.height;
List<String> data = <String>["Twitter", "Reddit", "YouTube", "Facebook",
"Vimeo", "GitHub", "GitLab", "BitBucket", "LinkedIn", "Medium",
"Tumblr", "Instagram", "Pinterest"];
List<RaisedButton> myWidgets = data.map((item) {
return new RaisedButton(
child: new Text(item),
onPressed: () async {
}
);
}).toList();
GridView myGrid = GridView.count(
crossAxisCount: 3,
children: myWidgets
);
return Container(
height: height*0.3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
child: myGrid
);
}
}
Result
Look at the design closely in the result, no extra spacing or padding

Flutter: Long Press on picture to get zoomed preview like Instagram

so I am currently having a grid of pictures and I want to implement a feature from instagram: If you longPress on one of the pictures, you get a a larger version of that picture appearing in the middle of the screen. If you stop pressing, the image dissapears.
I don't really need the code for that, but I just can't think of which widgets I should use.
Is there maybe a package for something like this? If not then how can I do it with Flutter standard widgets? Maybe using a dialog that appears on the longPress ?
Here's the improved vewrsion that resembles the same exact UX as of Instagram with blurred background.
We can achieve this using a combination of Stateful Widget, Stack and BackdropFliter, here is the sample code -
import 'dart:ui';
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(
debugShowCheckedModeBanner: false,
title: 'Counter Demo',
theme: ThemeData.light(),
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
centerTitle: true,
title: Text("Demo App"),
),
body: Stacked(),
),
);
}
}
class Stacked extends StatefulWidget {
#override
_StackedState createState() => _StackedState();
}
class _StackedState extends State<Stacked> {
final List<String> images = [
"1.jpg",
"2.jpg",
"3.jpg",
"4.jpg",
"5.jpg",
"6.jpg",
"7.jpg",
"8.jpg",
"9.jpg",
"10.jpg",
];
bool _showPreview = false;
String _image = "assets/images/1.jpg";
#override
Widget build(BuildContext context) {
return SafeArea(
child: Stack(
children: [
GridView.builder(
itemCount: images.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onLongPress: () {
setState(() {
_showPreview = true;
_image = "assets/images/${images[index]}";
});
},
onLongPressEnd: (details) {
setState(() {
_showPreview = false;
});
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
clipBehavior: Clip.hardEdge,
child: Image.asset("assets/images/${images[index]}"),
),
),
);
},
),
if (_showPreview) ...[
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 5.0,
sigmaY: 5.0,
),
child: Container(
color: Colors.white.withOpacity(0.6),
),
),
Container(
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.asset(
_image,
height: 300,
width: 300,
),
),
),
),
],
],
));
}
}
This is just a baseline example and there are endless possibilities you can modify this to achieve behavior you want.
Another simple way is we can build this by using StatefulWidget and IndexedStack -
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(
debugShowCheckedModeBanner: false,
title: 'Counter Demo',
theme: ThemeData.light(),
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
centerTitle: true,
title: Text("Demo App"),
),
body: Body(),
),
);
}
}
class Body extends StatefulWidget {
#override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> {
final List<String> images = [
"1.jpg",
"2.jpg",
"3.jpg",
"4.jpg",
"5.jpg",
"6.jpg",
"7.jpg",
"8.jpg",
"9.jpg",
"10.jpg",
];
int _index = 0;
String _image = "assets/images/1.jpg";
#override
Widget build(BuildContext context) {
return SafeArea(
child: IndexedStack(
index: _index,
children: [
GridView.builder(
itemCount: images.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onLongPress: () {
setState(() {
_index = 1;
_image = "assets/images/${images[index]}";
});
},
onLongPressEnd: (details) {
setState(() {
_index = 0;
});
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
clipBehavior: Clip.hardEdge,
child: Image.asset("assets/images/${images[index]}"),
),
),
);
},
),
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
),
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 400,
maxWidth: 400,
),
child: Image.asset(
_image,
),
),
),
)
],
),
);
}
}
You can check output for above code here.
You could use Peek and Pop https://pub.dev/packages/peek_and_pop
Is an implementation for Flutter based on the iOS functionality of the same name.

Can't make bottom textfield stick on top of keyboard when it show up in chat app, Flutter

So I m developing a chat app which read and write data from firebase.
I have a streambuilder(that shows the messages)which is above a Container widget(which hold the input text field)
My problem is when I tap the input field and the keyboard pop ups, it cover the message textfield.
I have done many solutions from Stackoverflow and none of them seems to work in my case. The technique i have tried are
-resizeToAvoidBottomInset: true
-Expanded(when I try this the messages no longer show up)
-Flexible
I test the same code in my other project and it works. The text field stick on top of the keyboard. It just doesn't work in a particular project which use Bloc Pattern. There might have been some scaffold error or I don't know. Please help
import 'chat_design.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedInUser;
class ChatScreen extends StatefulWidget {
static const String id = 'chat_screen';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextController = TextEditingController();
final _auth = FirebaseAuth.instance;
String messageText;
#override
void initState() {
// TODO: implement initState
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
print(loggedInUser.email);
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
//Do something with the user input.
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextController.clear();
//Implement send functionality.
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').limit(100).snapshots(),
builder: (context, snapshot) {
//wait before data is loaded
if(snapshot.data == null) return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(strokeWidth: 7,),
),
],
);
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe :currentUser == messageSender,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding:
EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
children: messageBubbles,
),
);
},
);
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.sender, this.text,this.isMe});
final String sender;
final String text;
final bool isMe;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
sender,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: isMe ? BorderRadius.only(topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(15.0))
:BorderRadius.only(topRight: Radius.circular(30.0),
bottomLeft: Radius.circular(15.0),
bottomRight: Radius.circular(30.0)),
color: isMe ? Colors.lightBlueAccent: Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
child: Text(
'$text',
style: TextStyle(
color: isMe ? Colors.white : Colors.black,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
Take ListView or SingleChildScrollView under Body. And then use bottomNavigationBar in Scaffold.
Scaffold(
body: ListView(
children: [],
),
bottomNavigationBar: Container(
padding: MediaQuery.of(context).viewInsets,
color: Colors.grey[300],
child: Container(
padding: EdgeInsets.symmetric(vertical: 2),
margin: EdgeInsets.symmetric(horizontal: 5),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Type a message',
),
))
),
);
I think what you need is use a SingleChildScrollView, the content will scroll when the keyboard show up, will let you two examples:
// Flutter code sample for
// In this example, the children are spaced out equally, unless there's no more
// room, in which case they stack vertically and scroll.
//
// When using this technique, [Expanded] and [Flexible] are not useful, because
// in both cases the "available space" is infinite (since this is in a viewport).
// The next section describes a technique for providing a maximum height constraint.
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return WidgetsApp(
title: 'Flutter Code Sample',
builder: (BuildContext context, Widget navigator) {
return MyStatelessWidget();
},
color: const Color(0xffffffff),
);
}
}
/// 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 LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar(
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
// A fixed-height child.
color: const Color(0xff808000), // Yellow
height: 120.0,
),
Container(
// Another fixed-height child.
color: const Color(0xff008000), // Green
height: 120.0,
),
],
),
),
),
);
},
);
}
}
Another example for SingleChildScrollView
// Flutter code sample for
// In this example, the column becomes either as big as viewport, or as big as
// the contents, whichever is biggest.
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return WidgetsApp(
title: 'Flutter Code Sample',
builder: (BuildContext context, Widget navigator) {
return MyStatelessWidget();
},
color: const Color(0xffffffff),
);
}
}
/// 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 LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Container(
// A fixed-height child.
color: const Color(0xff808000), // Yellow
height: 120.0,
),
Expanded(
// A flexible child that will grow to fit the viewport but
// still be at least as big as necessary to fit its contents.
child: Container(
color: const Color(0xff800000), // Red
height: 120.0,
),
),
],
),
),
),
);
},
);
}
}
Try this: Go to your AndroidManifest.xml and remove:
android:windowSoftInputMode="adjustResize" under the application-activity tag.
Basically, just change this:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
to this:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
>
Worked for one of my apps.
This is the correct way to do this:
Widget _buildContent(BuildContext context) {
return Stack(
children: [
Column(
children: [
Expanded(
child: YOUR_SCROLLING_AREA_HERE,
),
YOUR_PINNED_WIDGET_HERE,
],
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Title'),
),
body: _buildContent(context),
);
}

Text and Image together in a Flutter Card

I want to add an image and a text together in a card but I'm not able to do it. I think a row would be used here but not able to implement it. I'm new to flutter and app development so having some troubles. Any help is really appreciated. Also the cards are in GridView(not in ListView).
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'lists.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Just Another App',
home: Home(),
routes: {
"/webview": (_) => WebviewScaffold(
withJavascript: true,
withLocalStorage: true,
url: 'https://www.google.com/',
appBar: AppBar(
title: Text('Browser'),
),
),
},
theme: ThemeData(primaryColor: Colors.black),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final webView = FlutterWebviewPlugin();
#override
void initState() {
super.initState();
webView.close();
}
#override
Widget build(BuildContext context) {
var gridView = GridView.builder(
itemCount: 15,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Card(
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(35),
child: Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
),
),
onTap: () {
setState(() {
Navigator.of(context).pushNamed('/webview');
});
},
);
});
return Scaffold(
appBar: AppBar(
title: Text('Just Another App'),
),
body: Container(
child: gridView,
padding: EdgeInsets.all(12),
),
);
}
[GridViewApp Screenshot][1]}
This is a variable which I'm using in the "body" of Scaffold.
If you want to place an Image and a text side by side, add a Row widget:
child: Row(
children: <Widget>[
DecorationImage(...),
Text(...),
],
)
You can also set mainAxisAlignment and crossAxisAlignment to make sure that your widgets are placed correctly
just wrap your Container into a Row Widget and add a text to it.
Row(
children: <Widget>[
Text("add text here"),
Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
],
),

How to work with progress indicator in flutter?

I'm newbie in flutter and wanted to know what is better way to add CircularProgressIndicator in my layout. For example, my login view. This view have username, password and login Button. I did want create a overlay layout (with Opacity) that, when loading, show progress indicator like I use in NativeScript, but I'm little confused with how to do and too if it is the better way. On NativeScript, for example, I add IndicatorActivity in main layout and set busy to true or false, so it overlay all view components when is loading.
Edit:
I was able to reach this result:
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _loading = false;
void _onLoading() {
setState(() {
_loading = true;
new Future.delayed(new Duration(seconds: 3), _login);
});
}
Future _login() async{
setState((){
_loading = false;
});
}
#override
Widget build(BuildContext context) {
var body = new Column(
children: <Widget>[
new Container(
height: 40.0,
padding: const EdgeInsets.all(10.0),
margin: const EdgeInsets.fromLTRB(15.0, 150.0, 15.0, 0.0),
decoration: new BoxDecoration(
color: Colors.white,
),
child: new TextField(
decoration: new InputDecoration.collapsed(hintText: "username"),
),
),
new Container(
height: 40.0,
padding: const EdgeInsets.all(10.0),
margin: const EdgeInsets.all(15.0),
decoration: new BoxDecoration(
color: Colors.white,
),
child: new TextField(
decoration: new InputDecoration.collapsed(hintText: "password"),
),
),
],
);
var bodyProgress = new Container(
child: new Stack(
children: <Widget>[
body,
new Container(
alignment: AlignmentDirectional.center,
decoration: new BoxDecoration(
color: Colors.white70,
),
child: new Container(
decoration: new BoxDecoration(
color: Colors.blue[200],
borderRadius: new BorderRadius.circular(10.0)
),
width: 300.0,
height: 200.0,
alignment: AlignmentDirectional.center,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Center(
child: new SizedBox(
height: 50.0,
width: 50.0,
child: new CircularProgressIndicator(
value: null,
strokeWidth: 7.0,
),
),
),
new Container(
margin: const EdgeInsets.only(top: 25.0),
child: new Center(
child: new Text(
"loading.. wait...",
style: new TextStyle(
color: Colors.white
),
),
),
),
],
),
),
),
],
),
);
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(
decoration: new BoxDecoration(
color: Colors.blue[200]
),
child: _loading ? bodyProgress : body
),
floatingActionButton: new FloatingActionButton(
onPressed: _onLoading,
tooltip: 'Loading',
child: new Icon(Icons.check),
),
);
}
}
I'm still adapting to the idea of ​​states. This code is within the expected when working with flutter?
In flutter, there are a few ways to deal with Asynchronous actions.
A lazy way to do it can be using a modal. Which will block the user input, thus preventing any unwanted actions.
This would require very little change to your code. Just modifying your _onLoading to something like this :
void _onLoading() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: new Row(
mainAxisSize: MainAxisSize.min,
children: [
new CircularProgressIndicator(),
new Text("Loading"),
],
),
);
},
);
new Future.delayed(new Duration(seconds: 3), () {
Navigator.pop(context); //pop dialog
_login();
});
}
The most ideal way to do it is using FutureBuilder and a stateful widget. Which is what you started.
The trick is that, instead of having a boolean loading = false in your state, you can directly use a Future<MyUser> user
And then pass it as argument to FutureBuilder, which will give you some info such as "hasData" or the instance of MyUser when completed.
This would lead to something like this :
#immutable
class MyUser {
final String name;
MyUser(this.name);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<MyUser> user;
void _logIn() {
setState(() {
user = new Future.delayed(const Duration(seconds: 3), () {
return new MyUser("Toto");
});
});
}
Widget _buildForm(AsyncSnapshot<MyUser> snapshot) {
var floatBtn = new RaisedButton(
onPressed:
snapshot.connectionState == ConnectionState.none ? _logIn : null,
child: new Icon(Icons.save),
);
var action =
snapshot.connectionState != ConnectionState.none && !snapshot.hasData
? new Stack(
alignment: FractionalOffset.center,
children: <Widget>[
floatBtn,
new CircularProgressIndicator(
backgroundColor: Colors.red,
),
],
)
: floatBtn;
return new ListView(
padding: const EdgeInsets.all(15.0),
children: <Widget>[
new ListTile(
title: new TextField(),
),
new ListTile(
title: new TextField(obscureText: true),
),
new Center(child: action)
],
);
}
#override
Widget build(BuildContext context) {
return new FutureBuilder(
future: user,
builder: (context, AsyncSnapshot<MyUser> snapshot) {
if (snapshot.hasData) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Hello ${snapshot.data.name}"),
),
);
} else {
return new Scaffold(
appBar: new AppBar(
title: new Text("Connection"),
),
body: _buildForm(snapshot),
);
}
},
);
}
}
For me, one neat way to do this is to show a SnackBar at the bottom while the Signing-In process is taken place, this is a an example of what I mean:
Here is how to setup the SnackBar.
Define a global key for your Scaffold
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Add it to your Scaffold key attribute
return new Scaffold(
key: _scaffoldKey,
.......
My SignIn button onPressed callback:
onPressed: () {
_scaffoldKey.currentState.showSnackBar(
new SnackBar(duration: new Duration(seconds: 4), content:
new Row(
children: <Widget>[
new CircularProgressIndicator(),
new Text(" Signing-In...")
],
),
));
_handleSignIn()
.whenComplete(() =>
Navigator.of(context).pushNamed("/Home")
);
}
It really depends on how you want to build your layout, and I am not sure what you have in mind.
Edit
You probably want it this way, I have used a Stack to achieve this result and just show or hide my indicator based on onPressed
class TestSignInView extends StatefulWidget {
#override
_TestSignInViewState createState() => new _TestSignInViewState();
}
class _TestSignInViewState extends State<TestSignInView> {
bool _load = false;
#override
Widget build(BuildContext context) {
Widget loadingIndicator =_load? new Container(
color: Colors.grey[300],
width: 70.0,
height: 70.0,
child: new Padding(padding: const EdgeInsets.all(5.0),child: new Center(child: new CircularProgressIndicator())),
):new Container();
return new Scaffold(
backgroundColor: Colors.white,
body: new Stack(children: <Widget>[new Padding(
padding: const EdgeInsets.symmetric(vertical: 50.0, horizontal: 20.0),
child: new ListView(
children: <Widget>[
new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center
,children: <Widget>[
new TextField(),
new TextField(),
new FlatButton(color:Colors.blue,child: new Text('Sign In'),
onPressed: () {
setState((){
_load=true;
});
//Navigator.of(context).push(new MaterialPageRoute(builder: (_)=>new HomeTest()));
}
),
],),],
),),
new Align(child: loadingIndicator,alignment: FractionalOffset.center,),
],));
}
}
Create a bool isLoading and set it to false. With the help of ternary operator, When user clicks on login button set state of isLoading to true. You will get circular loading indicator in place of login button
isLoading ? new PrimaryButton(
key: new Key('login'),
text: 'Login',
height: 44.0,
onPressed: setState((){isLoading = true;}))
: Center(
child: CircularProgressIndicator(),
),
You can see Screenshots how it looks while before login is clicked
After login is clicked
In mean time you can run login process and login user. If user credentials are wrong then again you will setState of isLoading to false, such that loading indicator will become invisible and login button visible to user.
By the way, primaryButton used in code is my custom button. You can do same with OnPressed in button.
Step 1: Create Dialog
showAlertDialog(BuildContext context){
AlertDialog alert=AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(margin: EdgeInsets.only(left: 5),child:Text("Loading" )),
],),
);
showDialog(barrierDismissible: false,
context:context,
builder:(BuildContext context){
return alert;
},
);
}
Step 2: Call it
showAlertDialog(context);
await firebaseAuth.signInWithEmailAndPassword(email: email, password: password);
Navigator.pop(context);
Example Dialog and login form
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class DynamicLayout extends StatefulWidget{
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return new MyWidget();
}
}
showAlertDialog(BuildContext context){
AlertDialog alert=AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(margin: EdgeInsets.only(left: 5),child:Text("Loading" )),
],),
);
showDialog(barrierDismissible: false,
context:context,
builder:(BuildContext context){
return alert;
},
);
}
class MyWidget extends State<DynamicLayout>{
Color color = Colors.indigoAccent;
String title='app';
GlobalKey<FormState> globalKey=GlobalKey<FormState>();
String email,password;
login() async{
var currentState= globalKey.currentState;
if(currentState.validate()){
currentState.save();
FirebaseAuth firebaseAuth=FirebaseAuth.instance;
try {
showAlertDialog(context);
AuthResult authResult=await firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user=authResult.user;
Navigator.pop(context);
}catch(e){
print(e);
}
}else{
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar:AppBar(
title: Text("$title"),
) ,
body: Container(child: Form(
key: globalKey,
child: Container(
padding: EdgeInsets.all(10),
child: Column(children: <Widget>[
TextFormField(decoration: InputDecoration(icon: Icon(Icons.email),labelText: 'Email'),
// ignore: missing_return
validator:(val){
if(val.isEmpty)
return 'Please Enter Your Email';
},
onSaved:(val){
email=val;
},
),
TextFormField(decoration: InputDecoration(icon: Icon(Icons.lock),labelText: 'Password'),
obscureText: true,
// ignore: missing_return
validator:(val){
if(val.isEmpty)
return 'Please Enter Your Password';
},
onSaved:(val){
password=val;
},
),
RaisedButton(color: Colors.lightBlue,textColor: Colors.white,child: Text('Login'),
onPressed:login),
],)
,),)
),
);
}
}
Example from Ui
1. Without plugin
class IndiSampleState extends State<ProgHudPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Demo'),
),
body: Center(
child: RaisedButton(
color: Colors.blueAccent,
child: Text('Login'),
onPressed: () async {
showDialog(
context: context,
builder: (BuildContext context) {
return Center(child: CircularProgressIndicator(),);
});
await loginAction();
Navigator.pop(context);
},
),
));
}
Future<bool> loginAction() async {
//replace the below line of code with your login request
await new Future.delayed(const Duration(seconds: 2));
return true;
}
}
2. With plugin
check this plugin progress_hud
add the dependency in the pubspec.yaml file
dev_dependencies:
progress_hud:
import the package
import 'package:progress_hud/progress_hud.dart';
Sample code is given below to show and hide the indicator
class ProgHudPage extends StatefulWidget {
#override
_ProgHudPageState createState() => _ProgHudPageState();
}
class _ProgHudPageState extends State<ProgHudPage> {
ProgressHUD _progressHUD;
#override
void initState() {
_progressHUD = new ProgressHUD(
backgroundColor: Colors.black12,
color: Colors.white,
containerColor: Colors.blue,
borderRadius: 5.0,
loading: false,
text: 'Loading...',
);
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('ProgressHUD Demo'),
),
body: new Stack(
children: <Widget>[
_progressHUD,
new Positioned(
child: RaisedButton(
color: Colors.blueAccent,
child: Text('Login'),
onPressed: () async{
_progressHUD.state.show();
await loginAction();
_progressHUD.state.dismiss();
},
),
bottom: 30.0,
right: 10.0)
],
));
}
Future<bool> loginAction()async{
//replace the below line of code with your login request
await new Future.delayed(const Duration(seconds: 2));
return true;
}
}
I took the following approach, which uses a simple modal progress indicator widget that wraps whatever you want to make modal during an async call.
The example in the package also addresses how to handle form validation while making async calls to validate the form (see flutter/issues/9688 for details of this problem). For example, without leaving the form, this async form validation method can be used to validate a new user name against existing names in a database while signing up.
https://pub.dartlang.org/packages/modal_progress_hud
Here is the demo of the example provided with the package (with source code):
Example could be adapted to other modal progress indicator behaviour (like different animations, additional text in modal, etc..).
This is my solution with stack
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
final themeColor = new Color(0xfff5a623);
final primaryColor = new Color(0xff203152);
final greyColor = new Color(0xffaeaeae);
final greyColor2 = new Color(0xffE8E8E8);
class LoadindScreen extends StatefulWidget {
LoadindScreen({Key key, this.title}) : super(key: key);
final String title;
#override
LoginScreenState createState() => new LoginScreenState();
}
class LoginScreenState extends State<LoadindScreen> {
SharedPreferences prefs;
bool isLoading = false;
Future<Null> handleSignIn() async {
setState(() {
isLoading = true;
});
prefs = await SharedPreferences.getInstance();
var isLoadingFuture = Future.delayed(const Duration(seconds: 3), () {
return false;
});
isLoadingFuture.then((response) {
setState(() {
isLoading = response;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: Stack(
children: <Widget>[
Center(
child: FlatButton(
onPressed: handleSignIn,
child: Text(
'SIGN IN WITH GOOGLE',
style: TextStyle(fontSize: 16.0),
),
color: Color(0xffdd4b39),
highlightColor: Color(0xffff7f7f),
splashColor: Colors.transparent,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(30.0, 15.0, 30.0, 15.0)),
),
// Loading
Positioned(
child: isLoading
? Container(
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(themeColor),
),
),
color: Colors.white.withOpacity(0.8),
)
: Container(),
),
],
));
}
}
You can do it for center transparent progress indicator
Future<Null> _submitDialog(BuildContext context) async {
return await showDialog<Null>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return SimpleDialog(
elevation: 0.0,
backgroundColor: Colors.transparent,
children: <Widget>[
Center(
child: CircularProgressIndicator(),
)
],
);
});
}
{
isloading? progressIos:Container()
progressIos(int i) {
return Container(
color: i == 1
? AppColors.liteBlack
: i == 2 ? AppColors.darkBlack : i == 3 ? AppColors.pinkBtn : '',
child: Center(child: CupertinoActivityIndicator()));
}
}
You can use FutureBuilder widget instead. This takes an argument which must be a Future. Then you can use a snapshot which is the state at the time being of the async call when loging in, once it ends the state of the async function return will be updated and the future builder will rebuild itself so you can then ask for the new state.
FutureBuilder(
future: myFutureFunction(),
builder: (context, AsyncSnapshot<List<item>> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else {
//Send the user to the next page.
},
);
Here you have an example on how to build a Future
Future<void> myFutureFunction() async{
await callToApi();}
Centered on screen:
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [CircularProgressIndicator()])
])
class Loader extends StatefulWidget {
#override
State createState() => LoaderState();
}
class LoaderState extends State<Loader> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
#override
void initState() {
super.initState();
controller = AnimationController(
duration: Duration(milliseconds: 1200), vsync: this);
animation = CurvedAnimation(parent: controller, curve: Curves.elasticOut);
animation.addListener(() {
this.setState(() {});
});
animation.addStatusListener((AnimationStatus status) {});
controller.repeat();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
color: Colors.blue,
height: 3.0,
width: animation.value * 100.0,
),
Padding(
padding: EdgeInsets.only(bottom: 5.0),
),
Container(
color: Colors.blue[300],
height: 3.0,
width: animation.value * 75.0,
),
Padding(
padding: EdgeInsets.only(bottom: 5.0),
),
Container(
color: Colors.blue,
height: 3.0,
width: animation.value * 50.0,
)
],
);
}
}
Expanded(
child: Padding(
padding:
EdgeInsets.only(left: 20.0, right: 5.0, top:20.0),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FirstScreen()));
},
child: Container(
alignment: Alignment.center,
height: 45.0,
decoration: BoxDecoration(
color: Color(0xFF1976D2),
borderRadius: BorderRadius.circular(9.0)),
child: Text('Login',
style: TextStyle(
fontSize: 20.0, color: Colors.white))),
),
),
),
For your case, maybe it can be done by using showing a modal with a circle indicator. But I recommend using a simple plugin https://pub.dev/packages/flutter_easyloading.
The installation supper easy. Just run this flutter pub add flutter_easyloading in your terminal
Put this in you main.dart app
import 'package:flutter/material.dart';
import 'package:kunjungi_dokter/pages/welcome.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; // <- add this
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const Welcome(),
builder: EasyLoading.init(), // <- add this
);
}
}
To show the modal or the loading widget, in my case I show it in mya _login function in Login Screen:
import 'package:flutter_easyloading/flutter_easyloading.dart';
// ... other code
_login() async {
EasyLoading.show(status: 'loading...', maskType: EasyLoadingMaskType.black); // code to show modal with masking
var data = await LoginAPI.connectToAPI(
emailController.text, passwordController.text);
if (data.isError) {
EasyLoading.showError('Login Error: ' + data.message); // code to show modal without masking and auto close
} else {
await storage.write(key: 'token', value: data.token);
await storage.write(key: 'email', value: emailController.text);
EasyLoading.showSuccess('Login Success!'); // code to show modal without masking and auto close
Navigator.of(context)
.push(MaterialPageRoute(builder: ((context) => const Home())));
}
}
// ... other code
Tips, you can use this to close the modal:
EasyLoading.dismiss();
You will need a library for it
void onLoading() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return GFLoader(
type: GFLoaderType.android,
);
},
);
}
and then use this function where you need in code
onLoading;