VerticalCardPager not taking full width - flutter

When using the VerticalCardPager on a page on its own, it works with no problems.
However, when using it beneath other widgets, the cards shrink in size. I have tried wrapping within a SingleChildScrollView to extend the page but this does not work with the Expanded/Flexible widget.
HomeScreen
import 'package:club2_app/widgets/vertical_card.dart';
import 'package:flutter/material.dart';
import '../widgets/news_card.dart';
import '../constants.dart';
import '../widgets/app_bar.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(),
body: SafeArea(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 10, top: 15),
child: Text(
"News",
style: TextStyle(
color: kPrimaryLightColor,
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
),
],
), // 'News'
NewsCard(),
Row(
children: [
Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
'Posts',
style: TextStyle(
color: kPrimaryLightColor,
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
),
],
), // 'Posts'
Expanded(
child: Container(
padding: EdgeInsets.all(5.0),
width: double.infinity,
child: VerticalCard(),
),
)
],
),
),
);
}
}
VerticalCardWidget
import 'package:flutter/material.dart';
import 'package:vertical_card_pager/vertical_card_pager.dart';
class VerticalCard extends StatefulWidget {
#override
_VerticalCardState createState() => _VerticalCardState();
}
final List<String> titles = [
"How to Manage Injuries",
"Is Football Getting Faster?",
"Improving Match Fitness",
"Expected Goals: The Over and Under Achievers",
];
final List<Widget> images = [
Hero(
tag: "News 1",
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Container(
width: double.infinity,
child: Image.asset(
"assets/images/Mbappe.jpeg",
fit: BoxFit.cover,
),
),
),
),
Hero(
tag: "News 2",
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Image.asset(
"assets/images/Mbappe.jpeg",
fit: BoxFit.cover,
),
),
),
Hero(
tag: "News 3",
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Image.asset(
"assets/images/Mbappe.jpeg",
fit: BoxFit.cover,
),
),
),
Hero(
tag: "News 4",
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Image.asset(
"assets/images/Mbappe.jpeg",
fit: BoxFit.cover,
),
),
),
];
class _VerticalCardState extends State<VerticalCard> {
#override
Widget build(BuildContext context) {
return VerticalCardPager(
titles: titles,
images: images,
onPageChanged: (page) {
// print(page);
},
);
}
}

I'm afraid it is a limitation of the VerticalCardPager.
The width and height of the cards inside a VerticalCardPager are defined based on the maxHeight of the Parent Widget:
double getWidth(maxHeight, i) {
double cardMaxWidth = maxHeight / 2;
return cardMaxWidth - 60 * (i - 2).abs();
}
double getHeight(maxHeight, i) {
double cardMaxHeight = maxHeight / 2;
if (i == 2) {
return cardMaxHeight;
} else if (i == 0 || i == 4) {
return cardMaxHeight - cardMaxHeight * (4 / 5) - 10;
} else
return cardMaxHeight - cardMaxHeight * (4 / 5);
}
}
For i == 2, the middle Card, the width and height are both equal to maxHeight / 2.
So, if you want the Cards to have a different aspect ratio and fill the width of the screen, you will have to modify the code of the VerticalCardPager.
However, if you want to keep the same aspect ratio and expand out of the screen. You can use a SingleChildScrollView as you mentioned. Here you go:
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Vertical Pager')),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
[...]
SizedBox(
height: MediaQuery.of(context).size.height,
child: Container(
padding: EdgeInsets.all(5.0),
width: double.infinity,
child: VerticalCard(),
),
)
],
),
),
),
);
}
}
However, the scrolling behavior might be a little bit chaotic, or even impossible on some devices.

try to wrap Your column into container and set its width to "double.infinity"

Related

Flutter right overflow by 220 pixel

