is there a way to embed a SingleChildScrollView (Vertical) within another SingleChildScrollView(Horizontal) in Flutter - flutter

In my app there is a SingleChildScrollView(with scrollable direction as Horizontal) which has a N number of containers.
Is there a way to embed a the SingleChildScrollView(with scrollable direction as Horizontal) into a SingleChildScrollView (with scrollable direction as Vertical) in Flutter.
for example:
class HomeBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Padding(
padding: sidePadding,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HomeAppbar(),
addVerticalSpace(15),
Text(
'Welcome, Jack',
style: themeData.textTheme.headline1,
),
addVerticalSpace(15),
SearchField(
width: mediasize.width - 2 * screenHorizontalPadding,
height: mediasize.height,
),
addVerticalSpace(25),
//I want to add a SingleChildScrollView (Vertical Direction) from this point to
TitleMoreBar(barTitle: 'Trending'),
addVerticalSpace(15),
//the FullProductCardHorizontalList() has a SingleChildScrollView(Horizontal direction)
FullProductCardHorizontalList(),
addVerticalSpace(25),
TitleMoreBar(barTitle: 'Popular Brands'),
addVerticalSpace(25),
//the BrandCardList() has a SingleChildScrollView(Horizontal direction)
BrandCardList(),
// this where the SingleChildScrollView (Vertical) should end
],
),
),
),
);
}

Yes, you can do this like:
import 'package:flutter/material.dart';
class ScrollTraining extends StatefulWidget {
#override
_ScrollingTraining createState() => _ScrollingTraining();
}
class _ScrollingTraining extends State<ScrollTraining> {
double mWidth;
#override
Widget build(BuildContext context) {
mWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: mWidth,
height: 400,
color: Colors.indigo,
margin: EdgeInsets.symmetric(vertical: 8.0),
alignment: Alignment.center,
child: Text("Fixed Box"),
),
Container(
width: mWidth,
height: 200,
margin: EdgeInsets.symmetric(vertical: 8.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: getChildren(),
),
),
),
Container(
width: mWidth,
height: 400,
color: Colors.brown,
margin: EdgeInsets.symmetric(vertical: 8.0),
alignment: Alignment.center,
child: Text("Fixed Box"),
),
Container(
width: mWidth,
height: 200,
margin: EdgeInsets.symmetric(vertical: 8.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: getChildren(),
),
),
),
],
),
),
);
}
List<Widget> getChildren() {
List<Widget> output = List();
List<Color> colorList = [
Colors.redAccent,
Colors.deepOrange,
Colors.orangeAccent,
Colors.yellow,
Colors.lightGreenAccent,
Colors.green,
Colors.greenAccent,
Colors.blue,
Colors.purpleAccent,
Colors.pink,
];
for (int i = 0; i < 10; i++) {
output.add(Container(
width: 140,
height: 200,
color: colorList[i],
));
}
return output;
}
}
I hope it is useful for you.

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,
),
),
),
],
),
),
),
);
}
}

Flutter ListView not scrolling (I feel like I've tried every solution on the internet)

If I drag and hold my finger down I can see a few items that are below the cutoff of the screen but as soon as I let go, it just bounces back to the top. I tried using SingleChildScrollView places, tried setting primary = true, and a bunch of other stuff that didn't help. I'm fairly new to flutter so any help would be appreciated!! Let me know if any more info is needed.
Here is my code:
import 'package:flutter/material.dart';
import 'package:drink_specials/models/restaurant.dart';
import 'package:drink_specials/screens/home/restaurant_list.dart';
class RestaurantNameTextStyle {
static TextStyle display5(BuildContext context) {
return Theme.of(context).textTheme.headline2.copyWith(color: Colors.white);
}
}
class RestaurantTypeTextStyle {
static TextStyle display5(BuildContext context) {
return Theme.of(context).textTheme.headline6.copyWith(color: Colors.white);
}
}
class RestaurantDetail extends StatelessWidget {
final Restaurant restaurant;
RestaurantDetail({Key key, #required this.restaurant}) : super(key: key);
#override
Widget build(BuildContext context) {
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 100.0),
Text(
restaurant.name,
style: RestaurantNameTextStyle.display5(context),
),
SizedBox(height: 10.0),
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
restaurant.restaurant_type,
style: RestaurantTypeTextStyle.display5(context),
))),
],
);
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: NetworkImage(restaurant.photo),
fit: BoxFit.cover,
),
)),
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Center(
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
itemCount: restaurant.specials.length,
itemBuilder: (context, index) {
final item = restaurant.specials[index];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, 1.0)),
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal:20, vertical:10),
title: Text(item, style: TextStyle(color: Colors.white)),
)
),
);
}
),
),
);
return Scaffold(
body: Column(
children: <Widget>[
topContent,
Expanded(
child: bottomContent,
),
],
),
);
}
}
There is a ListView inside a SingleChildScrollView and both of them are scrollable. Scrolling on one of them should be disabled.
As they already explained. If you have a ListView.builder, you don't need SingleChildScrollView.
Try removing SingleChildScrollView. The code should look like this:
Scaffold(
body: Column(
children: <Widget>[
topContent,
Expanded(
child: bottomContent,
),
],
),
);
ListView already have scroll behavior so you won't need some SingleChildScrollView

