box_shadow.dart 4.3 KB
Newer Older
1 2 3 4 5
// 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:math' as math;
6
import 'dart:ui' as ui show Shadow, lerpDouble;
7 8 9 10

import 'package:flutter/foundation.dart';

import 'basic_types.dart';
11
import 'debug.dart';
12 13 14

/// A shadow cast by a box.
///
15 16
/// Inherits from [Shadow]
///
17
/// [BoxShadow] can cast non-rectangular shadows if the box is non-rectangular
18 19 20
/// (e.g., has a border radius or a circular shape).
///
/// This class is similar to CSS box-shadow.
21 22 23 24
///
/// See also:
///
///  * [Canvas.drawShadow], which is a more efficient way to draw shadows.
25
///  * [Shadow], which is the parent class that lacks [spreadRadius].
26
@immutable
27
class BoxShadow extends ui.Shadow {
28 29 30 31 32
  /// Creates a box shadow.
  ///
  /// By default, the shadow is solid black with zero [offset], [blurRadius],
  /// and [spreadRadius].
  const BoxShadow({
33 34 35
    Color color = const Color(0xFF000000),
    Offset offset = Offset.zero,
    double blurRadius = 0.0,
36
    this.spreadRadius = 0.0,
37
  }) : super(color: color, offset: offset, blurRadius: blurRadius);
38 39 40 41

  /// The amount the box should be inflated prior to applying the blur.
  final double spreadRadius;

42 43 44 45 46 47
  /// Create the [Paint] object that corresponds to this shadow description.
  ///
  /// The [offset] and [spreadRadius] are not represented in the [Paint] object.
  /// To honor those as well, the shape should be inflated by [spreadRadius] pixels
  /// in every direction and then translated by [offset] before being filled using
  /// this [Paint].
48
  @override
49
  Paint toPaint() {
50
    final Paint result = Paint()
51
      ..color = color
52
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, blurSigma);
53 54 55 56 57 58 59 60
    assert(() {
      if (debugDisableShadows)
        result.maskFilter = null;
      return true;
    }());
    return result;
  }

61
  /// Returns a new box shadow with its offset, blurRadius, and spreadRadius scaled by the given factor.
62
  @override
63
  BoxShadow scale(double factor) {
64
    return BoxShadow(
65 66 67
      color: color,
      offset: offset * factor,
      blurRadius: blurRadius * factor,
68
      spreadRadius: spreadRadius * factor,
69 70 71 72 73 74 75 76
    );
  }

  /// Linearly interpolate between two box shadows.
  ///
  /// If either box shadow is null, this function linearly interpolates from a
  /// a box shadow that matches the other box shadow in color but has a zero
  /// offset and a zero blurRadius.
77
  ///
78
  /// {@macro dart.ui.shadow.lerp}
79
  static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) {
80
    assert(t != null);
81 82 83 84 85 86
    if (a == null && b == null)
      return null;
    if (a == null)
      return b.scale(t);
    if (b == null)
      return a.scale(1.0 - t);
87
    return BoxShadow(
88 89 90
      color: Color.lerp(a.color, b.color, t),
      offset: Offset.lerp(a.offset, b.offset, t),
      blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t),
91
      spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t),
92 93 94 95 96 97
    );
  }

  /// Linearly interpolate between two lists of box shadows.
  ///
  /// If the lists differ in length, excess items are lerped with null.
98
  ///
99
  /// {@macro dart.ui.shadow.lerp}
100
  static List<BoxShadow> lerpList(List<BoxShadow> a, List<BoxShadow> b, double t) {
101
    assert(t != null);
102 103 104 105 106 107
    if (a == null && b == null)
      return null;
    a ??= <BoxShadow>[];
    b ??= <BoxShadow>[];
    final List<BoxShadow> result = <BoxShadow>[];
    final int commonLength = math.min(a.length, b.length);
108
    for (int i = 0; i < commonLength; i += 1)
109
      result.add(BoxShadow.lerp(a[i], b[i], t));
110
    for (int i = commonLength; i < a.length; i += 1)
111
      result.add(a[i].scale(1.0 - t));
112
    for (int i = commonLength; i < b.length; i += 1)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
      result.add(b[i].scale(t));
    return result;
  }

  @override
  bool operator ==(dynamic other) {
    if (identical(this, other))
      return true;
    if (runtimeType != other.runtimeType)
      return false;
    final BoxShadow typedOther = other;
    return color == typedOther.color &&
           offset == typedOther.offset &&
           blurRadius == typedOther.blurRadius &&
           spreadRadius == typedOther.spreadRadius;
  }

  @override
  int get hashCode => hashValues(color, offset, blurRadius, spreadRadius);

  @override
134
  String toString() => 'BoxShadow($color, $offset, ${debugFormatDouble(blurRadius)}, ${debugFormatDouble(spreadRadius)})';
135
}