I have this error Flutter right overflow by 220 Pixel and Right Overflow error is showing.
My code :
import 'package:flutter/material.dart';
class Category extends StatelessWidget {
const Category({super.key});
Widget CategoryCard(String imgUrl, String CategoryName) {
return GestureDetector(
onTap: () {},
child: Container(
margin: EdgeInsets.only(right: 16),
child: Stack(
children: [
ClipRRect(borderRadius: BorderRadius.circular(6),child: Image.network(imgUrl,width: 120,height: 60,fit: BoxFit.cover,)),
Container(alignment: Alignment.center,width: 120,height: 60,decoration: BoxDecoration(borderRadius: BorderRadius.circular(6),color: Color.fromARGB(135, 0, 0, 0),),
child: Text(CategoryName,style: TextStyle(color: Colors.white, fontSize: 15),),
)],),),);
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
Padding(padding: const EdgeInsets.all(10),child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [CategoryCard("img1", "Technology"),CategoryCard("img2", "Technology"),CategoryCard("img3", "Technology"),CategoryCard("img4", "Technology")],
),),],),);}
}
Screenshot of ui and error:
Wrap your Row with SingleChildScrollView
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
// CategoryCard()
I modify your code and solved it ;)
first import below lines:
import 'dart:ui';
import 'package:flutter/material.dart';
then using Category and AppScrollBehavior class :
class Category extends StatelessWidget {
const Category({super.key});
Widget CategoryCard(String imgUrl, String CategoryName) {
return GestureDetector(
onTap: () {},
child: Container(
margin: EdgeInsets.only(right: 16),
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: Image.network(
imgUrl,
width: 120,
height: 60,
fit: BoxFit.cover,
)),
Container(
alignment: Alignment.center,
width: 120,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color.fromARGB(135, 0, 0, 0),
),
// ignore: prefer_const_constructors
child: Text(
CategoryName,
style: TextStyle(color: Colors.white, fontSize: 15),
),
)
],
),
),
);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
ScrollConfiguration(
behavior: AppScrollBehavior(),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CategoryCard("https://avatars.githubusercontent.com/u/46590079?v=4", "Technology"),
CategoryCard("https://avatars.githubusercontent.com/u/46590079?v=4", "Technology"),
CategoryCard("https://avatars.githubusercontent.com/u/46590079?v=4", "Technology"),
CategoryCard("https://avatars.githubusercontent.com/u/46590079?v=4", "Technology")
],
),
),
),
),
],
);
}
}
// if using flutter web need below class for enable scrolling
class AppScrollBehavior extends MaterialScrollBehavior {
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}

Flutter set widget position exactly center of the screen

I want to put a container widget in the middle of the device screen. However, since I used the SizedBox() and SvgPicture.asset() widgets before that, the container does not come right in the middle of the device. How can I do this?
This is my code:
class CenterWidget extends StatefulWidget {
const CenterWidget({Key? key}) : super(key: key);
#override
_CenterWidgetState createState() => _CenterWidgetState();
}
class _CenterWidgetState extends State<CenterWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
const SizedBox(height: 56),
SvgPicture.asset(ImageConstants.instance.logoSvg,
width: (MediaQuery.of(context).size.width - 60) / 2),
Expanded(
child: Center(
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
),
),
],
),
),
),
);
}
}
Use a top center aligned stack, and put the widget you want to be centered within a Positioned.fill widget. You can put the spacer and logo in their own column to keep them arranged vertically:
class _CenterWidgetState extends State<CenterWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: Stack(
alignment: Alignment.topCenter,
children: [
Column(
children: [
const SizedBox(height: 56),
SvgPicture.asset(ImageConstants.instance.logoSvg,
width: (MediaQuery.of(context).size.width - 60) / 2),
],
),
Positioned.fill(
child: Center(
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
),
),
],
),
),
),
);
}
}

Achieving this layout in flutter

I am trying to achieve something like this in flutter. I have a horizontal scrollable which has these rounded containers. I want the width of these containers to shrink if the elements in the scrollable is more than 3 and it should expand as per the image if the elements are less than 2. What i want is exactly like this image, i have been reading about flexible widget but when i wrap it inside a scrollable row it gives layout specific issues. Any workaround to achieve this?
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SingleChildScrollView(
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
child: Row(
children: [
...List.generate(
9,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
height: 100,
width: 100,
),
),
)
],
)),
SizedBox(
height: 20,
),
Row(
children: [
...List.generate(
2,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 180,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(20))),
))
],
),
SizedBox(
height: 20,
),
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 350,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(20))),
),
],
)
],
),
),
);
}
The above build method produces the following result.(The values here are hardcoded and is just for demonstration). The list values are going to be dynamic and the desired result should be like the one in the video. How do i proceed with this?
https://streamable.com/w142je
import 'package:flutter/material.dart';
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: MyHomePage());
}
}
class MyHomePage extends StatefulWidget {
final String hintText = 'hing';
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
#override
Widget build(BuildContext context) {
var list1 = List.filled(2, '2');
var list2 = List.filled(4, '4');
var list3 = List.filled(1, '1');
return SafeArea(
child: Scaffold(
body: Column(
children: [
_getList(context, list1),
_getList(context, list2),
_getList(context, list3),
],
),
),
);
}
Widget _getList(BuildContext context, List<String> list) {
bool ownSize = list.length == 2;
if (ownSize) {
return SingleChildScrollView(
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
child: Row(
children: list.map((t) => rowItem(t, 250)).toList(),
),
);
} else {
return Row(
children: list
.map(
(t) => Expanded(child: rowItem(t)),
)
.toList(),
);
}
}
Widget rowItem(String text, [double? width]) {
return Container(
margin: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
height: 100,
width: width,
alignment: Alignment.center,
child: Text(text),
);
}
}

How do I put a ListView under a scaffold with padding?

