| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import 'package:flutter/animation.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| const double _kMinScrollbarThumbLength = 18.0; |
| const double _kScrollbarThumbGirth = 6.0; |
| const Duration _kScrollbarThumbFadeDuration = const Duration(milliseconds: 300); |
| |
| class ScrollbarPainter extends ScrollableListPainter { |
| |
| double _opacity = 0.0; |
| int get _alpha => (_opacity * 0xFF).round(); |
| |
| // TODO(hansmuller): thumb color should come from ThemeData. |
| Color get thumbColor => const Color(0xFF9E9E9E); |
| |
| void paintThumb(PaintingContext context, Rect thumbBounds) { |
| final Paint paint = new Paint()..color = thumbColor.withAlpha(_alpha); |
| context.canvas.drawRect(thumbBounds, paint); |
| } |
| |
| void paintScrollbar(PaintingContext context, Offset offset) { |
| final Rect viewportBounds = offset & viewportSize; |
| Point thumbOrigin; |
| Size thumbSize; |
| |
| if (isVertical) { |
| double thumbHeight = viewportBounds.height * viewportBounds.height / contentExtent; |
| thumbHeight = thumbHeight.clamp(_kMinScrollbarThumbLength, viewportBounds.height); |
| final double maxThumbTop = viewportBounds.height - thumbHeight; |
| double thumbTop = (scrollOffset / (contentExtent - viewportBounds.height)) * maxThumbTop; |
| thumbTop = viewportBounds.top + thumbTop.clamp(0.0, maxThumbTop); |
| thumbOrigin = new Point(viewportBounds.right - _kScrollbarThumbGirth, thumbTop); |
| thumbSize = new Size(_kScrollbarThumbGirth, thumbHeight); |
| } else { |
| double thumbWidth = viewportBounds.width * viewportBounds.width / contentExtent; |
| thumbWidth = thumbWidth.clamp(_kMinScrollbarThumbLength, viewportBounds.width); |
| final double maxThumbLeft = viewportBounds.width - thumbWidth; |
| double thumbLeft = (scrollOffset / (contentExtent - viewportBounds.width)) * maxThumbLeft; |
| thumbLeft = viewportBounds.left + thumbLeft.clamp(0.0, maxThumbLeft); |
| thumbOrigin = new Point(thumbLeft, viewportBounds.height - _kScrollbarThumbGirth); |
| thumbSize = new Size(thumbWidth, _kScrollbarThumbGirth); |
| } |
| |
| paintThumb(context, thumbOrigin & thumbSize); |
| } |
| |
| void paint(PaintingContext context, Offset offset) { |
| if (_alpha == 0) |
| return; |
| paintScrollbar(context, offset); |
| } |
| |
| ValuePerformance<double> _fade; |
| |
| Future scrollStarted() { |
| _fade ??= new ValuePerformance<double>() |
| ..duration = _kScrollbarThumbFadeDuration |
| ..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease) |
| ..addListener(() { |
| _opacity = _fade.value; |
| renderer?.markNeedsPaint(); |
| }); |
| return _fade.forward(); |
| } |
| |
| Future scrollEnded() { |
| return _fade.reverse(); |
| } |
| |
| void detach() { |
| super.detach(); |
| _fade?.stop(); |
| } |
| } |