Flutter. GridView inside Container - flutter

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

Related

Background image is moving when keyboards appears 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(),
),

How to implement a horizontal scroll which is controlled by bottom minus bar in flutter

I have to implement a horizontal scroll list in flutter.I could do that and have included the code below(The code is still to be modified but the base of the code is good enough to put in the pictures and other such details)
But the problem is the minus bar below the horizontal scroll.I don't know what feature in flutter allows to do that.I search many things but other than radio boxes,check boxes, switches,etc I am not able to find any details of it.Please have a look at the screenshot of the app ,I have indicated the minus bar control in red.Home screen,the minus bar indicated in red
The code I have written:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black ,
body: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 500,
child: ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: <Widget>[
Container(
width:400 ,
color: Colors.red,
),
Container(
width: 400.0,
color: Colors.blue,
),
Container(
width: 400.0,
color: Colors.green,
),
],
),
)
);
}
}
What you want to look for is not ListView but PageView here is a small code sample to try in DartPad and see how you could make your layout.
Basically I am using a PageController to change the current page by taping on certain widgets.
Code
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
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: MyWidget()),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final _items = [Colors.red, Colors.blue, Colors.yellow];
final _pageController = PageController();
int _currentPageNotifier = 0;
final double _indicatorWidth = 30;
Widget _buildPageView() {
return PageView.builder(
controller: _pageController,
itemCount: _items.length,
itemBuilder: (context, index) => Center(
child: FlutterLogo(
colors: _items[index],
size: 50,
),
),
onPageChanged: (int index) =>
setState(() => _currentPageNotifier = index),
);
}
Widget _buildIndicator() {
List<Widget> itemWidgets = [];
for (int index = 0; index < _items.length; index++) {
itemWidgets.add(GestureDetector(
onTap: () => _pageController.animateToPage(
index,
duration: Duration(milliseconds: 300),
curve: Curves.ease,
),
child: Container(
decoration: BoxDecoration(
color: _currentPageNotifier == index
? Colors.green
: Colors.grey,
borderRadius: BorderRadius.circular(9),
),
margin: EdgeInsets.only(right: 10),
width: _indicatorWidth,
height: 8,
),
));
}
return Positioned(
bottom: MediaQuery.of(context).size.height / 2 - 50,
left: MediaQuery.of(context).size.width / 2 -
_items.length * _indicatorWidth +
_items.length * 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: itemWidgets,
),
);
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
_buildPageView(),
_buildIndicator(),
],
);
}
}

Card flip to hero/dialog in Flutter

Looking to achieve an animation going from a bunch of card-like widgets in a gridview to a simple dialog, using a hero-style transition. I've mocked something up in Unity to demonstrate the concept
I've played around a bit with a hero tranisition (trying various things like RotationTransition) and have also used a package called Flip Card (https://pub.dev/packages/flip_card), but I can't quite get the two concepts working together, wondering if someone had some ideas
It's quite fun actually, I've done it, try this code:
import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'package:after_layout/after_layout.dart';
class FlipCardHero extends StatefulWidget {
#override
_FlipCardHeroState createState() => _FlipCardHeroState();
}
class _FlipCardHeroState extends State<FlipCardHero> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 1.0,
),
itemCount: 12,
itemBuilder: (context, index) {
return GestureDetector(
child: Hero(
tag: 'flipcardHero$index',
child: Container(
color: Colors.yellow[50],
height: 150,
child: FlipCard(
flipOnTouch: false,
direction: FlipDirection.HORIZONTAL,
front: Container(
child: Text('Front'),
),
back: Container(
child: Text('Back'),
),
),
),
),
onTap: () {
Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
pageBuilder: (_, __, ___) =>
SingleFlipCard(id: 'flipcardHero$index'),
),
);
},
);
},
),
);
}
}
class SingleFlipCard extends StatefulWidget {
final id;
SingleFlipCard({#required this.id});
#override
SingleFlipCardState createState() => SingleFlipCardState();
}
class SingleFlipCardState extends State<SingleFlipCard>
with AfterLayoutMixin<SingleFlipCard> {
final GlobalKey<FlipCardState> cardKey = GlobalKey<FlipCardState>();
#override
void afterFirstLayout(BuildContext context) {
cardKey.currentState.toggleCard();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: GestureDetector(
child: Center(
child: Hero(
tag: widget.id,
child: Container(
color: Colors.yellow[50],
height: 150,
child: FlipCard(
key: cardKey,
flipOnTouch: false,
direction: FlipDirection.HORIZONTAL,
front: Container(
width: 200,
height: 400,
child: Text('Front'),
),
back: Container(
width: 200,
height: 400,
child: Text('Back'),
),
),
),
),
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}

Is it possible to have both 'expand' and 'contract' effects with the slivers in Flutter?

I have implemented a screen with the CustomScrollView, SliverAppBar and FlexibleSpaceBar like the following:
Now, I'm stuck trying to further expand the functionality by trying to replicate the following effect:
Expand image to fullscreen on scroll
Can something like this be done by using the slivers in Flutter?
Basically, I want the image in it's initial size when screen opens, but depending on scroll direction, it should animate -> contract/fade (keeping the list scrolling functionality) or expand to fullscreen (maybe to new route?).
Please help as I'm not sure in which direction I should go.
Here's the code for the above screen:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
static const double bottomNavigationBarHeight = 48;
#override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
home: SliverPage(),
);
}
class SliverPage extends StatefulWidget {
#override
_SliverPageState createState() => _SliverPageState();
}
class _SliverPageState extends State<SliverPage> {
double appBarHeight = 0.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
physics: AlwaysScrollableScrollPhysics(),
slivers: <Widget>[
SliverAppBar(
centerTitle: true,
expandedHeight: MediaQuery.of(context).size.height * 0.4,
pinned: true,
flexibleSpace: LayoutBuilder(builder: (context, boxConstraints) {
appBarHeight = boxConstraints.biggest.height;
return FlexibleSpaceBar(
centerTitle: true,
title: AnimatedOpacity(
duration: Duration(milliseconds: 200),
opacity: appBarHeight < 80 + MediaQuery.of(context).padding.top ? 1 : 0,
child: Padding(padding: EdgeInsets.only(bottom: 2), child: Text("TEXT"))),
background: Image.network(
'https://images.pexels.com/photos/443356/pexels-photo-443356.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
fit: BoxFit.cover,
),
);
}),
),
SliverList(delegate: SliverChildListDelegate(_buildList(40))),
],
),
);
}
List _buildList(int count) {
List<Widget> listItems = List();
for (int i = 0; i < count; i++) {
listItems.add(
new Padding(padding: new EdgeInsets.all(20.0), child: new Text('Item ${i.toString()}', style: new TextStyle(fontSize: 25.0))));
}
return listItems;
}
}
use CustomScrollView with SliverPersistentHeader
child: LayoutBuilder(
builder: (context, constraints) {
return CustomScrollView(
controller: ScrollController(initialScrollOffset: constraints.maxHeight * 0.6),
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: Delegate(constraints.maxHeight),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, i) => Container(height: 100, color: i.isOdd? Colors.green : Colors.green[700]),
childCount: 12,
),
),
],
);
},
),
the Delegate class used by SliverPersistentHeader looks like:
class Delegate extends SliverPersistentHeaderDelegate {
final double _maxExtent;
Delegate(this._maxExtent);
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
var t = shrinkOffset / maxExtent;
return Material(
elevation: 4,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset('images/bg.jpg', fit: BoxFit.cover,),
Opacity(
opacity: t,
child: Container(
color: Colors.deepPurple,
alignment: Alignment.bottomCenter,
child: Transform.scale(
scale: ui.lerpDouble(16, 1, t),
child: Text('scroll me down',
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white)),
),
),
),
],
),
);
}
#override double get maxExtent => _maxExtent;
#override double get minExtent => 64;
#override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

