sliver_persistent_header.dart 8.96 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4 5 6 7 8 9
// 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 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';

import 'framework.dart';

10
abstract class SliverPersistentHeaderDelegate {
Ian Hickson's avatar
Ian Hickson committed
11 12
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
13
  const SliverPersistentHeaderDelegate();
Ian Hickson's avatar
Ian Hickson committed
14

15 16 17
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent);

  double get minExtent;
Ian Hickson's avatar
Ian Hickson committed
18 19 20

  double get maxExtent;

21
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate);
22 23 24 25 26 27 28

  /// Specifies how floating headers should animate in and out of view.
  ///
  /// If the value of this property is null, then floating headers will
  /// not animate into place.
  @protected
  FloatingHeaderSnapConfiguration get snapConfiguration => null;
Ian Hickson's avatar
Ian Hickson committed
29 30
}

31 32
class SliverPersistentHeader extends StatelessWidget {
  SliverPersistentHeader({
Ian Hickson's avatar
Ian Hickson committed
33 34 35 36 37 38 39 40 41 42
    Key key,
    @required this.delegate,
    this.pinned: false,
    this.floating: false,
  }) : super(key: key) {
    assert(delegate != null);
    assert(pinned != null);
    assert(floating != null);
  }

43
  final SliverPersistentHeaderDelegate delegate;
Ian Hickson's avatar
Ian Hickson committed
44 45 46 47 48 49 50

  final bool pinned;

  final bool floating;

  @override
  Widget build(BuildContext context) {
51 52
    if (floating && pinned)
      return new _SliverFloatingPinnedPersistentHeader(delegate: delegate);
Ian Hickson's avatar
Ian Hickson committed
53
    if (pinned)
54
      return new _SliverPinnedPersistentHeader(delegate: delegate);
Ian Hickson's avatar
Ian Hickson committed
55
    if (floating)
56 57
      return new _SliverFloatingPersistentHeader(delegate: delegate);
    return new _SliverScrollingPersistentHeader(delegate: delegate);
Ian Hickson's avatar
Ian Hickson committed
58 59 60 61 62 63
  }

  @override
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    description.add('delegate: $delegate');
64
    final List<String> flags = <String>[];
Ian Hickson's avatar
Ian Hickson committed
65 66 67 68 69 70 71 72 73 74
    if (pinned)
      flags.add('pinned');
    if (floating)
      flags.add('floating');
    if (flags.isEmpty)
      flags.add('normal');
    description.add('mode: ${flags.join(", ")}');
  }
}

75 76
class _SliverPersistentHeaderElement extends RenderObjectElement {
  _SliverPersistentHeaderElement(_SliverPersistentHeaderRenderObjectWidget widget) : super(widget);
Ian Hickson's avatar
Ian Hickson committed
77 78

  @override
79
  _SliverPersistentHeaderRenderObjectWidget get widget => super.widget;
Ian Hickson's avatar
Ian Hickson committed
80 81

  @override
82
  _RenderSliverPersistentHeaderForWidgetsMixin get renderObject => super.renderObject;
Ian Hickson's avatar
Ian Hickson committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96

  @override
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    renderObject._element = this;
  }

  @override
  void unmount() {
    super.unmount();
    renderObject._element = null;
  }

  @override
97 98
  void update(_SliverPersistentHeaderRenderObjectWidget newWidget) {
    final _SliverPersistentHeaderRenderObjectWidget oldWidget = widget;
Ian Hickson's avatar
Ian Hickson committed
99
    super.update(newWidget);
100 101
    final SliverPersistentHeaderDelegate newDelegate = newWidget.delegate;
    final SliverPersistentHeaderDelegate oldDelegate = oldWidget.delegate;
Ian Hickson's avatar
Ian Hickson committed
102 103 104 105 106 107 108 109 110 111 112 113
    if (newDelegate != oldDelegate &&
        (newDelegate.runtimeType != oldDelegate.runtimeType || newDelegate.shouldRebuild(oldDelegate)))
      renderObject.triggerRebuild();
  }

  @override
  void performRebuild() {
    renderObject.triggerRebuild();
  }

  Element child;

