I have a very simple ListView in which I have a container of full height
class TestApp extends StatelessWidget {
final List<MessageItem> items;
TestApp({Key? key, required this.items}) : super(key: key);
#override
Widget build(BuildContext context) {
final title = 'Mixed List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount: 3,
itemBuilder: (context, index) {
return ColorsBox(context);
},
),
),
],
),
),
);
}
Widget ColorsBox(context) {
return Container(
height: MediaQuery.of(context).size.height * 1,
color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt())
.withOpacity(1.0));
}
}
What I need to do is I need to set 1 container only at a time. Mean no half container will be shown only 1 colour container show on 1 time. If scroll then the second container then 3rd so on. Basically trying some TikTok stuff on ListView
You should Use PageView.Builder
PageController controller = PageController();
var currentPageValue = 0.0;
PageView.builder(
scrollDirection: Axis.vertical,
controller: controller,
itemCount: 10,
itemBuilder: (context, position) {
return Container(
color: position % 2 == 0 ? Colors.blue : Colors.pink,
child: Center(
child: Text(
"Page",
style: TextStyle(color: Colors.white, fontSize: 22.0),
),
),
);
},
)
It's already working Fine.
return Container(
margin: EdgeInsets.only(bottom: 15),
height: MediaQuery.of(context).size.height,
color: Colors.blue
.withOpacity(1.0));
}
Related
I have a create so simple slidable view pager with CarouselSlider:
return Scaffold(
body: CarouselSlider(
options: CarouselOptions(
viewportFraction: 1,
// aspectRatio: 1,
height: double.maxFinite,
// enlargeCenterPage: true,
),
items: List.generate(
10,
(i) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
color: (i % 2 == 0) ? Colors.red : Colors.green,
),
),
Text('text $i', style: TextStyle(fontSize: 16.0)),
],
)),
));
This is its result:
But as you can see next container connects to the first widget, I want when the first widget to be swapped to the left, the next widget appears under the first widget Not next to it. It looks like the following widget is fixed and we remove the top widget.
You can use a package called stacked_page_view, it is very simple, lightweight, and similar to the same original PageView in usage.
Example Snippet:
PageView.builder(
itemCount: 10,
scrollDirection: Axis.vertical,
controller: pageController,
itemBuilder: (context, index) {
return StackPageView(
controller: pageController,
index: index,
child: Container(
color: (colors..shuffle()).first,
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
),
);
},
)
Note: You can control the scroll axis with the property scrollDirection inside PageView.builder() with values of Axis.vertical or Axis.horizontal.
I finally find a way to create stack page view, This is a full codes:
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart';
import 'dummy_data.dart';
import 'page_view_item.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
/// The current page of the page view
double _page = 0;
/// The index of the leftmost element of the list to be displayed
int get _firstItemIndex => _page.toInt();
/// Controller to get the current position of the page view
final _controller = PageController(
viewportFraction: 0.5,
);
/// The width of a single item
late final _itemWidth =
MediaQuery.of(context).size.width * _controller.viewportFraction;
#override
void initState() {
super.initState();
_controller.addListener(() => setState(() {
_page = _controller.page!;
}));
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("LV Scroll"),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Positioned.fill(
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: _itemWidth,
child: FractionallySizedBox(
child: PageViewItem(
index: _firstItemIndex,
width: _itemWidth,
url: model[_firstItemIndex],
),
),
),
),
),
SizedBox(
height: 250,
child: PageView.builder(
padEnds: false,
controller: _controller,
itemBuilder: (context, index) {
return Opacity(
opacity: index <= _firstItemIndex ? 0 : 1,
child: PageViewItem(
index: index,
width: _itemWidth,
url: model[index],
),
);
},
itemCount: model.length,
),
),
],
),
],
),
);
}
}
it's result :
and its reference;
You can use a package called expandable_page_view, it is a PageView widget adjusting its height to currently displayed page. It accepts the same parameters as classic PageView.
ExpandablePageView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Container(color: Colors.blue);
},
),
I am sending data from my controller to my ui part i can't understand what the problem is and how to solve it. I tried every answer given on stackoverflow and many other websites but nothing seems to work for me:( i am sure my login part has no problem but my ui is not able to render the data According to my needs.
Code:
final singleViewController = Get.put(SingleViewController());
class SingleView extends StatelessWidget {
final List stanza;
final String paragraphId;
const SingleView({
Key? key,
required this.stanza,
required this.paragraphId,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(
stanza.toString().trim(),
style: const TextStyle(
fontSize: 25,
color: Colors.red,
),
),
),
body: Container(
height: 800,
color: Colors.amber,
child: Column(
children: [
GetBuilder<SingleViewController>(builder: (controller) {
return SizedBox(
height:600,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: singleViewController.foundedparagraph.length,
itemBuilder: (ctx, index) {
return Text(
singleViewController.foundedparagraph[index]["stanza"]
.toString(),
);
},
),
);
}),
],
),
),
),
);
}
}
this is the error i am receiving:
Error Image
I'm working with a StaggeredGridView within Flutter and I don't seem to see a way to center a tile if a tile is going to be the only tile in that "row".
For example, if I set the crossAxisCount of the StaggeredGridView to something like 6; and then sent the tile's crossAxisCellCount to 4, the tile occupies 4 "cells" starting from the left, leaving 2 "Cells" worth of empty space on the right if there isn't a tile that can occupy 2 cells.
Is it possible to force the tile to be centered? Essentially, making it occupy cells 2 - 5, leaving 1 empty cell on the left and 1 empty cell on the right?
I've tried wrapping the StaggeredGridView in a Center widget, but this didn't appear to make a difference.
Currently I have a stateful widget which has the following build method.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
);
}
In the View model for that widget there are two relevant functions that the StaggeredGridView uses: the displayCardTiles function that creates the StaggeredTiles, and the displayCards function which creates the widgets that go in the tiles. Those two functions are as follows:
List<StaggeredTile> _buildDisplayCardTiles(){
List<StaggeredTile> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(StaggeredTile.fit(bioCategory.crossAxisCellCount));
}
return myList;
}
List<Widget> _buildDisplayCards(){
List<Widget> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(ProfileItemCard(bioCategory: bioCategory));
}
return myList;
}
The "ProfileItemCard" is just a Card widget that displays a variety of Text widgets and checkboxes, but it's contents wouldn't impact the position of the Card within the StaggeredGridView.
I've also tried wrapping the ProfileItemCard in a Center widget, but it doesn't have any impact on how the Card is displayed.
Intro: I came into this myself, so I want to thank you for opening the question.
Baseline: calculate the remainder of the model count and the cross axis count (userProfile.bioCategories and 6 in the original question), then place the "remaining" tiles in a row (spaced evenly) and span the row all over entire grid width.
Demo
Repro: Github.
Code (a single-file solution, the only prerequsite is flutter_staggered_grid_view: 0.4.0):
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
void main() {
runApp(const TabBarDemo());
}
generateRandomColor() => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
class Model {
final num;
Model({this.num});
}
class ModelWidget extends StatelessWidget {
final Model model;
ModelWidget(this.model) : super();
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Container(
color: generateRandomColor(),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
model.num.toString(),
textAlign: TextAlign.center,
),
],
)),
);
}
}
class TabBarDemo extends StatelessWidget {
const TabBarDemo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// ------------------------------- given ----------------------------------
const CROSS_AXIS_COUNT = 6;
const CROSS_AXIS_SPACING = 10.0;
const MAIN_AXIS_SPACING = 10.0;
final models = List.generate(20, (_) => Model(num: Random().nextInt(100)));
// ------------------------------------------------------------------------
// ------------------------------ solution --------------------------------
final modelCount = models.length;
final int fittingCount = modelCount - modelCount % CROSS_AXIS_COUNT;
// ------------------------------------------------------------------------
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(
child: Text("problem"),
),
Tab(
child: Text("solution (static)"),
),
Tab(icon: Text("solution (builder)")),
],
),
title: const Text('staggered_grid - centering tiles'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: TabBarView(
children: [
// ------------------------------ problem ---------------------------------
Scaffold(
body: StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: models.map((m) => StaggeredTile.fit(1)).toList(),
children: models.map((m) => ModelWidget(m)).toList(),
),
),
// ------------------------------------------------------------------------
// ------------------------- solution (static) ----------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: [
...models.sublist(0, fittingCount).map((m) => StaggeredTile.fit(1)).toList(),
if (modelCount != fittingCount) StaggeredTile.fit(CROSS_AXIS_COUNT)
],
children: [
...models.sublist(0, fittingCount).map((m) => ModelWidget(m)).toList(),
if (modelCount != fittingCount)
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList())
],
);
}),
),
// ------------------------------------------------------------------------
// ------------------------- solution (builder) ---------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.countBuilder(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
itemCount: modelCount == fittingCount ? fittingCount : fittingCount + 1,
itemBuilder: (context, index) {
if (index < fittingCount) {
return ModelWidget(models.elementAt(index));
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList());
}
},
staggeredTileBuilder: (int index) {
if (index < fittingCount) {
return StaggeredTile.count(1, 1);
} else {
return StaggeredTile.count(CROSS_AXIS_COUNT, 1);
}
});
}),
),
// ------------------------------------------------------------------------
],
),
),
),
),
);
}
}
try wrapping in a center, then a container with aligment property
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: Container(
margin: EdgeInsets.all(50),
height: double.infinity,
alignment: Alignment.center,
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
),
);
}
I am designing the app in which i have to create some number of blocks which represent the flats of building.
in which i have 2 numbers
number of floors
number of flats per floor
so i tried 2 ways
Using gridview and give itemCount as number of floors crossAxisCount as - number of flats per floor
Using 2 Listview. first listview for floor - which scroll vertically and inside its builder second listview for flats which scroll horizontally.
but i want to make it as scrollable for both horizontally and vertically, so i don't know how to do it, can anyone help me please !
look this,created using listview
You can achieve this by nesting horizontal ListViews inside a vertical ListView:
ListView.builder(
shrinkWrap: true,
itemCount: 10,
itemExtent: 50,
itemBuilder: (context, verticalIndex) => ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 15,
itemExtent: 50,
itemBuilder: (context, appartmentIndex) => Container(),
),
);
Full Demo
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
const List<Color> kColors = [
Color(0x66a7414a),
Color(0x66282726),
Color(0x666a8a82),
Color(0x66a37c27),
Color(0x66563838),
];
const double kOpacity = .6;
const double kAppartmentSize = 64.0;
const TextStyle kFloorTextStyle = TextStyle(
fontSize: 8.0,
fontWeight: FontWeight.normal,
);
const TextStyle kApartmentTextStyle = TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
);
const int kMinNbFloors = 10;
const int kMaxNbFloors = 18;
const int kMinNbApartments = 3;
const int kMaxNbApartments = 10;
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Real Estate Demo',
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(title: Text('Real Estate Demo')),
body: MyWidget(),
),
),
);
}
class MyWidget extends HookWidget {
final Random random = new Random();
#override
Widget build(BuildContext context) {
final nbFloors = useState(
kMinNbFloors + random.nextInt(kMaxNbFloors - kMinNbFloors + 1));
final nbAppartments = useState(
List.generate(
nbFloors.value,
(index) =>
kMinNbApartments +
random.nextInt(kMaxNbApartments - kMinNbApartments + 1),
),
);
return ListView.builder(
shrinkWrap: true,
itemCount: nbFloors.value,
itemExtent: kAppartmentSize,
reverse: true,
itemBuilder: (context, floorIndex) => ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: nbAppartments.value[floorIndex],
itemExtent: kAppartmentSize,
itemBuilder: (context, appartmentIndex) => Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color:
kColors[random.nextInt(kColors.length)].withOpacity(kOpacity),
border: Border.all(
width: .5, // red as border color
),
image: DecorationImage(
image: AssetImage("images/window.png"),
fit: BoxFit.contain,
alignment: Alignment.center,
),
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(appartmentIndex.toString(), style: kApartmentTextStyle),
const SizedBox(width: 4.0),
Text(floorIndex.toString(), style: kFloorTextStyle),
],
),
),
),
),
);
}
}
I am using PageView.builder to create pages.
PageView.builder(
itemCount: _pagesList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
color: _pagesList[index],
);
}
)
What I currently have:
What I want:
i.e. I want to provide some Padding between pages (when they are being scrolled)
Reason: I will display Images in these pages, and since the Images will cover the full width of each page, it doesn't look nice when we scroll pages, since they are knitted together, like this:
How can I solve this?
PageController imagesController =
PageController(initialPage: 0, viewportFraction: 1.1);
PageView(
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: Container(
color: _pagesList[index],
),
);
}
),
If you want to add padding and still have your pages as wide as the screen:
I needed this exact same thing, also for displaying images. I wanted to add padding but at the same time have each image take up the entire screen width. I figured I could use Fahad Javed's technique and tweaking it a little bit by calculating the viewPortFraction based on the screen width and padding.
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width; // screen width
double screenPad = 16.0; // screen padding for swiping between pages
int _currentPosition = 0;
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: data.length,
controller: PageController(
initialPage: _currentPosition,
viewportFraction:
1 + (screenPad * 2 / screenWidth)), // calculate viewPortFraction
onPageChanged: (int value) {
_currentPosition = value;
},
itemBuilder: (BuildContext context, int position) {
return Padding(
padding: EdgeInsets.only(left: screenPad, right: screenPad),
child: Text('YOUR PAGE CONTENT'),
);
},
);
}
This answer from on the question asked by Amon Kataria Github
final pageController = PageController(viewportFraction: 1.1);
PageView.builder(
controller: pageController,
itemCount: _pagesList.length,
itemBuilder: (BuildContext context, int index) {
return FractionallySizedBox(
widthFactor: 1 / pageController.viewportFraction,
child: Container(
color: _pagesList[index],
),
);
},
);
Thanks #mono0926
Best effort:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: MyPageView()
)
);
}
}
class MyPageView extends StatefulWidget {
MyPageView({Key key}) : super(key: key);
_MyPageViewState createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
#override
Widget build(BuildContext context) {
return PageView(
children: <Widget>[
Container(
color: Colors.black,
child: Card(
color: Colors.red,
)
),
Container(
color: Colors.black,
child: Card(
color: Colors.blue,
),
),
Container(
color: Colors.black,
child: Card(
color: Colors.green,
),
),
],
);
}
}
You just need to add some padding around each page and the width of the page view must be at least the 'card width + the padding from both sides'. This worked for me:
class MyWidget extends StatelessWidget {
final _CARD_WIDTH = 220.0;
final PageController _controller = PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return Container(
height: _CARD_WIDTH,
width: _CARD_WIDTH + 32,
child: PageView(
scrollDirection: Axis.horizontal,
controller: _controller,
children: <Widget>[
_buildImageCard("1"),
_buildImageCard("2"),
_buildImageCard("3"),
],
),
);
}
Widget _buildImageCard(String text) {
return Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16),
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(15),
),
width: _CARD_WIDTH,
height: _CARD_WIDTH,
child: Center(
child: Text(text),
),
),
);
}
}