How to give some space (margin/padding) between pages in PageView? - flutter

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

Related

Flutter ListView set 1 complete container at a time

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

The swap widget so that the under widget has been fixed

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

Flutter: cannot create horizontally scrollable body with shown scroll bar

I need help to create scrollable body:
my screen
This is how my structure of body looks: build()
body: Padding(
padding: const EdgeInsets.all(30.0),
child: DragAndDropLists(
children: _contents,
onItemReorder: _onItemReorder,
onListReorder: _onListReorder,
axis: Axis.horizontal,
listWidth: 300,
listDraggingWidth: 300,
listPadding: EdgeInsets.all(20.0),
itemDivider: const Divider(
thickness: 4,
height: 10,
color: lightBlue,
),
itemDecorationWhileDragging: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color(0xff004269).withOpacity(0.5),
spreadRadius: 2,
blurRadius: 3,
offset: const Offset(0, 0), // changes position of shadow
),
],
),
listInnerDecoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.all(Radius.circular(5)),
),
lastItemTargetHeight: 2,
addLastItemTargetHeightToTop: true,
lastListTargetSize: 40,
),
),
I tried already ListView, SingleChildScrollView, Column
I don't know why but it's doesn't work
Maybe somebody has an idea what I can change to see scrollbar and can scroll it horizontally
Thank you
You seem to be using a bit of complex layout, but a simplified version would look something like this:
You can set scrollDirection property of ListView to Axis.horizontal and for scrollbar you can wrap ListView inside Scrollbar.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final ScrollController _scrollController = ScrollController();
final List<int> _items = List<int>.generate(100, (int index) => index);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
height: 150,
child: Scrollbar(
isAlwaysShown: true,
controller: _scrollController,
child: ReorderableListView.builder(
scrollDirection: Axis.horizontal,
scrollController: _scrollController,
itemBuilder: buildItem,
itemCount: _items.length,
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final int item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
),
),
),
));
}
Widget buildItem(context, index) {
return Container(
key: Key('$index'),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.green[200],
),
margin: const EdgeInsets.all(8.0),
height: 100,
width: 100,
child: Center(child: Text('${_items[index]}')),
);
}
}
Ignore the handles, they only appear on desktop, drag and drop works on mobile devices.
Try wrap Padding in your Scaffold with SingleChildScrollView
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(),
)
Other option that you can use is GridView, and ListView.

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

Create image slider with pageView

i tried create a image slider like this image
i tried create this slider with PageView but a have a problem with pageview
and my code :
class SlideMusic extends StatefulWidget{
final Size _size;
final List<String> _listArts;
double itemExtent;
SlideMusic(this._size,this._listArts){
itemExtent = _size.width / 3;
}
#override
SlideMusicState createState() => SlideMusicState();
}
class SlideMusicState extends State<SlideMusic> {
double currentPage = 0;
PageController _pageController = PageController(
viewportFraction: 0.3333,
);
#override
void setState(fn) {
super.setState(fn);
_pageController.addListener((){
currentPage = _pageController.page;
});
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget._size.width,
height: widget.itemExtent,
child: Container(
color: Colors.green,
child: NotificationListener<ScrollNotification>(
onNotification: _onNotification,
child: PageView.builder(
controller: _pageController,
physics: BouncingScrollPhysics(),
itemCount: widget._listArts.length,
itemBuilder: (context, index){
return itemArt(widget._listArts[index], index);
},
),
)
)
);
}
bool _onNotification(ScrollNotification notification){
setState(() {
currentPage = _pageController.page;
print(currentPage);
});
}
double itemOffset(int index){
return (index - currentPage ).abs()* widget.itemExtent;
}
Widget itemArt(String image , int index){
Offset offset = Offset.zero;
if(index > currentPage.round())
offset = Offset(-itemOffset(index)/2,0);
else
offset = Offset(itemOffset(index)/2,0);
return Align(
alignment: Alignment.center,
child: Transform.translate(
offset: offset,
child: Container(
color: Colors.lightBlue,
child: LayoutBuilder(
builder: (context,constrat){
return SizedBox(
width: constrat.maxWidth - itemOffset(index)/3.5,
height: constrat.maxHeight - itemOffset(index) /3.5,
child: Center(
child: Image.asset(image)
),
);
},
)
),
)
);
}
}
Check out the Picture slider widget made with carousel_slider.
Don't mind the jankyness of GIF.
Code:
class PictureSlideShow extends StatefulWidget {
#override
_PictureSlideShowState createState() => _PictureSlideShowState();
}
class _PictureSlideShowState extends State<PictureSlideShow> {
#override
Widget build(BuildContext context) {
return Center(
child: CarouselSlider(
height: 200.0,
enlargeCenterPage: true,
items: [1, 2, 3, 4, 5].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: 400,
height: 400,
margin: EdgeInsets.all(0.5),
decoration:
BoxDecoration(color: Colors.lightBlue[100 * (i % 5)]),
child: Center(
child: Text(
'text $i',
style: TextStyle(fontSize: 16.0),
),
),
);
},
);
}).toList(),
),
);
}
}
This is a similiar design to what you wanted.