123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- import 'dart:async';
- import 'package:flutter/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:photos/ui/huge_listview/scroll_bar_thumb.dart';
- class DraggableScrollbar extends StatefulWidget {
- final Widget child;
- final Color backgroundColor;
- final Color drawColor;
- final double heightScrollThumb;
- final EdgeInsetsGeometry padding;
- final int totalCount;
- final int initialScrollIndex;
- final int currentFirstIndex;
- final ValueChanged<double> onChange;
- final String Function(int) labelTextBuilder;
- final bool isEnabled;
- const DraggableScrollbar({
- Key key,
- @required this.child,
- this.backgroundColor = Colors.white,
- this.drawColor = Colors.grey,
- this.heightScrollThumb = 80.0,
- this.padding,
- this.totalCount = 1,
- this.initialScrollIndex = 0,
- this.currentFirstIndex = 0,
- @required this.labelTextBuilder,
- this.onChange,
- this.isEnabled = true,
- }) : super(key: key);
- @override
- DraggableScrollbarState createState() => DraggableScrollbarState();
- }
- class DraggableScrollbarState extends State<DraggableScrollbar>
- with TickerProviderStateMixin {
- static const thumbAnimationDuration = Duration(milliseconds: 1000);
- static const labelAnimationDuration = Duration(milliseconds: 1000);
- double thumbOffset = 0.0;
- bool isDragging = false;
- int currentFirstIndex;
- double get thumbMin => 0.0;
- double get thumbMax => context.size.height - widget.heightScrollThumb;
- AnimationController _thumbAnimationController;
- Animation<double> _thumbAnimation;
- AnimationController _labelAnimationController;
- Animation<double> _labelAnimation;
- Timer _fadeoutTimer;
- @override
- void initState() {
- super.initState();
- currentFirstIndex = widget.currentFirstIndex;
- if (widget.initialScrollIndex > 0 && widget.totalCount > 1) {
- WidgetsBinding.instance?.addPostFrameCallback((_) {
- setState(
- () => thumbOffset = (widget.initialScrollIndex / widget.totalCount) *
- (thumbMax - thumbMin),
- );
- });
- }
- _thumbAnimationController = AnimationController(
- vsync: this,
- duration: thumbAnimationDuration,
- );
- _thumbAnimation = CurvedAnimation(
- parent: _thumbAnimationController,
- curve: Curves.fastOutSlowIn,
- );
- _labelAnimationController = AnimationController(
- vsync: this,
- duration: labelAnimationDuration,
- );
- _labelAnimation = CurvedAnimation(
- parent: _labelAnimationController,
- curve: Curves.fastOutSlowIn,
- );
- }
- @override
- void dispose() {
- _thumbAnimationController.dispose();
- _labelAnimationController.dispose();
- _fadeoutTimer?.cancel();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- if (widget.isEnabled) {
- return Stack(
- children: [
- RepaintBoundary(child: widget.child),
- RepaintBoundary(child: buildThumb()),
- ],
- );
- } else {
- return widget.child;
- }
- }
- Widget buildKeyboard() {
- if (defaultTargetPlatform == TargetPlatform.windows) {
- return RawKeyboardListener(
- focusNode: FocusNode(),
- onKey: keyHandler,
- child: buildThumb(),
- );
- } else {
- return buildThumb();
- }
- }
- Widget buildThumb() => Padding(
- padding: widget.padding,
- child: Container(
- alignment: Alignment.topRight,
- margin: EdgeInsets.only(top: thumbOffset),
- child: ScrollBarThumb(
- widget.backgroundColor,
- widget.drawColor,
- widget.heightScrollThumb,
- widget.labelTextBuilder.call(currentFirstIndex),
- _labelAnimation,
- _thumbAnimation,
- onDragStart,
- onDragUpdate,
- onDragEnd,
- ),
- ),
- );
- void setPosition(double position, int currentFirstIndex) {
- setState(() {
- this.currentFirstIndex = currentFirstIndex;
- thumbOffset = position * (thumbMax - thumbMin);
- if (_thumbAnimationController.status != AnimationStatus.forward) {
- _thumbAnimationController.forward();
- }
- _fadeoutTimer?.cancel();
- _fadeoutTimer = Timer(thumbAnimationDuration, () {
- _thumbAnimationController.reverse();
- _labelAnimationController.reverse();
- _fadeoutTimer = null;
- });
- });
- }
- void onDragStart(DragStartDetails details) {
- setState(() {
- isDragging = true;
- _labelAnimationController.forward();
- _fadeoutTimer?.cancel();
- });
- }
- void onDragUpdate(DragUpdateDetails details) {
- setState(() {
- if (_thumbAnimationController.status != AnimationStatus.forward) {
- _thumbAnimationController.forward();
- }
- if (isDragging && details.delta.dy != 0) {
- thumbOffset += details.delta.dy;
- thumbOffset = thumbOffset.clamp(thumbMin, thumbMax);
- final double position = thumbOffset / (thumbMax - thumbMin);
- widget.onChange?.call(position);
- }
- });
- }
- void onDragEnd(DragEndDetails details) {
- _fadeoutTimer = Timer(thumbAnimationDuration, () {
- _thumbAnimationController.reverse();
- _labelAnimationController.reverse();
- _fadeoutTimer = null;
- });
- setState(() => isDragging = false);
- }
- void keyHandler(RawKeyEvent value) {
- if (value.runtimeType == RawKeyDownEvent) {
- if (value.logicalKey == LogicalKeyboardKey.arrowDown) {
- onDragUpdate(
- DragUpdateDetails(
- globalPosition: Offset.zero,
- delta: const Offset(0, 2),
- ),
- );
- } else if (value.logicalKey == LogicalKeyboardKey.arrowUp) {
- onDragUpdate(
- DragUpdateDetails(
- globalPosition: Offset.zero,
- delta: const Offset(0, -2),
- ),
- );
- } else if (value.logicalKey == LogicalKeyboardKey.pageDown) {
- onDragUpdate(
- DragUpdateDetails(
- globalPosition: Offset.zero,
- delta: const Offset(0, 25),
- ),
- );
- } else if (value.logicalKey == LogicalKeyboardKey.pageUp) {
- onDragUpdate(
- DragUpdateDetails(
- globalPosition: Offset.zero,
- delta: const Offset(0, -25),
- ),
- );
- }
- }
- }
- }
|