switch.dart 4.81 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/painting/radial_reaction.dart';
9 10
import 'package:sky/painting/shadows.dart';
import 'package:sky/rendering/box.dart';
11
import 'package:sky/rendering/object.dart';
12 13 14
import 'package:sky/theme/shadows.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/theme.dart';
15
import 'package:sky/widgets/framework.dart';
16
import 'package:sky/rendering/toggleable.dart';
17

18
export 'package:sky/rendering/toggleable.dart' show ValueChanged;
19 20 21 22 23 24 25 26

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;
27 28 29 30
const double _kTrackWidth =
    _kSwitchWidth - (_kThumbRadius - _kTrackRadius) * 2.0;
const Duration _kCheckDuration = const Duration(milliseconds: 200);
const Size _kSwitchSize = const Size(_kSwitchWidth + 2.0, _kSwitchHeight + 2.0);
31
const double _kReactionRadius = _kSwitchWidth / 2.0;
32

33 34
class Switch extends LeafRenderObjectWrapper {
  Switch({ Key key, this.value, this.onChanged })
35 36 37 38 39
      : super(key: key);

  final bool value;
  final ValueChanged onChanged;

40
  _RenderSwitch get renderObject => super.renderObject;
41
  _RenderSwitch createNode() => new _RenderSwitch(
42 43 44 45
    value: value,
    thumbColor: null,
    onChanged: onChanged
  );
46

47
  void syncRenderObject(Switch old) {
48
    super.syncRenderObject(old);
49 50
    renderObject.value = value;
    renderObject.onChanged = onChanged;
51
    renderObject.thumbColor = Theme.of(this).accentColor;
52 53 54
  }
}

55
class _RenderSwitch extends RenderToggleable {
56 57 58 59 60
  _RenderSwitch({
    bool value,
    Color thumbColor: _kThumbOffColor,
    ValueChanged onChanged
  }) : _thumbColor = thumbColor,
61
        super(value: value, onChanged: onChanged, size: _kSwitchSize) {}
62 63

  Color _thumbColor;
64
  Color get thumbColor => _thumbColor;
65 66 67 68 69 70
  void set thumbColor(Color value) {
    if (value == _thumbColor) return;
    _thumbColor = value;
    markNeedsPaint();
  }

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
  RadialReaction _radialReaction;

  EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) {
    if (event is sky.PointerEvent) {
      if (event.type == 'pointerdown') {
        _showRadialReaction(entry.localPosition);
        return combineEventDispositions(EventDisposition.processed,
                                        super.handleEvent(event, entry));
      }
      if (event.type == 'pointerup') {
        _hideRadialReaction();
        return combineEventDispositions(EventDisposition.processed,
                                        super.handleEvent(event, entry));
      }
    }
    return super.handleEvent(event, entry);
  }

  void _showRadialReaction(Point startLocation) {
    if (_radialReaction != null)
      return;
    _radialReaction = new RadialReaction(
      center: new Point(_kSwitchSize.width / 2.0, _kSwitchSize.height / 2.0),
      radius: _kReactionRadius,
      startPosition: startLocation)
      ..addListener(markNeedsPaint)
      ..show();
  }

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

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

    // Draw the track rrect
    sky.Paint paint = new sky.Paint()..color = trackColor;
    paint.setStyle(sky.PaintingStyle.fill);
119 120 121 122 123
    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);
124 125
    canvas.drawRRect(rrect, paint);

126 127 128
    if (_radialReaction != null)
      _radialReaction.paint(canvas, offset);

129 130 131
    // Draw the raised thumb with a shadow
    paint.color = thumbColor;
    var builder = new ShadowDrawLooperBuilder();
132 133
    for (BoxShadow boxShadow in shadows[1]) builder.addShadow(
        boxShadow.offset, boxShadow.color, boxShadow.blur);
134 135 136
    paint.setDrawLooper(builder.build());

    // The thumb contracts slightly during the animation
137
    double inset = 2.0 - (position.value - 0.5).abs() * 2.0;
138 139
    Point thumbPos = new Point(offset.dx +
            _kTrackRadius +
140
            position.value * (_kTrackWidth - _kTrackRadius * 2),
141
        offset.dy + _kSwitchHeight / 2.0);
142 143 144
    canvas.drawCircle(thumbPos, _kThumbRadius - inset, paint);
  }
}