decoration.dart 6.13 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 'package:flutter/foundation.dart';
6 7
import 'package:flutter/services.dart';

8
import 'basic_types.dart';
9
import 'edge_insets.dart';
10

11 12
export 'package:flutter/services.dart' show ImageConfiguration;

13
export 'basic_types.dart' show Point, Offset, Size;
14
export 'edge_insets.dart' show EdgeInsets;
15 16 17

// This group of classes is intended for painting in cartesian coordinates.

18 19 20 21 22 23 24 25 26
/// A description of a box decoration (a decoration applied to a [Rect]).
///
/// This class presents the abstract interface for all decorations.
/// See [BoxDecoration] for a concrete example.
///
/// To actually paint a [Decoration], use the [createBoxPainter]
/// method to obtain a [BoxPainter]. [Decoration] objects can be
/// shared between boxes; [BoxPainter] objects can cache resources to
/// make painting on a particular surface faster.
27
abstract class Decoration {
28 29
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
30
  const Decoration();
31 32 33 34 35 36

  /// In checked mode, throws an exception if the object is not in a
  /// valid configuration. Otherwise, returns true.
  ///
  /// This is intended to be used as follows:
  /// ```dart
37
  ///   assert(myDecoration.debugAssertIsValid());
38
  /// ```
39
  bool debugAssertIsValid() => true;
40 41 42 43 44 45

  /// Returns the insets to apply when using this decoration on a box
  /// that has contents, so that the contents do not overlap the edges
  /// of the decoration. For example, if the decoration draws a frame
  /// around its edge, the padding would return the distance by which
  /// to inset the children so as to not overlap the frame.
46
  EdgeInsets get padding => null;
47

48 49 50
  /// Whether this decoration is complex enough to benefit from caching its painting.
  bool get isComplex => false;

51
  /// Linearly interpolates from [a] to [this].
52
  Decoration lerpFrom(Decoration a, double t) => this;
53 54

  /// Linearly interpolates from [this] to [b].
55
  Decoration lerpTo(Decoration b, double t) => b;
56 57 58 59 60 61 62

  /// Linearly interpolates from [begin] to [end].
  ///
  /// This defers to [end]'s [lerpTo] function if [end] is not null,
  /// otherwise it uses [begin]'s [lerpFrom] function.
  static Decoration lerp(Decoration begin, Decoration end, double t) {
    if (end != null)
63
      return end.lerpFrom(begin, t);
64
    if (begin != null)
65
      return begin.lerpTo(end, t);
66 67 68 69 70 71 72 73
    return null;
  }

  /// Tests whether the given point, on a rectangle of a given size,
  /// would be considered to hit the decoration or not. For example,
  /// if the decoration only draws a circle, this function might
  /// return true if the point was inside the circle and false
  /// otherwise.
74
  bool hitTest(Size size, Point position) => true;
75 76

  /// Returns a [BoxPainter] that will paint this decoration.
77 78 79 80 81
  ///
  /// The `onChanged` argument configures [BoxPainter.onChanged]. It can be
  /// omitted if there is no chance that the painter will change (for example,
  /// if it is a [BoxDecoration] with definitely no [BackgroundImage]).
  BoxPainter createBoxPainter([VoidCallback onChanged]);
82

83 84 85 86 87 88 89 90
  /// Returns a string representation of this object.
  ///
  /// Every line of the output should be prefixed by `prefix`.
  ///
  /// If `indentPrefix` is non-null, then the description can be further split
  /// into sublines, and each subline should be prefixed with `indentPrefix`
  /// (rather that `prefix`). This is used, for example, by [BoxDecoration] for
  /// the otherwise quite verbose [BoxShadow] descriptions.
91
  @override
92
  String toString([String prefix = '', String indentPrefix ]) => '$prefix$runtimeType';
93 94
}

95 96 97 98
/// A stateful class that can paint a particular [Decoration].
///
/// [BoxPainter] objects can cache resources so that they can be used
/// multiple times.
99 100 101 102 103 104 105 106
///
/// Some resources used by [BoxPainter] may load asynchronously. When this
/// happens, the [onChanged] callback will be invoked. To stop this callback
/// from being called after the painter has been discarded, call [dispose].
abstract class BoxPainter {
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
  BoxPainter([this._onChanged]);
107 108

  /// Paints the [Decoration] for which this object was created on the
109 110 111 112
  /// given canvas using the given configuration.
  ///
  /// The [ImageConfiguration] object passed as the third argument must, at a
  /// minimum, have a non-null [Size].
113
  ///
114 115 116 117 118
  /// If this object caches resources for painting (e.g. [Paint] objects), the
  /// cache may be flushed when [paint] is called with a new configuration. For
  /// this reason, it may be more efficient to call
  /// [Decoration.createBoxPainter] for each different rectangle that is being
  /// painted in a particular frame.
119 120 121 122 123 124 125
  ///
  /// For example, if a decoration's owner wants to paint a particular
  /// decoration once for its whole size, and once just in the bottom
  /// right, it might get two [BoxPainter] instances, one for each.
  /// However, when its size changes, it could continue using those
  /// same instances, since the previous resources would no longer be
  /// relevant and thus losing them would not be an issue.
126 127 128 129
  ///
  /// Implementations should paint their decorations on the canvas in a
  /// rectangle whose top left corner is at the given `offset` and whose size is
  /// given by `configuration.size`.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration);

  /// Callback that is invoked if an asynchronously-loading resource used by the
  /// decoration finishes loading. For example, an image. When this is invoked,
  /// the [paint] method should be called again.
  ///
  /// Resources might not start to load until after [paint] has been called,
  /// because they might depend on the configuration.
  VoidCallback get onChanged => _onChanged;
  VoidCallback _onChanged;

  /// Discard any resources being held by the object. This also guarantees that
  /// the [onChanged] callback will not be called again.
  @mustCallSuper
  void dispose() {
    _onChanged = null;
  }
147
}