This is my flutter website:
I want to add a scrollbar on my website like this for example:
this is my code:
import 'dart:core';
import 'dart:ui';
import 'package:braintrinig/animation/LongBreak.dart';
import 'package:braintrinig/animation/ShortBreak.dart';
import 'package:braintrinig/animation/StartPomodoro.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:interval_ticker_provider/interval_ticker_provider.dart';
import 'dart:async';
import 'package:responsive_sizer/responsive_sizer.dart';
class HomePageTimerUI extends StatefulWidget {
const HomePageTimerUI({Key? key}) : super(key: key);
@override
State<HomePageTimerUI> createState() => _HomePageTimerUIState();
}
class _HomePageTimerUIState extends State<HomePageTimerUI> with TickerProviderStateMixin {
late TabController _tabController;
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
void notify() {
if (countText == '00:00:00') {
_tabController.animateTo(1, duration: const Duration(milliseconds: 300));
}
}
@override
Widget build (BuildContext context) {
return Container(
height: 600,
width: double.infinity,
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
bottom: PreferredSize(
preferredSize: Size.fromHeight(55),
child: Container(
color: Colors.transparent,
child: SafeArea(
child: Column(
children: <Widget>[
TabBar(
controller: _tabController,
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: Color(0xff3B3B3B), width: 4.0),
insets: EdgeInsets.fromLTRB(
12.0, 12.0, 12.0, 11.0)),
indicatorWeight: 15,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Color(0xff3B3B3B),
labelStyle: TextStyle(
fontSize: 12,
letterSpacing: 1.3,
fontWeight: FontWeight.w500),
unselectedLabelColor: Color(0xffD7D7D7),
tabs: [
Tab(
text: "POMODORO",
icon: Icon(Icons.work_history, size: 40),
),
Tab(
text: "SHORT BREAK",
icon: Icon(Icons.ramen_dining, size: 40),
),
Tab(
text: "LONG BREAK",
icon: Icon(
Icons.battery_charging_full_rounded,
size: 40),
),
])
],
),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: <Widget>[
Center(
child: StartPomodoro(),
),
Center(
child: ShortBreak(),
),
Center(child: LongBreak()),
],
),
bottomNavigationBar: Container(
height: 110,
color: Color(0xffFAFAFA),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20),
child: GNav(
iconSize: 40,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
backgroundColor: Color(0xffFAFAFA),
color: Color(0xffD7D7D7),
activeColor: Color(0xff3B3B3B),
tabBackgroundColor: Color(0xffF0F0F0),
gap: 8,
onTabChange: (index) {
print(index);
},
padding: EdgeInsets.all(15),
tabs: [
GButton(
icon: Icons.settings,
text: 'Settings',),
GButton(
icon: Icons.person,
text: "Profile",),
GButton(
icon: Icons.task,
text: "Tasks",),
GButton(
icon: Icons.show_chart,
text: "Performance",
),
],
),
),
),)));
}
}
pomodoro.dart
import 'dart:async';
import 'package:braintrinig/animation/home_page_timer_ui.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:core';
import 'dart:math' as math;
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:responsive_sizer/responsive_sizer.dart';
import 'ShortBreak.dart';
class StartPomodoro extends StatefulWidget {
const StartPomodoro({Key? key}) : super(key: key);
@override
State<StartPomodoro> createState() => _StartPomodoroState();
}
class _StartPomodoroState extends State<StartPomodoro>
with TickerProviderStateMixin {
List<bool> isSelected = [true, false];
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
double progress = 1.0;
bool LongBreak = true;
void notify() {
if (countText == '00:00:00') {}
}
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 0),
);
controller.addListener(() {
notify();
if (controller.isAnimating) {
setState(() {
progress = controller.value;
});
} else {
setState(() {
progress = 1.0;
LongBreak = true;
});
}
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return ResponsiveSizer(builder: (context, orientation, screenType) {
return Device.screenType == ScreenType.mobile
? Scaffold(
backgroundColor:
LongBreak ? Color(0xffD94530) : Color(0xff6351c5),
body: GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Color(0xffD94530),
height: controller.value *
MediaQuery.of(context).size.height *
0.715,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Align(
alignment: FractionalOffset.bottomCenter,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment:
MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Text(
countText,
style: TextStyle(
fontSize: 90.0,
color: Color(0xffFAFAFA),
),
),
],
),
),
),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
);
}),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
child:
FloatingActionButton.extended(
backgroundColor:
Color(0xffFAFAFA),
onPressed: () {
if (controller
.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller
.value ==
0
? 1.0
: controller
.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating
? Icons.pause
: Icons.play_arrow,
color:
Color(0xff3B3B3B),
),
label: Text(
controller.isAnimating
? "Pause"
: "Pomoworko",
style: TextStyle(
color: Color(
0xff3B3B3B)),
)),
);
}),
SizedBox(width: 20, height: 100),
],
),
),
],
),
),
],
);
}),
),
)
: Scaffold(
backgroundColor:
LongBreak ? Color(0xffD94530) : Color(0xff6351c5),
body: GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Color(0xffD94530),
height: controller.value *
MediaQuery.of(context).size.height *
0.615,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Align(
alignment: FractionalOffset.bottomCenter,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment:
MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Text(
countText,
style: TextStyle(
fontSize: 90.0,
color: Color(0xffFAFAFA),
),
),
],
),
),
),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
);
}),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
child:
FloatingActionButton.extended(
backgroundColor:
Color(0xffFAFAFA),
onPressed: () {
if (controller
.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller
.value ==
0
? 1.0
: controller
.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating
? Icons.pause
: Icons.play_arrow,
color:
Color(0xff3B3B3B),
),
label: Text(
controller.isAnimating
? "Pause"
: "Pomoworko",
style: TextStyle(
color: Color(
0xff3B3B3B)),
)),
);
}),
SizedBox(width: 20, height: 100),
],
),
),
],
),
),
],
);
}),
),
);
});
}
}
class CustomTimerPainter extends CustomPainter {
CustomTimerPainter({
required this.animation,
required this.backgroundColor,
required this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
@override
bool shouldRepaint(CustomTimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
How to achieve the scrollbar?
I tried to implement Responsive Sizer, mostly to align the animation to the top bar and I thought that it could be a great idea to separate mobile and website, but it doesn't work
Device.screenType == ScreenType.mobile
? Scaffold
: Scaffold (web)
(that's what I thinked in the beginning, but it don't make any changes on my website changing MediaQuery.of(context).size.height * 0.715, to MediaQuery.of(context).size.height * 0.615, (its because the animation has certain lag when the timer starts))
How to be able to align the animation when timer starts to mobile and website and don't have any type of lag in the website side?
Thank you in advance if you can help in these two questions
CodePudding user response:
Have you tried the Scrollbar view widget for implementing the Scrollbar?
It goes like this:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
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(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scrollbar(
child: GridView.builder(
itemCount: 120,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text('item $index'),
);
},
),
);
}
}
Make sure that you have a fixed height widget in the Scrollbar, or there maybe chances for errors like the pixel overflow
CodePudding user response:
Wrap the content of the body of scaffold with a scrollbar widget
Scrollbar(
thicknesses: 10,
child: GestureDetector()
)