I'm trying to use Flow widget instead of BottomNavigationBar.
this is my code.
#override
Widget build(BuildContext context) {
final delegate = S.of(context);
return SafeArea(
child: Scaffold(
drawer: DrawerWidget(),
body: Stack(
children: [
_pages[_selectedPageIndex]['page'],
Positioned(
child: Container(
child: Flow(
delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
children: menuItems
.map<Widget>((IconData icon) => flowMenuItem(icon))
.toList(),
),
),
),
]),
}
But after adding left, right, bottom, or top properties to the Positioned widget, the Flow widget gon.
You can copy paste run full code below
You can use ConstrainedBox and set Stack fit and Positioned with Container
SafeArea(
child: Scaffold(
body: ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Stack(
alignment: Alignment.topLeft,
fit: StackFit.expand,
children: [
...
Positioned(
left: 0,
top: 0,
child: Container(
alignment: Alignment.topLeft,
width: MediaQuery.of(context).size.width,
height: 65,
child: FlowMenu()))
]),
),
),
);
working demo
full code
import 'package:flutter/cupertino.dart';
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FlowTest(),
);
}
}
class FlowTest extends StatefulWidget {
#override
_FlowTestState createState() => _FlowTestState();
}
class _FlowTestState extends State<FlowTest> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Stack(
alignment: Alignment.topLeft,
fit: StackFit.expand,
children: [
ListView(
shrinkWrap: true,
children: <Widget>[
Column(
children: <Widget>[
SizedBox(height: 20.0),
ListView.builder(
shrinkWrap: true,
itemCount: 5,
physics: PageScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.format_list_numbered,
color: Colors.white),
Padding(
padding: const EdgeInsets.only(right: 5.0)),
Text(index.toString(),
style: TextStyle(
fontSize: 20.0, color: Colors.white)),
],
),
),
Container(
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: true,
physics: PageScrollPhysics(),
childAspectRatio: 1.2,
children: List.generate(
8,
(index) {
return Container(
child: Card(
color: Colors.blue,
),
);
},
),
),
),
SizedBox(height: 20.0),
],
);
},
),
],
),
],
),
Positioned(
left: 0,
top: 0,
child: Container(
alignment: Alignment.topLeft,
width: MediaQuery.of(context).size.width,
height: 65,
child: FlowMenu()))
]),
),
),
);
}
}
class FlowMenu extends StatefulWidget {
#override
_FlowMenuState createState() => _FlowMenuState();
}
class _FlowMenuState extends State<FlowMenu>
with SingleTickerProviderStateMixin {
AnimationController menuAnimation;
IconData lastTapped = Icons.notifications;
final List<IconData> menuItems = <IconData>[
Icons.home,
Icons.new_releases,
Icons.notifications,
Icons.settings,
Icons.menu,
];
void _updateMenu(IconData icon) {
if (icon != Icons.menu) setState(() => lastTapped = icon);
}
#override
void initState() {
super.initState();
menuAnimation = AnimationController(
duration: const Duration(milliseconds: 250),
vsync: this,
);
}
Widget flowMenuItem(IconData icon) {
final double buttonDiameter =
MediaQuery.of(context).size.width / menuItems.length;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: RawMaterialButton(
fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
splashColor: Colors.amber[100],
shape: CircleBorder(),
constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
onPressed: () {
_updateMenu(icon);
menuAnimation.status == AnimationStatus.completed
? menuAnimation.reverse()
: menuAnimation.forward();
},
child: Icon(
icon,
color: Colors.white,
size: 45.0,
),
),
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Flow(
delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
children: menuItems
.map<Widget>((IconData icon) => flowMenuItem(icon))
.toList(),
),
);
}
}
class FlowMenuDelegate extends FlowDelegate {
FlowMenuDelegate({this.menuAnimation}) : super(repaint: menuAnimation);
final Animation<double> menuAnimation;
#override
bool shouldRepaint(FlowMenuDelegate oldDelegate) {
return menuAnimation != oldDelegate.menuAnimation;
}
#override
void paintChildren(FlowPaintingContext context) {
double dx = 0.0;
for (int i = 0; i < context.childCount; ++i) {
dx = context.getChildSize(i).width * i;
context.paintChild(
i,
transform: Matrix4.translationValues(
dx * menuAnimation.value,
0,
0,
),
);
}
}
}
Related
In my flutter application I want to create a timetable widget as below which will scroll horizontally and vertically with corresponding heading. The timetable should have 'Day' as horizontal heading and 'Period' as vertical heading. During horizontal scrolling the 'Period' header should freeze and horizontal 'Day' header should scroll with data. Similarly, during vertical scrolling the 'Day' header should freeze and vertical 'Period' header should scroll with data. How can I achieve a widget like that.Please help..
In Android we can obtain the above type of scrolling by extending HorizontalScrollView & VerticalScrollView.
You can archive this using nested listView widgets.
You can try this approach:
class TimeTableView extends StatefulWidget {
const TimeTableView({super.key});
#override
State<TimeTableView> createState() => _TimeTableViewState();
}
class _TimeTableViewState extends State<TimeTableView> {
final periodsSlots = 15;
final double containerHeight = 55.0;
final double containerWidth = 80;
final days = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
final subjects = [
"Maths",
"Hindi",
"English",
"Chemistry",
"History",
"Geography",
];
late ScrollController mainController;
late ScrollController secondController;
#override
void initState() {
super.initState();
secondController = ScrollController();
mainController = ScrollController()
..addListener(() {
if (mainController.hasClients && secondController.hasClients) {
secondController.jumpTo(mainController.offset);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Time Table"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: PageView(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
// Top header View
SizedBox(
height: containerHeight,
width: containerWidth,
child: CustomPaint(
painter: RectanglePainter(),
child: Stack(
children: const [
Align(
alignment: Alignment.topRight,
child: Padding(
padding: EdgeInsets.all(4.0),
child: Text("Day"),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.all(4.0),
child: Text("Period"),
),
),
],
),
),
),
Expanded(
child: SizedBox(
height: containerHeight,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
controller: mainController,
child: Row(
children: List<Widget>.generate(
days.length,
(index) => Container(
height: containerHeight,
width: containerWidth,
color: bgColorHeader(index),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8),
child: Center(child: Text(days[index])),
),
),
),
),
),
),
)
],
),
SizedBox(
// Added fixed size to scroll listView horizontal
height: 500,
child: ListView.builder(
physics: const ClampingScrollPhysics(),
padding:
EdgeInsets.zero, // remove listview default padding.
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: periodsSlots,
itemBuilder: (context, index) => Container(
height: containerHeight,
width: containerWidth,
color: bgColorHeader(index),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// period header
Padding(
padding: EdgeInsets.zero,
child: SizedBox(
width: containerWidth,
height: containerHeight,
child: Center(child: Text("period ${index + 1}")),
),
),
// period subjects
Expanded(
child: SizedBox(
height: containerHeight,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
controller: secondController,
child: Row(
children: List<Widget>.generate(
subjects.length,
(index) => Container(
color: Colors.white,
child: Container(
height: containerHeight,
width: containerWidth,
color: bgColorSubject(index),
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4),
child: Text(subjects[index]),
)),
),
),
),
),
),
),
)
],
),
),
),
)
],
),
],
),
),
);
}
// Alternate background colors
Color bgColorHeader(int index) =>
index % 2 == 0 ? Colors.cyan.withOpacity(0.5) : Colors.cyanAccent;
Color bgColorSubject(int index) =>
index % 2 == 0 ? Colors.grey.withOpacity(0.5) : Colors.grey;
}
// Draw cross line from top left container
class RectanglePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final backgroundPaint = Paint()
..color = Colors.cyanAccent
..strokeWidth = 2.0
..strokeCap = StrokeCap.round;
final crossLine = Paint()
..color = Colors.white
..strokeWidth = 2.0
..strokeCap = StrokeCap.round;
// Draw the rectangle
canvas.drawRect(Offset.zero & size, backgroundPaint);
// Draw the cross line
canvas.drawLine(Offset.zero, Offset(size.width, size.height), crossLine);
//canvas.drawLine(Offset(0, size.height), Offset(size.width, 0), crossLine);
}
#override
bool shouldRepaint(RectanglePainter oldDelegate) => false;
}
Scrolling widgets will create a default scroll controller (ScrollController class) if none is provided. A scroll controller creates a ScrollPosition to manage the state specific to an individual Scrollable widget.
To link our scroll controllers we’ll use linked_scroll_controller, a scroll controller that allows two or more scroll views to be in sync.
import 'package:flutter/material.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
class ScrollDemo extends StatefulWidget {
#override
_ScrollDemoState createState() => _ScrollDemoState();
}
class _ScrollDemoState extends State<ScrollDemo> {
final List<String> colEntries = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
final List<String> rowEntries =
Iterable<int>.generate(15).map((e) => e.toString()).toList();
late LinkedScrollControllerGroup _horizontalControllersGroup;
late ScrollController _horizontalController1;
late ScrollController _horizontalController2;
late LinkedScrollControllerGroup _verticalControllersGroup;
late ScrollController _verticalController1;
late ScrollController _verticalController2;
#override
void initState() {
super.initState();
_horizontalControllersGroup = LinkedScrollControllerGroup();
_horizontalController1 = _horizontalControllersGroup.addAndGet();
_horizontalController2 = _horizontalControllersGroup.addAndGet();
_verticalControllersGroup = LinkedScrollControllerGroup();
_verticalController1 = _verticalControllersGroup.addAndGet();
_verticalController2 = _verticalControllersGroup.addAndGet();
}
#override
void dispose() {
_horizontalController1.dispose();
_horizontalController2.dispose();
_verticalController1.dispose();
_verticalController2.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('sync scroll demo'),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 75,
height: 75,
color: Colors.grey[200],
),
const SizedBox(width: 10),
Container(
height: 75,
width: 400,
color: Colors.blue[100],
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalController2,
child: HeaderContainer(rowEntries: rowEntries),
),
)
],
),
const SizedBox(height: 10),
Row(
children: <Widget>[
Container(
width: 75,
height: 400,
color: Colors.blue[100],
child: SingleChildScrollView(
controller: _verticalController2,
child: ColumnContainer(
colEntries: colEntries,
),
),
),
const SizedBox(width: 10),
SizedBox(
width: 400,
height: 400,
child: SingleChildScrollView(
controller: _verticalController1,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalController1,
child: BodyContainer(
rowEntries: rowEntries,
colEntries: colEntries,
),
),
),
)
],
),
],
),
),
),
);
}
}
class ColumnContainer extends StatelessWidget {
final List<String> colEntries;
const ColumnContainer({
Key? key,
required this.colEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int numberOfRows = colEntries.length;
return Column(
children: List.generate(
numberOfRows,
(i) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.white)),
child: Center(child: Text(colEntries[i])),
);
},
),
);
}
}
class HeaderContainer extends StatelessWidget {
final List<String> rowEntries;
const HeaderContainer({
Key? key,
required this.rowEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int _numberOfColumns = rowEntries.length;
return Row(
children: List.generate(
_numberOfColumns,
(i) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.white)),
child: Center(child: Text(rowEntries[i])),
);
},
),
);
}
}
class BodyContainer extends StatelessWidget {
final List<String> colEntries;
final List<String> rowEntries;
const BodyContainer({
Key? key,
required this.colEntries,
required this.rowEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int _numberOfColumns = rowEntries.length;
int _numberOfLines = colEntries.length;
return Column(
children: List.generate(_numberOfLines, (y) {
return Row(
children: List.generate(_numberOfColumns, (x) {
return TableCell(item: "${colEntries[y]}${rowEntries[x]}");
}),
);
}),
);
}
}
class TableCell extends StatelessWidget {
final String item;
const TableCell({
Key? key,
required this.item,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Center(child: Text(item)),
);
}
}
I found these solutions from these 2 links.
Flutter: How to create linked scroll widgets
Flutter: Creating a two-direction scrolling table with a fixed head and column
I'm looking for a tutorial on using a horizontal ListView that behaves like a Tabview, ie displaying the link on the same screen.
Some links to propose?
thanks
Tab child can others widget too, use height on Tab and isScrollable:true on TabBar
class TabBarDemo extends StatelessWidget {
const TabBarDemo({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
tabs: [
Tab(
height: 100, // height
icon: Card(
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
)),
Tab(
icon: Icon(Icons.directions_transit),
),
Tab(
icon: Icon(Icons.directions_bike),
),
],
),
title: const Text('Tabs Demo'),
),
body: const TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
more about tabs
And using PageView & ListView, it will be
class TabBarDemo extends StatelessWidget {
const TabBarDemo({super.key});
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return Scaffold(
body: Column(
children: [
SizedBox(
height: 100, //tab item height
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
controller.animateToPage(index,
duration: Duration(milliseconds: 100),
curve: Curves.bounceIn);
},
child: Container(
height: 100,
width: 100,
color: Colors.red,
child: Card(
child: Text("tab $index"),
),
),
),
),
),
Expanded(
child: PageView.builder(
controller: controller,
itemBuilder: (context, index) {
return Center(
child: Text("$index"),
);
},
),
),
],
),
);
}
}
Also you can check CustomScrollView.
run this example and you will get the whole idea :
class ListTapPage extends StatefulWidget {
const ListTapPage({Key? key}) : super(key: key);
#override
State<ListTapPage> createState() => _ListTapPageState();
}
class _ListTapPageState extends State<ListTapPage> {
List<Widget> pages = [const Center(child: Text("one")),const Center(child: Text("two")),const Center(child: Text("three"),)];
List<String> names = ["one","two","three"];
List<Color> colors = [Colors.red,Colors.blue,Colors.yellow];
int _index = 0 ;
void changeIndex({required int num}){
setState((){
_index = num;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Positioned(top: 0,right: 0,left: 0,bottom: MediaQuery.of(context).size.height * 0.75,
child: SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return GestureDetector(
onTap:()=>changeIndex(num: index) ,
child: Container(alignment: Alignment.center,width: 200,height: 50,color: colors[index],child: Text(names[index])),
);
},
),
)
),
Positioned(
left: 0,
right: 0,
bottom: 0,
height: MediaQuery.of(context).size.height * 0.30,
child: pages[_index]
),
]
),
),
);
}
}
just return this widget in the material app ,see the result and look at the code , you will understand , it's a simple demo.
I want to remove the following blue padding from MaterialBanner widget, but it doesn't seem to be customizable. I want to insert an image in the red region.
I looked into MaterialBanner for using across Scaffold widgets because ScaffoldMessenger doesn't allow me to insert widgets other than MaterialBanner.
Is there any suggestion?
dartpad.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Scaffold(body: JustBanner())));
}
class JustBanner extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _JustBannerState();
}
}
class _JustBannerState extends State<JustBanner> {
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
final messenger = ScaffoldMessenger.of(context);
messenger.clearMaterialBanners();
messenger.showMaterialBanner(MaterialBanner(
padding: EdgeInsets.zero,
leadingPadding: EdgeInsets.zero,
leading: const SizedBox.shrink(),
backgroundColor: Colors.blue,
content: Container(
color: Colors.red,
width: 200,
height: 50,
),
actions: const [SizedBox.shrink()]));
},
child: const Text('Banner')),
],
);
}
}
Container(
width: MediaQuery.of(context).size.width,
child: MaterialBanner(
content: Text('Hello'),
actions: [
Icon(Icons.add),
],
),
),
Its no possible without copy and re-create the class, buttonBar always appear:
final Widget buttonBar = Container( // <-- problematic widget
alignment: AlignmentDirectional.centerEnd,
constraints: const BoxConstraints(minHeight: 52.0),
padding: const EdgeInsets.symmetric(horizontal: 8),
child: OverflowBar(
overflowAlignment: widget.overflowAlignment,
spacing: 8,
children: widget.actions,
),
);
final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0;
final Color backgroundColor = widget.backgroundColor
?? bannerTheme.backgroundColor
?? theme.colorScheme.surface;
final TextStyle? textStyle = widget.contentTextStyle
?? bannerTheme.contentTextStyle
?? theme.textTheme.bodyText2;
Widget materialBanner = Container(
margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0),
child: Material(
elevation: elevation,
color: backgroundColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: padding,
child: Row(
children: <Widget>[
if (widget.leading != null)
Padding(
padding: leadingPadding,
child: widget.leading,
),
Expanded(
child: DefaultTextStyle(
style: textStyle!,
child: widget.content,
),
),
if (isSingleRow)
buttonBar, // <----- here
],
),
),
if (!isSingleRow)
buttonBar, // <----- here
if (elevation == 0)
const Divider(height: 0),
],
),
),
);
I want to build a portfolio website with flutter and I can't find fade-in animation while scrolling down,
there are animatedBox and a lot of animation but none of them have listeners for fading in while scrolling down.
Can anyone help me with this? An example would be more helpful.
Thank you
After a while, I find a way to do that, we should use the scrollController and mediaQuery for riching this goal,
source code
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: 'Ali Azimoshan',
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController _scrollController;
var selectedSlide;
imageBox() {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-1.jpg',
),
),
),
),
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-2.jpg',
),
),
),
),
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-3.jpg',
),
),
),
),
],
),
);
}
List allSlides = [
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false}
];
#override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController.addListener(changeSelector);
setState(() {
selectedSlide = allSlides[0];
selectedSlide['selected'] = true;
});
}
changeSelector() {
var maxScrollVal = _scrollController.position.maxScrollExtent;
var divisor = (maxScrollVal / allSlides.length) + 20;
var scrollValue = _scrollController.offset.round();
var slideValue = (scrollValue / divisor).round();
// var currentSlide = allSlides.indexWhere((slide) => slide['selected']);
setState(() {
// allSlides[currentSlide]['selected'] = false;
selectedSlide = allSlides[slideValue];
selectedSlide['selected'] = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
child: ListView(
controller: _scrollController,
children: allSlides.map((element) {
return getCards(element);
}).toList(),
),
)
],
),
);
}
Widget getCards(slide) {
return Padding(
padding: EdgeInsets.all(0),
child: AnimatedCrossFade(
firstChild: imageBox(),
duration: Duration(seconds: 1),
secondChild: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.transparent,
),
crossFadeState: slide['selected']
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
),
);
}
}
Ok here's a little demo
here's the code
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
class overall extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<overall> {
double offset = 0;
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
final nameStyle = Theme.of(context).textTheme.headline2;
final descriptionStyle = Theme.of(context).textTheme.headline4;
final workStyle = Theme.of(context).textTheme.headline6;
return Material(
child: NotificationListener<ScrollNotification>(
onNotification: updateOffsetAccordingToScroll,
child: ScrollConfiguration(
behavior: NoScrollGlow(),
child: Stack(
children: <Widget>[
Positioned(
top: -.45 * offset,
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: backgroundImage,
height: height,
width: width,
fit: BoxFit.fitWidth,
),
),
Positioned(
top: -.25 * offset,
child: SizedBox(
height: height,
width: width,
child: Align(
alignment: Alignment(0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
circleIcon(profileicon, 100),
Text(
'My Name',
style: nameStyle.copyWith(
color: Colors.white,
),
),
SizedBox(height: 20),
Text(
'Representing my core values here',
style: descriptionStyle.copyWith(
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Text(
"Currently Working with",
style: workStyle.copyWith(
color: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: circleIcon(fluttericon, 40),
),
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: circleIcon(darticon, 40)),
],
),
)
],
)),
),
),
SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height: height),
Container(
height: height,
width: width,
color: Colors.blueAccent,
)
],
),
)
],
),
),
),
);
}
bool updateOffsetAccordingToScroll(ScrollNotification scrollNotification) {
setState(() => offset = scrollNotification.metrics.pixels);
return true;
}
}
class NoScrollGlow extends ScrollBehavior {
#override
Widget buildViewportChrome(
BuildContext context,
Widget child,
AxisDirection axisDirection,
) {
return child;
}
}
circleIcon(String icon, size) {
return CircleAvatar(
radius: size,
backgroundImage: NetworkImage(icon),
);
}
const backgroundImage = 'https://wallpaperaccess.com/full/7033.jpg';
const profileicon =
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg';
const darticon =
'data:image/png;base64,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';
const fluttericon =
'https://cdn.iconscout.com/icon/free/png-512/flutter-2038877-1720090.png';
in this sample code which that have ListView and Container i would like to make simple gradient top of ListView when user is scrolling ListView items to right or left,
scrolling items to right should show gradient divider and scrolling to left should hide the divider, all of this visiblity should be have fade effect, could you help me how can i show and hide this gradient divider?
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(SampleShadow());
class SampleShadow extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'sample',
home: ShadowContainer(),
);
}
}
class ShadowContainer extends StatefulWidget {
#override
State<StatefulWidget> createState() => _ShadowContainer();
}
class _ShadowContainer extends State<ShadowContainer> with TickerProviderStateMixin {
final ValueNotifier<bool> showShadow = ValueNotifier<bool>(false);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
backgroundColor: Colors.indigo.withOpacity(0.7),
appBar: AppBar(),
body: Container(
margin: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 100.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: Colors.indigo[400],
borderRadius: BorderRadius.circular(100.0),
),
),
Expanded(
child: Stack(children: <Widget>[
NotificationListener<ScrollNotification>(
onNotification: (scrollState) {
if (scrollState is ScrollEndNotification && scrollState.metrics.pixels >= 100) {
showShadow.value = true;
print('show');
} else {
showShadow.value = false;
print('hide');
}
return false;
},
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10.0),
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: Colors.purple[400],
borderRadius: BorderRadius.circular(100.0),
),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 50),
),
ValueListenableBuilder<bool>(
valueListenable: showShadow,
builder: (context, value, child) => value? Container(
width: 10.0,
color: Colors.green,
): Container()),
]),
),
],
),
),
],
),
),
),
);
}
}
this solution work fine, thanks to #CopsOnRoad
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(SampleShadow());
class SampleShadow extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'sample',
home: ShadowContainer(),
);
}
}
class ShadowContainer extends StatefulWidget {
#override
State<StatefulWidget> createState() => _ShadowContainer();
}
class _ShadowContainer extends State<ShadowContainer> with TickerProviderStateMixin {
final ValueNotifier<bool> showShadow = ValueNotifier<bool>(false);
AnimationController _animationController;
Animation<double> _fadeInFadeOut;
ScrollController _scrollController;
#override
void initState() {
super.initState();
_scrollController = ScrollController();
_animationController = AnimationController(vsync: this, duration: kThemeAnimationDuration);
_fadeInFadeOut = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
_animationController.forward();
_scrollController.addListener(() {
if (_scrollController.offset >= 10) {
showShadow.value = true;
} else {
showShadow.value = false;
}
});
}
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
backgroundColor: Colors.indigo.withOpacity(0.7),
appBar: AppBar(),
body: Container(
margin: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 100.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: Colors.indigo[400],
borderRadius: BorderRadius.circular(100.0),
),
),
Expanded(
child: Stack(children: <Widget>[
ListView.separated(
controller: _scrollController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10.0),
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: Colors.purple[400],
borderRadius: BorderRadius.circular(100.0),
),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 50),
ValueListenableBuilder<bool>(
valueListenable: showShadow,
builder: (context, value, child) {
if (value) {
_animationController.forward();
} else {
_animationController.reverse();
}
return FadeTransition(
opacity: _fadeInFadeOut,
child: Container(
width: 10.0,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.centerLeft,
colors: [Colors.black.withOpacity(0.5), Colors.transparent])),
),
);
}),
]),
),
],
),
),
],
),
),
),
);
}
}