-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #64 from proformance/add-flexiblespace-animation-f…
…ade-transition
- Loading branch information
Showing
3 changed files
with
132 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import 'dart:math' as math; | ||
import 'dart:ui'; | ||
|
||
import 'package:black_hole_flutter/black_hole_flutter.dart'; | ||
import 'package:collection/collection.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/rendering.dart'; | ||
|
||
import 'app_bar.dart'; | ||
import 'state.dart'; | ||
|
||
class AnimatedFlexibleSpace extends MultiChildRenderObjectWidget { | ||
AnimatedFlexibleSpace(MorphingState state) | ||
: t = state.t, | ||
super( | ||
children: [_createChild(state.parent), _createChild(state.child)], | ||
); | ||
|
||
final double t; | ||
|
||
static Widget _createChild(EndState state) { | ||
final flexibleSpace = state.appBar.flexibleSpace; | ||
if (flexibleSpace == null) return const SizedBox(); | ||
|
||
return DefaultTextStyle.merge(child: flexibleSpace); | ||
} | ||
|
||
@override | ||
RenderObject createRenderObject(BuildContext context) => | ||
_AnimatedFlexibleSpaceLayout(t: t); | ||
|
||
@override | ||
void updateRenderObject( | ||
BuildContext context, | ||
covariant RenderObject renderObject, | ||
) => | ||
(renderObject as _AnimatedFlexibleSpaceLayout).t = t; | ||
} | ||
|
||
class _AnimatedFlexibleSpaceParentData | ||
extends ContainerBoxParentData<RenderBox> {} | ||
|
||
class _AnimatedFlexibleSpaceLayout | ||
extends AnimatedAppBarLayout<_AnimatedFlexibleSpaceParentData> { | ||
_AnimatedFlexibleSpaceLayout({super.t}); | ||
|
||
@override | ||
void setupParentData(RenderObject child) { | ||
if (child.parentData is! _AnimatedFlexibleSpaceParentData) { | ||
child.parentData = _AnimatedFlexibleSpaceParentData(); | ||
} | ||
} | ||
|
||
@override | ||
double computeMinIntrinsicWidth(double height) => | ||
children.map((c) => c.getMinIntrinsicWidth(height)).max.toDouble(); | ||
@override | ||
double computeMaxIntrinsicWidth(double height) => | ||
children.map((c) => c.getMaxIntrinsicWidth(height)).max.toDouble(); | ||
@override | ||
double computeMinIntrinsicHeight(double width) => | ||
children.map((c) => c.getMinIntrinsicHeight(width)).max.toDouble(); | ||
@override | ||
double computeMaxIntrinsicHeight(double width) => | ||
children.map((c) => c.getMaxIntrinsicHeight(width)).max.toDouble(); | ||
|
||
@override | ||
bool get alwaysNeedsCompositing => true; | ||
|
||
@override | ||
void performLayout() { | ||
assert(!sizedByParent); | ||
|
||
final parent = firstChild!; | ||
final child = parent.data.nextSibling!; | ||
|
||
parent.layout(constraints, parentUsesSize: true); | ||
child.layout(constraints, parentUsesSize: true); | ||
size = parent.size.coerceAtLeast(child.size); | ||
|
||
parent.data.offset = Offset(0, (size.height - parent.size.height) / 2); | ||
child.data.offset = Offset(0, (size.height - child.size.height) / 2); | ||
} | ||
|
||
@override | ||
void paint(PaintingContext context, Offset offset) { | ||
final parent = firstChild!; | ||
final child = parent.data.nextSibling!; | ||
|
||
context | ||
..pushOpacity( | ||
offset, | ||
math.max<double>(0, 1 - t).opacityToAlpha, | ||
(context, offset) => context.paintChild(parent, offset), | ||
) | ||
..pushOpacity( | ||
offset, | ||
math.max<double>(0, t).opacityToAlpha, | ||
(context, offset) => context.paintChild(child, offset), | ||
); | ||
} | ||
} | ||
|
||
extension _ParentData on RenderBox { | ||
_AnimatedFlexibleSpaceParentData get data => | ||
parentData! as _AnimatedFlexibleSpaceParentData; | ||
} |