How to fill vertical space in nested Column in ListView

I want the green box to fill the vertical space so MainAxisAlignment.spaceBetween will work.
import 'package:flutter/material.dart';
void main() => runApp(_app);
const title = "Layout test";
var _app = new MaterialApp(
title: title,
home: new Scaffold(
appBar: new AppBar(
title: const Text(title),
),
body: new _LayoutTest(),
),
);
class _LayoutTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return new ListView(
children: [
new Container(
color: Colors.orangeAccent,
margin: const EdgeInsets.only(bottom: 20.0),
child: new Row(
children: [
new Image.network(
// this can be any image
"http://via.placeholder.com/185x278",
width: size.width / 5,
),
new Expanded(
child: new Container(
margin: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0),
color: Colors.lightGreenAccent,
// this should fill vertical space
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
const Text("Top"),
const Text("Bottom"),
],
),
),
),
],
),
),
],
);
}
}
You can give the inner Container same height as outer container:
class _LayoutTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final newRandom = new Random().nextInt(50);
return new ListView(
children: [
new Container(
color: Colors.orangeAccent,
margin: const EdgeInsets.only(bottom: 20.0),
child: new Row(
children: [
new Container(
color: Colors.pinkAccent,
width: size.width / 5,
height: 200.0 + newRandom,
),
new Expanded(
child: new Container(
margin: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0),
color: Colors.lightGreenAccent,
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
const Text("Top"),
const Text("Bottom"),
],
),
height: 200.0 + newRandom,
),
),
],
),
),
],
);
}
}

Flutter - Overlay card widget on a container

In flutter, is it possible to place a part of a card on another container? In CSS, we would set margin-top to a negative value or use translate property. In flutter as we cannot set negative values to margin-top, is there an alternative to that?
Yes, you can acheive it with a Stack widget. You can stack a card over the background and provide a top or bottom padding.
A simple example would look like:
class StackDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
// The containers in the background
new Column(
children: <Widget>[
new Container(
height: MediaQuery.of(context).size.height * .65,
color: Colors.blue,
),
new Container(
height: MediaQuery.of(context).size.height * .35,
color: Colors.white,
)
],
),
// The card widget with top padding,
// incase if you wanted bottom padding to work,
// set the `alignment` of container to Alignment.bottomCenter
new Container(
alignment: Alignment.topCenter,
padding: new EdgeInsets.only(
top: MediaQuery.of(context).size.height * .58,
right: 20.0,
left: 20.0),
child: new Container(
height: 200.0,
width: MediaQuery.of(context).size.width,
child: new Card(
color: Colors.white,
elevation: 4.0,
),
),
)
],
);
}
}
The output of the above code would look something like:
Hope this helps!
Screenshot:
Instead of hardcoding Positioned or Container, you should use Align.
Code:
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: Stack(
children: [
Column(
children: [
Expanded(flex: 2, child: Container(color: Colors.indigo)),
Expanded(child: Container(color: Colors.white)),
],
),
Align(
alignment: Alignment(0, 0.5),
child: Container(
width: size.width * 0.9,
height: size.height * 0.4,
child: Card(
elevation: 12,
child: Center(child: Text('CARD', style: Theme.of(context).textTheme.headline2)),
),
),
),
],
),
);
}
Here is running example with overlay:
class _MyHomePageState extends State<MyHomePage> {
double _width = 0.0;
double _height = 0.0;
#override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
// The containers in the background and scrollable
getScrollableBody(),
// This container will work as Overlay
getOverlayWidget()
],
),
);
}
Widget getOverlayWidget() {
return new Container(
alignment: Alignment.bottomCenter,
child: new Container(
height: 100.0,
width: _width,
color: Colors.cyan.withOpacity(0.4),
),
);
}
Widget getScrollableBody() {
return SingleChildScrollView(
child: new Column(
children: <Widget>[
new Container(
height: _height * .65,
color: Colors.yellow,
),
new Container(
height: _height * .65,
color: Colors.brown,
),
new Container(
margin: EdgeInsets.only(bottom: 100.0),
height: _height * .65,
color: Colors.orange,
),
],
),
);
}
}
Here is Result of code:
Scrollable Body under customised Bottom Bar