Hide top header until scroll to certain height

I'm new to flutter and I want to implement something like this: (klook app)
It's basically a button being shown when the user scrolls a bit.
I tried different things with a SliverAppBar and SliverStickyHeader, but I can't make it work like this. I also played with Opacity and Visibility but it moves my hole view and does not 'overlap' my banner/searchby widget.
My code so far:
class _ExplorePageState extends State<ExplorePage> {
ScrollController _scrollController;
bool lastStatus = true;
_scrollListener() {
if (isShrink != lastStatus) {
print("listen");
setState(() {
lastStatus = isShrink;
});
}
}
bool get isShrink {
return _scrollController.hasClients &&
_scrollController.offset > (400 - kToolbarHeight);
}
#override
void initState() {
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
super.initState();
}
#override
void dispose() {
_scrollController.removeListener(_scrollListener());
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverStickyHeader(
header: Visibility(
child: Container(
color: Colors.red,
height: isShrink ? 100 : 0,
child: Text('Header 1'),
),
visible: isShrink ? true : false,
maintainState: true,
maintainSize: true,
maintainAnimation: true,
),
sliver: SliverList(
delegate: SliverChildListDelegate(
[
BannerWidget(),
ButtonWidget(),
],
),
),
),
],
),
);
}
}
The BannerWidget and ButtomWidget are two Containers similar to the app shown above.
I hope you can help me or tell me maybe what this behaviour is called.
Thank you!
If you're ok with using CustomScrollView, you could use SliverPersistentHeader with your own delegate. It will allow you to access current header scroll state and make your own layout depending on how much space you have left.
const double _kSearchHeight = 50.0;
const double _kHeaderHeight = 250.0;
class _ExplorePageState extends State<ExplorePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
delegate: DelegateWithSearchBar(),
pinned: true,
),
SliverList(
delegate: SliverChildListDelegate(
[
for (int i = 0; i < 4; i++)
Container(
height: 200,
child: Text('test'),
color: Colors.black26
),
],
),
)
],
),
),
);
}
}
class DelegateWithSearchBar extends SliverPersistentHeaderDelegate {
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
final showSearchBar = shrinkOffset > _kHeaderHeight - _kSearchHeight;
return Stack(
children: <Widget>[
AnimatedOpacity(
opacity: !showSearchBar ? 1 : 0,
duration: Duration(milliseconds: 100),
child: LayoutBuilder(
builder: (context, constraints) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('xxx'),
fit: BoxFit.cover
)
),
height: constraints.maxHeight,
child: SafeArea(
child: Container(
padding: EdgeInsets.only(left: 20, bottom: 20),
alignment: Alignment.bottomLeft,
child: Text(
'Sample Text',
style: TextStyle(color: Colors.white, fontSize: 22)
),
),
),
);
}
),
),
AnimatedOpacity(
opacity: showSearchBar ? 1 : 0,
duration: Duration(milliseconds: 100),
child: Container(
height: _kSearchHeight,
color: Colors.white,
alignment: Alignment.center,
child: Text('search bar')
),
),
],
);
}
#override
bool shouldRebuild(SliverPersistentHeaderDelegate _) => true;
#override
double get maxExtent => _kHeaderHeight;
#override
double get minExtent => _kSearchHeight;
}