I'm trying to implement a list of image arranged in a column vertically. I used PageView Widget to make use of the PageChange listener to indicate what current page I currently am. However I am implementing this in WebView as well so I need to wrap it in ScrollBar. Although the Scrollbar is showing and moving accordingly, it is not draggable or not automatically scrolling if I used the ScrollBar. Is theres a work around this or a solution?
You have to pass the controller for the Scrollbar widget with the same controller of PageView widget.
Define a PageController
final PageController pageController = PageController(initialPage: 0);
Pass the pageController to the controller property of Scrollbar widget.
return Scrollbar(
controller: pageController,
isAlwaysShown: true, // This forces the scrollbar to be visible always
child: PageView(
scrollDirection: Axis.vertical,
controller: pageController,
You can set other properties like thickness and hoverthickness to addjust the thickness of the scroll bar. Refer this youtube video and documentation for more details.
A working demo. Also available as a dartpad here:
/// Flutter code sample for PageView
// Here is an example of [PageView]. It creates a centered [Text] in each of the three pages
// which scroll horizontally.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController pageController = PageController(initialPage: 0);
return Scrollbar(
controller: pageController,
isAlwaysShown: true,
thickness: 10,
showTrackOnHover: true,
hoverThickness: 15,
radius: Radius.circular(0),
child: PageView(
scrollDirection: Axis.vertical,
controller: pageController,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
),
);
}
}
Related
I'm trying to implement a sliding option that will basically, depending on if I go left or right, direct me to the previous/next message in my app (aka. trigger an action). It should work on the entire page, similar to how tinder slide left/right works. Is there any way to do this in flutter?
I've looked into the flutter_slidable but I'm not sure if I can make the sliding work on the whole page.
Would appreciate some help, thanks in advance!
You can use TabBarView for this:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main()
{
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Learning',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState()
{
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(text: "Flights", icon: Icon(Icons.flight),),
Tab(text: "Trains", icon: Icon(Icons.train)),
Tab(text: "Hotels",icon: Icon(Icons.restaurant)),
],
),
title: Text('Flutter TabBar'),
),
body: TabBarView(
children: const <Widget>[
Center(
child: Text("Flights"),
),
Center(
child: Text("Trains"),
),
Center(
child: Text("Hotels"),
),
],
),
),
);
}
}
Link
Flutter PageView is used to slide pages either vertically or horizontally.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('PageView ')),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return PageView(
/// [PageView.scrollDirection] defaults to [Axis.horizontal].
/// Use [Axis.vertical] to scroll vertically.
scrollDirection: Axis.horizontal,
controller: controller,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
);
}
}
The issue is on web when we try to scroll the vertically scrollable widget which is a child of horizontally scrollable widget where scroll bar is always visible.
When we scroll the horizontally scrollable widget the scroll bar for horizontal scroll is correctly displayed as shown in picture
horizontal scroll
But when we scroll the vertically scrollable widget the horizontal scrollbar disappears and new vertical scroll bar is seen at right as shown in screenshot
vertical scroll
Code to reproduce the issue.
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(
title: 'Scroll Issue Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Scroll Issue Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _horizontalController = ScrollController();
final List<ScrollController> _verticalController = [];
#override
void initState() {
super.initState();
for (int i = 0; i < 6; i++) {
_verticalController.add(ScrollController());
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Row(
children: <Widget>[
Expanded(
child: _buildHorizontalScroll(),
)
],
),
);
}
Widget _buildHorizontalScroll() {
return Scrollbar(
isAlwaysShown: true,
controller: _horizontalController,
notificationPredicate: (predicate) {
return predicate.depth == 0;
},
child: ListView.separated(
controller: _horizontalController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Container(
margin: const EdgeInsets.all(30),
width: 300,
color: Colors.black12,
child: Column(
children: [
Expanded(
child: _buildVerticalScroll(index),
)
],
),
),
separatorBuilder: (context, index) => const Divider(
height: 30,
),
itemCount: 6),
);
}
Widget _buildVerticalScroll(int index) {
return Scrollbar(
scrollbarOrientation: ScrollbarOrientation.right,
isAlwaysShown: true,
controller: _verticalController[index],
child: ListView.separated(
controller: _verticalController[index],
itemBuilder: (context, index) => Container(
margin: const EdgeInsets.all(30),
height: 100,
color: Colors.green,
),
separatorBuilder: (context, index) => const Divider(
height: 30,
),
itemCount: 200),
);
}
}
Checking the notification predicate in the horizontal scroll bar, it detects the depth of scroll as both 0 and 1 when scrolling the vertically scrollable list. Is there a workaround for this problem? The problem started to appear since the upgrade to 2.5.0 for stable channel of flutter.
Maybe this package will help you easily customize your thumb and scrolling track both horizontally and vertically
https://pub.dev/packages/cross_scroll
I am zoom a image inside interactive viewer , interactive viewer is a child of container ,set some height to container,after zoom a image, particular position in viewport ,i cant scroll and zoom a image
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Zoom(),
),
);
}
}
class Zoom extends StatefulWidget
{
#override
MyStatelessWidget createState()=> MyStatelessWidget();
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends State<Zoom> {
#override
Widget build(BuildContext context) {
return Center(
child:Container(height: 300,
child: InteractiveViewer(
scaleEnabled: true,maxScale: 4.0,
child: Center(
child:Container( child:Image.asset('Assets/Java-001.jpg',fit: BoxFit.cover,alignment: Alignment.center,)),
),
)));
}
}
How can i resolve this problem?
Try adding these arguments to the InteractiveViewer widget:
minScale: 0.1,
maxScale: 4.0,
boundaryMargin: const EdgeInsets.all(double.infinity),
constrained: false,
If your widget is greater than the viewport, you'll need to set constrained to false.
constrained: If set to false, then the child will be given infinite constraints. This is often useful when a child should be bigger than the InteractiveViewer.
InteractiveViewer(
constrained: false, // Set it to false.
child: YourContainer(...),
)
My current project has a scrollable row which works fine, but I can't find a way to make some kind of static scroll, where when you scroll to an item, the item is centered automatically.
This is what I currently have:
When the cards are scrolled they stay in the position when the scroll finish:
The effect I want to accomplish is the card aligning itself in the center when scrolling to the next card.
Is there a widget that actually works like that?
Try this,
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final List<String> images = ["Me", "You", "Foo", "Baa"];
final PageController controller = PageController(viewportFraction:0.8);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: PageView.builder(
controller: controller,
itemCount: images.length,
itemBuilder: (context,index){
return Container(
margin: EdgeInsets.all(16),
child: Center(child:Text(images[index])),
color: Colors.grey.shade200
);
}
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text('Hello, World!', style: Theme.of(context).textTheme.headline4);
}
}
The solution was simple:
Padding(
padding: const EdgeInsets.symmetric(vertical: 80),
child: Container(
child: PageView(
controller: controller,
scrollDirection: Axis.horizontal,
pageSnapping: true,
physics: BouncingScrollPhysics(),
children: [CardMovie(), CardMovie(), CardMovie()],
),
),
)
using PageView widget and giving a padding top because the height of the widget was the full screen.
I am trying to place a PageView which pages are scrollable vertically into a CustomScrollView.
The reason for this setup is that I want to make use of SliverAppBar. If one starts scrolling vertically, the AppBar starts shrinking and ultimately docks at the top of the screen. At the same time the currently active page's content is expanded. Once the AppBar is docked and the page's content reached it's maximum allowed size, it itself starts scrolling.
I am running into all sorts of problem, mostly issues with unbounded sizes.
The answer you've found as you've mentioned in the comments is correct. Instead of a CustomScrollView, NestedScrollView should be used because there are multiple scrollable views that will be managed on the screen. As mentioned in the docs, the most common use case for NestedScrollView is a scrollable view with a flexible SliverAppBar containing a TabBar in the header - similar to your use case.
Here's a working sample based from the snippet provided in the post you've referenced.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
var _scrollController, _tabController;
#override
void initState() {
_scrollController = ScrollController();
_tabController = TabController(vsync: this, length: 2);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text(widget.title),
pinned: true,
floating: true,
snap: false,
forceElevated: innerBoxIsScrolled,
bottom: TabBar(
tabs: <Tab>[
Tab(text: "Page 1"),
Tab(text: "Page 2"),
],
controller: _tabController,
),
),
];
},
body: TabBarView(
controller: _tabController,
children: <Widget>[
_pageView(),
_pageView(),
],
),
),
);
}
_pageView() {
return ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Container(
padding: EdgeInsets.all(16.0),
child: Text('List Item $index'),
),
);
},
);
}
}
Demo