scrollbar_painter.dart 2.87 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
// 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
65
      ..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease)
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
      ..addListener(() {
        _opacity = _fade.value;
        renderer?.markNeedsPaint();
      });
    return _fade.forward();
  }

  Future scrollEnded() {
    return _fade.reverse();
  }

  void detach() {
    super.detach();
    _fade?.stop();
  }
}