Skip to content

Commit

Permalink
Scrollbar display always (flutter#50752)
Browse files Browse the repository at this point in the history
  • Loading branch information
onatcipli committed Mar 27, 2020
1 parent 763f875 commit ac3b77b
Show file tree
Hide file tree
Showing 4 changed files with 565 additions and 13 deletions.
91 changes: 85 additions & 6 deletions packages/flutter/lib/src/cupertino/scrollbar.dart
Expand Up @@ -60,6 +60,7 @@ class CupertinoScrollbar extends StatefulWidget {
const CupertinoScrollbar({
Key key,
this.controller,
this.isAlwaysShown = false,
@required this.child,
}) : super(key: key);

Expand Down Expand Up @@ -125,6 +126,60 @@ class CupertinoScrollbar extends StatefulWidget {
/// {@endtemplate}
final ScrollController controller;

/// {@template flutter.cupertino.cupertinoScrollbar.isAlwaysShown}
/// Indicates whether the [Scrollbar] should always be visible.
///
/// When false, the scrollbar will be shown during scrolling
/// and will fade out otherwise.
///
/// When true, the scrollbar will always be visible and never fade out.
///
/// The [controller] property must be set in this case.
/// It should be passed the relevant [Scrollable]'s [ScrollController].
///
/// Defaults to false.
///
/// {@tool snippet}
///
/// ```dart
/// final ScrollController _controllerOne = ScrollController();
/// final ScrollController _controllerTwo = ScrollController();
///
/// build(BuildContext context) {
/// return Column(
/// children: <Widget>[
/// Container(
/// height: 200,
/// child: Scrollbar(
/// isAlwaysShown: true,
/// controller: _controllerOne,
/// child: ListView.builder(
/// controller: _controllerOne,
/// itemCount: 120,
/// itemBuilder: (BuildContext context, int index)
/// => Text('item $index'),
/// ),
/// ),
/// ),
/// Container(
/// height: 200,
/// child: CupertinoScrollbar(
/// isAlwaysShown: true,
/// controller: _controllerTwo,
/// child: SingleChildScrollView(
/// controller: _controllerTwo,
/// child: SizedBox(height: 2000, width: 500,),
/// ),
/// ),
/// ),
/// ],
/// );
/// }
/// ```
/// {@end-tool}
/// {@endtemplate}
final bool isAlwaysShown;

@override
_CupertinoScrollbarState createState() => _CupertinoScrollbarState();
}
Expand Down Expand Up @@ -183,6 +238,28 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
..color = CupertinoDynamicColor.resolve(_kScrollbarColor, context)
..padding = MediaQuery.of(context).padding;
}
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
if (widget.isAlwaysShown) {
assert(widget.controller != null);
// Wait one frame and cause an empty scroll event. This allows the
// thumb to show immediately when isAlwaysShown is true. A scroll
// event is required in order to paint the thumb.
widget.controller.position.didUpdateScrollPositionBy(0);
}
});
}

@override
void didUpdateWidget(CupertinoScrollbar oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.isAlwaysShown != oldWidget.isAlwaysShown) {
if (widget.isAlwaysShown == true) {
assert(widget.controller != null);
_fadeoutAnimationController.animateTo(1.0);
} else {
_fadeoutAnimationController.reverse();
}
}
}

/// Returns a [ScrollbarPainter] visually styled like the iOS scrollbar.
Expand Down Expand Up @@ -228,11 +305,13 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
}

void _startFadeoutTimer() {
_fadeoutTimer?.cancel();
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
_fadeoutAnimationController.reverse();
_fadeoutTimer = null;
});
if (!widget.isAlwaysShown) {
_fadeoutTimer?.cancel();
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
_fadeoutAnimationController.reverse();
_fadeoutTimer = null;
});
}
}

bool _checkVertical() {
Expand Down Expand Up @@ -267,7 +346,7 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
_fadeoutTimer?.cancel();
_thicknessAnimationController.forward().then<void>(
(_) => HapticFeedback.mediumImpact(),
);
);
}

void _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) {
Expand Down
47 changes: 40 additions & 7 deletions packages/flutter/lib/src/material/scrollbar.dart
Expand Up @@ -37,6 +37,7 @@ class Scrollbar extends StatefulWidget {
Key key,
@required this.child,
this.controller,
this.isAlwaysShown = false,
}) : super(key: key);

/// The widget below this widget in the tree.
Expand All @@ -50,6 +51,9 @@ class Scrollbar extends StatefulWidget {
/// {@macro flutter.cupertino.cupertinoScrollbar.controller}
final ScrollController controller;

/// {@macro flutter.cupertino.cupertinoScrollbar.isAlwaysShown}
final bool isAlwaysShown;

@override
_ScrollbarState createState() => _ScrollbarState();
}
Expand Down Expand Up @@ -102,11 +106,33 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
_textDirection = Directionality.of(context);
_materialPainter = _buildMaterialScrollbarPainter();
_useCupertinoScrollbar = false;
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
if (widget.isAlwaysShown) {
assert(widget.controller != null);
// Wait one frame and cause an empty scroll event. This allows the
// thumb to show immediately when isAlwaysShown is true. A scroll
// event is required in order to paint the thumb.
widget.controller.position.didUpdateScrollPositionBy(0);
}
});
break;
}
assert(_useCupertinoScrollbar != null);
}

@override
void didUpdateWidget(Scrollbar oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.isAlwaysShown != oldWidget.isAlwaysShown) {
assert(widget.controller != null);
if (widget.isAlwaysShown == false) {
_fadeoutAnimationController.reverse();
} else {
_fadeoutAnimationController.animateTo(1.0);
}
}
}

ScrollbarPainter _buildMaterialScrollbarPainter() {
return ScrollbarPainter(
color: _themeColor,
Expand All @@ -126,17 +152,23 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
// iOS sub-delegates to the CupertinoScrollbar instead and doesn't handle
// scroll notifications here.
if (!_useCupertinoScrollbar &&
(notification is ScrollUpdateNotification || notification is OverscrollNotification)) {
(notification is ScrollUpdateNotification ||
notification is OverscrollNotification)) {
if (_fadeoutAnimationController.status != AnimationStatus.forward) {
_fadeoutAnimationController.forward();
}

_materialPainter.update(notification.metrics, notification.metrics.axisDirection);
_fadeoutTimer?.cancel();
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
_fadeoutAnimationController.reverse();
_fadeoutTimer = null;
});
_materialPainter.update(
notification.metrics,
notification.metrics.axisDirection,
);
if (!widget.isAlwaysShown) {
_fadeoutTimer?.cancel();
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
_fadeoutAnimationController.reverse();
_fadeoutTimer = null;
});
}
}
return false;
}
Expand All @@ -154,6 +186,7 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
if (_useCupertinoScrollbar) {
return CupertinoScrollbar(
child: widget.child,
isAlwaysShown: widget.isAlwaysShown,
controller: widget.controller,
);
}
Expand Down

0 comments on commit ac3b77b

Please sign in to comment.