114
  void _build(double shrinkOffset, bool overlapsContent) {
Ian Hickson's avatar
Ian Hickson committed
115
    owner.buildScope(this, () {
116
      child = updateChild(child, widget.delegate.build(this, shrinkOffset, overlapsContent), null);
Ian Hickson's avatar
Ian Hickson committed
117 118 119 120 121 122 123 124 125 126
    });
  }

  @override
  void forgetChild(Element child) {
    assert(child == this.child);
    this.child = null;
  }

  @override
127
  void insertChildRenderObject(covariant RenderObject child, Null slot) {
Ian Hickson's avatar
Ian Hickson committed
128 129 130 131
    renderObject.child = child;
  }

  @override
132
  void moveChildRenderObject(covariant RenderObject child, Null slot) {
Ian Hickson's avatar
Ian Hickson committed
133 134 135 136
    assert(false);
  }

  @override
137
  void removeChildRenderObject(covariant RenderObject child) {
Ian Hickson's avatar
Ian Hickson committed
138 139 140 141 142 143 144 145 146
    renderObject.child = null;
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    visitor(child);
  }
}

147 148
abstract class _SliverPersistentHeaderRenderObjectWidget extends RenderObjectWidget {
  _SliverPersistentHeaderRenderObjectWidget({
Ian Hickson's avatar
Ian Hickson committed
149 150 151 152 153 154
    Key key,
    @required this.delegate,
  }) : super(key: key) {
    assert(delegate != null);
  }

155
  final SliverPersistentHeaderDelegate delegate;
Ian Hickson's avatar
Ian Hickson committed
156 157

  @override
158
  _SliverPersistentHeaderElement createElement() => new _SliverPersistentHeaderElement(this);
Ian Hickson's avatar
Ian Hickson committed
159 160

  @override
161
  _RenderSliverPersistentHeaderForWidgetsMixin createRenderObject(BuildContext context);
Ian Hickson's avatar
Ian Hickson committed
162 163 164 165 166 167 168 169

  @override
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    description.add('delegate: $delegate');
  }
}

170 171
abstract class _RenderSliverPersistentHeaderForWidgetsMixin implements RenderSliverPersistentHeader {
  _SliverPersistentHeaderElement _element;
Ian Hickson's avatar
Ian Hickson committed
172

173 174 175
  @override
  double get minExtent => _element.widget.delegate.minExtent;

Ian Hickson's avatar
Ian Hickson committed
176 177 178 179
  @override
  double get maxExtent => _element.widget.delegate.maxExtent;

  @override
180
  void updateChild(double shrinkOffset, bool overlapsContent) {
Ian Hickson's avatar
Ian Hickson committed
181
    assert(_element != null);
182
    _element._build(shrinkOffset, overlapsContent);
Ian Hickson's avatar
Ian Hickson committed
183 184 185 186
  }

  @protected
  void triggerRebuild() {
187
    markNeedsLayout();
Ian Hickson's avatar
Ian Hickson committed
188 189 190
  }
}

191 192
class _SliverScrollingPersistentHeader extends _SliverPersistentHeaderRenderObjectWidget {
  _SliverScrollingPersistentHeader({
Ian Hickson's avatar
Ian Hickson committed
193
    Key key,
194
    @required SliverPersistentHeaderDelegate delegate,
Ian Hickson's avatar
Ian Hickson committed
195 196 197
  }) : super(key: key, delegate: delegate);

  @override
198 199
  _RenderSliverPersistentHeaderForWidgetsMixin createRenderObject(BuildContext context) {
    return new _RenderSliverScrollingPersistentHeaderForWidgets();
Ian Hickson's avatar
Ian Hickson committed
200 201 202 203
  }
}

// This class exists to work around https://github.com/dart-lang/sdk/issues/15101
204
abstract class _RenderSliverScrollingPersistentHeader extends RenderSliverScrollingPersistentHeader { }
Ian Hickson's avatar
Ian Hickson committed
205

206 207
class _RenderSliverScrollingPersistentHeaderForWidgets extends _RenderSliverScrollingPersistentHeader
  with _RenderSliverPersistentHeaderForWidgetsMixin { }
Ian Hickson's avatar
Ian Hickson committed
208

