switch.dart 4.63 KB
Newer Older
1 2 3 4
// 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.

5
import 'dart:async';
6 7
import 'dart:sky' as sky;

8
import 'package:sky/material.dart';
9
import 'package:sky/painting.dart';
10
import 'package:sky/rendering.dart';
11 12 13
import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/theme.dart';
import 'package:sky/src/widgets/framework.dart';
14

15
export 'package:sky/rendering.dart' show ValueChanged;
16 17 18 19 20 21 22 23

const sky.Color _kThumbOffColor = const sky.Color(0xFFFAFAFA);
const sky.Color _kTrackOffColor = const sky.Color(0x42000000);
const double _kSwitchWidth = 35.0;
const double _kThumbRadius = 10.0;
const double _kSwitchHeight = _kThumbRadius * 2.0;
const double _kTrackHeight = 14.0;
const double _kTrackRadius = _kTrackHeight / 2.0;
24 25 26
const double _kTrackWidth =
    _kSwitchWidth - (_kThumbRadius - _kTrackRadius) * 2.0;
const Size _kSwitchSize = const Size(_kSwitchWidth + 2.0, _kSwitchHeight + 2.0);
27
const double _kReactionRadius = _kSwitchWidth / 2.0;
28

29
class Switch extends StatelessComponent {
30
  Switch({ Key key, this.value, this.onChanged })
31 32 33 34 35
      : super(key: key);

  final bool value;
  final ValueChanged onChanged;

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  Widget build(BuildContext context) {
    return new _SwitchWrapper(
      value: value,
      thumbColor: Theme.of(context).accentColor,
      onChanged: onChanged
    );
  }
}

class _SwitchWrapper extends LeafRenderObjectWidget {
  _SwitchWrapper({ Key key, this.value, this.thumbColor, this.onChanged })
      : super(key: key);

  final bool value;
  final Color thumbColor;
  final ValueChanged onChanged;

  _RenderSwitch createRenderObject() => new _RenderSwitch(
54
    value: value,
55
    thumbColor: thumbColor,
56 57
    onChanged: onChanged
  );
58

59
  void updateRenderObject(_RenderSwitch renderObject, _SwitchWrapper oldWidget) {
60
    renderObject.value = value;
61
    renderObject.thumbColor = thumbColor;
62
    renderObject.onChanged = onChanged;
63 64 65
  }
}

66
class _RenderSwitch extends RenderToggleable {
67 68 69 70 71
  _RenderSwitch({
    bool value,
    Color thumbColor: _kThumbOffColor,
    ValueChanged onChanged
  }) : _thumbColor = thumbColor,
72
        super(value: value, onChanged: onChanged, size: _kSwitchSize) {}
73 74

  Color _thumbColor;
75
  Color get thumbColor => _thumbColor;
76 77 78 79 80 81
  void set thumbColor(Color value) {
    if (value == _thumbColor) return;
    _thumbColor = value;
    markNeedsPaint();
  }

82 83
  RadialReaction _radialReaction;

Adam Barth's avatar
Adam Barth committed
84
  void handleEvent(sky.Event event, BoxHitTestEntry entry) {
85
    if (event is sky.PointerEvent) {
Adam Barth's avatar
Adam Barth committed
86
      if (event.type == 'pointerdown')
87
        _showRadialReaction(entry.localPosition);
Adam Barth's avatar
Adam Barth committed
88
      else if (event.type == 'pointerup')
89 90
        _hideRadialReaction();
    }
Adam Barth's avatar
Adam Barth committed
91
    super.handleEvent(event, entry);
92 93 94 95 96 97 98 99
  }

  void _showRadialReaction(Point startLocation) {
    if (_radialReaction != null)
      return;
    _radialReaction = new RadialReaction(
      center: new Point(_kSwitchSize.width / 2.0, _kSwitchSize.height / 2.0),
      radius: _kReactionRadius,
100 101 102
      startPosition: startLocation
    )..addListener(markNeedsPaint)
     ..show();
103 104 105 106 107 108 109 110 111
  }

  Future _hideRadialReaction() async {
    if (_radialReaction == null)
      return;
    await _radialReaction.hide();
    _radialReaction = null;
  }

112 113
  void paint(PaintingContext context, Offset offset) {
    final PaintingCanvas canvas = context.canvas;
114 115
    sky.Color thumbColor = _kThumbOffColor;
    sky.Color trackColor = _kTrackOffColor;
116
    if (value) {
117 118
      thumbColor = _thumbColor;
      trackColor = new sky.Color(_thumbColor.value & 0x80FFFFFF);
119 120 121
    }

    // Draw the track rrect
122 123 124
    sky.Paint paint = new sky.Paint()
      ..color = trackColor
      ..style = sky.PaintingStyle.fill;
125 126 127 128 129
    sky.Rect rect = new sky.Rect.fromLTWH(offset.dx,
        offset.dy + _kSwitchHeight / 2.0 - _kTrackHeight / 2.0, _kTrackWidth,
        _kTrackHeight);
    sky.RRect rrect = new sky.RRect()
      ..setRectXY(rect, _kTrackRadius, _kTrackRadius);
130 131
    canvas.drawRRect(rrect, paint);

132 133 134
    if (_radialReaction != null)
      _radialReaction.paint(canvas, offset);

135 136
    // Draw the raised thumb with a shadow
    paint.color = thumbColor;
137 138 139 140
    ShadowDrawLooperBuilder builder = new ShadowDrawLooperBuilder();
    for (BoxShadow boxShadow in shadows[1])
      builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blur);
    paint.drawLooper = builder.build();
141 142

    // The thumb contracts slightly during the animation
143
    double inset = 2.0 - (position - 0.5).abs() * 2.0;
144 145
    Point thumbPos = new Point(offset.dx +
            _kTrackRadius +
146
            position * (_kTrackWidth - _kTrackRadius * 2),
147
        offset.dy + _kSwitchHeight / 2.0);
148 149 150
    canvas.drawCircle(thumbPos, _kThumbRadius - inset, paint);
  }
}