I am quite new to flutter and I've been trying to set up a profile page for my app but it seems like I don't quite understand how these flutter widgets come together, I apologize if my question is quite dumb but I've been googling and failing at getting this to work. So basically I have a scaffold which holds a container thats supposed to display profile info (email, name, etc.), under it I'd like to place a listview, but flutter has been boggling my mind, I can't seem to understand how layouts work together, here is my code. When I try to do buildPage(), I get an error that the scaffold has infinite size, using buildBox() alone works. I'm not sure how to go about this. Any Help is appreciated
import 'package:flutter/material.dart';
class ProfileBox extends StatefulWidget {
final String userEmail;
const ProfileBox(this.userEmail);
#override
_ProfileBoxState createState() => _ProfileBoxState();
}
class _ProfileBoxState extends State<ProfileBox> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildBox(){
return Scaffold(
body: Align(
alignment: Alignment.topCenter,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2), border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))
),
height: constraints.maxHeight / 2.5,
width: MediaQuery.of(context).size.width - (MediaQuery.of(context).size.width * 5)/100,
child: Center(
child: Text(
widget.userEmail,
textAlign: TextAlign.center,
),
),
);
},
),
),
);
}
Widget _buildPage()
{
return Column(children: <Widget>[
_buildBox(),
_buildList(),
],);
}
Widget _buildList()
{
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}
I just modified your code with Scaffold put the top Widget before the SafeArea, Please check the below code of it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildPage() {
return SafeArea(
top: true,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2),
border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))),
height: MediaQuery.of(context).size.height / 2.5,
width: MediaQuery.of(context).size.width -
(MediaQuery.of(context).size.width * 5) / 100,
child: Center(
child: Text(
"YOUR_EMAIL",
textAlign: TextAlign.center,
),
),
),
Expanded(
child: _buildList(),
)
],
),
),
);
Column(
children: <Widget>[
// _buildBox(),
_buildList(),
],
);
}
Widget _buildList() {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}
And output of the program as follow
Scaffold Widget should be a top Widget that contains the Column widget and all children Widget. I think you can start learning how to layout Widget in Flutter in order to understand more the way how Widget works, and the good place can be: https://flutter.dev/docs/development/ui/layout#lay-out-a-widget
Coming back to your question, you can just fix a bit to make it work:
class _ProfileBoxState extends State<ProfileBox> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildBox() {
return Align(
alignment: Alignment.topCenter,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2),
border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))),
height: constraints.maxHeight / 2.5,
width: MediaQuery.of(context).size.width -
(MediaQuery.of(context).size.width * 5) / 100,
child: Center(
child: Text(
widget.userEmail,
textAlign: TextAlign.center,
),
),
);
},
),
);
}
Widget _buildPage() {
return Scaffold(
body: Column(
children: <Widget>[
_buildBox(),
_buildList(),
],
),
);
}
Widget _buildList() {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}

Create device height background element

I am very new to flutter so please be fair.
I would like to create the following.
Layout
Background which is always the entire screen-size (includes multiple stacked images)
Content (adapts to the the normal app ui behaviours -> ui element like keyboard)
I can't seem to figure out how to create this background element which should not resize when the keyboard is pulled out.
I have this and I hope someone could give me a hand.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var insetHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Stack(
children: <Widget>[
Stack(
children: <Widget>[
Positioned(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height + insetHeight,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
alignment: Alignment.bottomCenter,
),
)
),
),
],
),
SizedBox(
width: 370,
child: SingleChildScrollView(
physics: PageScrollPhysics(), // dont really need this
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text("Login to",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Opensans",
fontSize: 30,
letterSpacing: .6,
color: Colors.black45,
fontWeight: FontWeight.normal
)
),
),
Card(
child: Padding(padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0), child: LoginForm()),
)
],
),
)
)
],
),
);
}
}
I have tried to use the MediaQuery.of(context).viewInsets.bottom; but it's always returning 0.
I am not sure how to solve this.
The Scaffold rebuilds its body when keyboard is visible.
So move your background widget outside the Scaffold.
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SizedBox.expand(
child: Image.asset(
"assets/images/background.png",
fit: BoxFit.cover,
),
),
Scaffold(
backgroundColor: Colors.transparent, //Should be transparent
body: Center(
child: TextField(),
),
),
],
);
}
}
For background, Try following:
Create a variable Size _screensize in _MyHomePageState.
Override initState in _MyHomePageState and do following:
#override
void initState() {
super.initState();
_screenSize ??= MediaQuery.of(context).size;`
}
Use this _screenSize as width and height for Positioned as below:
Positioned(
width: _screenSize.width,
height: _screenSize.height,
),
Add other normal widgets as usual.
Summary for background:
step 1: creating a private reference for size to use.
step 2: updating the private size variable only when it is null, which is only when the widget state is initialized the first time.
step 3: using private size as height and width for the background.