209 210
class _SliverPinnedPersistentHeader extends _SliverPersistentHeaderRenderObjectWidget {
  _SliverPinnedPersistentHeader({
Ian Hickson's avatar
Ian Hickson committed
211
    Key key,
212
    @required SliverPersistentHeaderDelegate delegate,
Ian Hickson's avatar
Ian Hickson committed
213 214 215
  }) : super(key: key, delegate: delegate);

  @override
216 217
  _RenderSliverPersistentHeaderForWidgetsMixin createRenderObject(BuildContext context) {
    return new _RenderSliverPinnedPersistentHeaderForWidgets();
Ian Hickson's avatar
Ian Hickson committed
218 219 220 221
  }
}

// This class exists to work around https://github.com/dart-lang/sdk/issues/15101
222
abstract class _RenderSliverPinnedPersistentHeader extends RenderSliverPinnedPersistentHeader { }
Ian Hickson's avatar
Ian Hickson committed
223

224
class _RenderSliverPinnedPersistentHeaderForWidgets extends _RenderSliverPinnedPersistentHeader with _RenderSliverPersistentHeaderForWidgetsMixin { }
Ian Hickson's avatar
Ian Hickson committed
225

226 227
class _SliverFloatingPersistentHeader extends _SliverPersistentHeaderRenderObjectWidget {
  _SliverFloatingPersistentHeader({
Ian Hickson's avatar
Ian Hickson committed
228
    Key key,
229
    @required SliverPersistentHeaderDelegate delegate,
Ian Hickson's avatar
Ian Hickson committed
230 231 232
  }) : super(key: key, delegate: delegate);

  @override
233
  _RenderSliverPersistentHeaderForWidgetsMixin createRenderObject(BuildContext context) {
234 235 236 237 238 239 240 241 242
    // Not passing this snapConfiguration as a constructor parameter to avoid the
    // additional layers added due to https://github.com/dart-lang/sdk/issues/15101
    return new _RenderSliverFloatingPersistentHeaderForWidgets()
      ..snapConfiguration = delegate.snapConfiguration;
  }

  @override
  void updateRenderObject(BuildContext context, _RenderSliverFloatingPersistentHeaderForWidgets renderObject) {
    renderObject.snapConfiguration = delegate.snapConfiguration;
Ian Hickson's avatar
Ian Hickson committed
243 244 245
  }
}

246 247 248 249 250 251 252 253 254 255 256 257 258
// This class exists to work around https://github.com/dart-lang/sdk/issues/15101
abstract class _RenderSliverFloatingPinnedPersistentHeader extends RenderSliverFloatingPinnedPersistentHeader { }

class _RenderSliverFloatingPinnedPersistentHeaderForWidgets extends _RenderSliverFloatingPinnedPersistentHeader with _RenderSliverPersistentHeaderForWidgetsMixin { }

class _SliverFloatingPinnedPersistentHeader extends _SliverPersistentHeaderRenderObjectWidget {
  _SliverFloatingPinnedPersistentHeader({
    Key key,
    @required SliverPersistentHeaderDelegate delegate,
  }) : super(key: key, delegate: delegate);

  @override
  _RenderSliverPersistentHeaderForWidgetsMixin createRenderObject(BuildContext context) {
259 260 261 262 263 264 265 266 267
    // Not passing this snapConfiguration as a constructor parameter to avoid the
    // additional layers added due to https://github.com/dart-lang/sdk/issues/15101
    return new _RenderSliverFloatingPinnedPersistentHeaderForWidgets()
      ..snapConfiguration = delegate.snapConfiguration;
  }

  @override
  void updateRenderObject(BuildContext context, _RenderSliverFloatingPinnedPersistentHeaderForWidgets renderObject) {
    renderObject.snapConfiguration = delegate.snapConfiguration;
268 269 270
  }
}

Ian Hickson's avatar
Ian Hickson committed
271
// This class exists to work around https://github.com/dart-lang/sdk/issues/15101
272
abstract class _RenderSliverFloatingPersistentHeader extends RenderSliverFloatingPersistentHeader { }
Ian Hickson's avatar
Ian Hickson committed
273

274
class _RenderSliverFloatingPersistentHeaderForWidgets extends _RenderSliverFloatingPersistentHeader with _RenderSliverPersistentHeaderForWidgetsMixin { }