Add ListenableBuilder, remove all AnimatedBuilders

This commit is contained in:
Shawn 2022-11-14 14:49:00 -07:00
parent af87d8e6db
commit 90902e27aa
15 changed files with 78 additions and 71 deletions

View File

@ -26,4 +26,5 @@ export 'package:wonders/ui/common/controls/buttons.dart';
export 'package:wonders/ui/common/controls/circle_buttons.dart'; export 'package:wonders/ui/common/controls/circle_buttons.dart';
export 'package:wonders/ui/common/controls/scroll_decorator.dart'; export 'package:wonders/ui/common/controls/scroll_decorator.dart';
export 'package:wonders/ui/common/controls/app_image.dart'; export 'package:wonders/ui/common/controls/app_image.dart';
export 'package:wonders/ui/common/listenable_builder.dart';
export 'package:flutter_animate/flutter_animate.dart'; export 'package:flutter_animate/flutter_animate.dart';

View File

@ -1,6 +1,4 @@
import 'dart:math'; import 'package:wonders/common_libs.dart';
import 'package:flutter/material.dart';
/// Easily add visual decorations to a scrolling widget based on the state of its controller. /// Easily add visual decorations to a scrolling widget based on the state of its controller.
class ScrollDecorator extends StatefulWidget { class ScrollDecorator extends StatefulWidget {
@ -125,8 +123,8 @@ class _ScrollDecoratorState extends State<ScrollDecorator> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
content = widget.builder(currentController); content = widget.builder(currentController);
return AnimatedBuilder( return ListenableBuilder(
animation: currentController, listenable: currentController,
builder: (_, __) { builder: (_, __) {
return Stack( return Stack(
children: [ children: [

View File

@ -8,8 +8,8 @@ class FadeColorTransition extends StatelessWidget {
final Color color; final Color color;
@override @override
Widget build(BuildContext context) => AnimatedBuilder( Widget build(BuildContext context) => ListenableBuilder(
animation: animation, listenable: animation,
builder: (_, __) => Container(color: color.withOpacity(animation.value)), builder: (_, __) => Container(color: color.withOpacity(animation.value)),
); );
} }

View File

@ -0,0 +1,10 @@
import 'package:flutter/cupertino.dart';
class ListenableBuilder extends AnimatedBuilder {
const ListenableBuilder({
Key? key,
required Listenable listenable,
required TransitionBuilder builder,
Widget? child,
}) : super(key: key, animation: listenable, builder: builder, child: child);
}

View File

@ -26,8 +26,8 @@ class _FullscreenUrlImgViewerState extends State<FullscreenUrlImgViewer> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget content = AnimatedBuilder( Widget content = ListenableBuilder(
animation: _isZoomed, listenable: _isZoomed,
builder: (_, __) { builder: (_, __) {
final bool enableSwipe = !_isZoomed.value && widget.urls.length > 1; final bool enableSwipe = !_isZoomed.value && widget.urls.length > 1;
return PageView.builder( return PageView.builder(

View File

@ -218,8 +218,8 @@ class _ArtifactScreenState extends State<ArtifactCarouselScreen> {
child: PageView.builder( child: PageView.builder(
controller: _controller, controller: _controller,
clipBehavior: Clip.none, clipBehavior: Clip.none,
itemBuilder: (context, index) => AnimatedBuilder( itemBuilder: (context, index) => ListenableBuilder(
animation: _controller, listenable: _controller,
builder: (_, __) { builder: (_, __) {
return _CarouselItem( return _CarouselItem(
index: index, index: index,

View File

@ -164,8 +164,8 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
), ),
/// Home Btn /// Home Btn
AnimatedBuilder( ListenableBuilder(
animation: _scroller, listenable: _scroller,
builder: (_, child) { builder: (_, child) {
return AnimatedOpacity( return AnimatedOpacity(
opacity: _scrollPos.value > 0 ? 0 : 1, opacity: _scrollPos.value > 0 ? 0 : 1,

View File

@ -94,8 +94,8 @@ class _AnimatedCircleWithTextState extends State<_AnimatedCircleWithText> with S
@override @override
Widget build(_) { Widget build(_) {
return AnimatedBuilder( return ListenableBuilder(
animation: _anim, listenable: _anim,
builder: (_, __) { builder: (_, __) {
var rot = _prevIndex > widget.index ? -pi : pi; var rot = _prevIndex > widget.index ? -pi : pi;
return Transform.rotate( return Transform.rotate(

View File

@ -46,8 +46,8 @@ class _TitleText extends StatelessWidget {
/// Wonder title text /// Wonder title text
Semantics( Semantics(
sortKey: OrdinalSortKey(0), sortKey: OrdinalSortKey(0),
child: AnimatedBuilder( child: ListenableBuilder(
animation: scroller, listenable: scroller,
builder: (_, __) { builder: (_, __) {
final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0; final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0;
bool enableHero = yPos > -100; bool enableHero = yPos > -100;
@ -68,8 +68,8 @@ class _TitleText extends StatelessWidget {
ExcludeSemantics( ExcludeSemantics(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md), padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
child: AnimatedBuilder( child: ListenableBuilder(
animation: scroller, listenable: scroller,
builder: (_, __) => CompassDivider( builder: (_, __) => CompassDivider(
isExpanded: scroller.position.pixels <= 0, isExpanded: scroller.position.pixels <= 0,
linesColor: data.type.fgColor, linesColor: data.type.fgColor,

View File

@ -54,8 +54,8 @@ class _BottomScrubber extends StatelessWidget {
), ),
/// Visible area, follows the position of scroller /// Visible area, follows the position of scroller
AnimatedBuilder( ListenableBuilder(
animation: scroller, listenable: scroller,
builder: (_, __) { builder: (_, __) {
ScrollPosition? pos; ScrollPosition? pos;
if (scroller.hasClients) pos = scroller.position; if (scroller.hasClients) pos = scroller.position;

View File

@ -61,8 +61,8 @@ class _ScalingViewportState extends State<_ScrollingViewport> {
// Dashed line with a year that changes as we scroll // Dashed line with a year that changes as we scroll
IgnorePointer( IgnorePointer(
ignoringSemantics: false, ignoringSemantics: false,
child: AnimatedBuilder( child: ListenableBuilder(
animation: controller.scroller, listenable: controller.scroller,
builder: (_, __) { builder: (_, __) {
return _DashedDividerWithYear(controller.calculateYearFromScrollPos()); return _DashedDividerWithYear(controller.calculateYearFromScrollPos());
}, },
@ -79,8 +79,8 @@ class _ScalingViewportState extends State<_ScrollingViewport> {
Widget buildTimelineSection(WonderData data) { Widget buildTimelineSection(WonderData data) {
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.circular(99), borderRadius: BorderRadius.circular(99),
child: AnimatedBuilder( child: ListenableBuilder(
animation: controller.scroller, listenable: controller.scroller,
builder: (_, __) => TimelineSection( builder: (_, __) => TimelineSection(
data, data,
controller.calculateYearFromScrollPos(), controller.calculateYearFromScrollPos(),
@ -128,8 +128,8 @@ class _ScalingViewportState extends State<_ScrollingViewport> {
), ),
/// Event Markers, rebuilds on scroll /// Event Markers, rebuilds on scroll
AnimatedBuilder( ListenableBuilder(
animation: controller.scroller, listenable: controller.scroller,
builder: (_, __) => _EventMarkers( builder: (_, __) => _EventMarkers(
controller.calculateYearFromScrollPos(), controller.calculateYearFromScrollPos(),
onEventChanged: _handleEventMarkerChanged, onEventChanged: _handleEventMarkerChanged,

View File

@ -29,47 +29,10 @@ class _EventsListState extends State<_EventsList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return LayoutBuilder( return widget.blurOnScroll ? _buildScrollingListWithBlur() : _buildScrollingList();
builder: (_, constraints) {
return Stack(
children: [
AnimatedBuilder(
animation: _scroller,
builder: (_, __) {
bool showBackdrop = widget.blurOnScroll;
double backdropAmt = 0;
if (_scroller.hasClients && showBackdrop) {
double blurStart = 50;
double maxScroll = 150;
double scrollPx = _scroller.position.pixels - blurStart;
// Normalize scroll position to a value between 0 and 1
backdropAmt = (_scroller.position.pixels - blurStart).clamp(0, maxScroll) / maxScroll;
// Disable backdrop once it is offscreen for an easy perf win
showBackdrop = (scrollPx <= 500);
}
// Container provides a underlay which gets darker as the background blurs
return Stack(
children: [
if (showBackdrop) ...[
AppBackdrop(
strength: backdropAmt,
child: IgnorePointer(
child: Container(
color: $styles.colors.black.withOpacity(backdropAmt * .6),
),
)),
],
_buildScrollingList()
],
);
},
),
],
);
},
);
} }
/// The actual content of the scrolling list
Widget _buildScrollingList() { Widget _buildScrollingList() {
Container buildHandle() { Container buildHandle() {
return Container( return Container(
@ -136,4 +99,40 @@ class _EventsListState extends State<_EventsList> {
], ],
); );
} }
/// Wraps the list in a scroll listener
Widget _buildScrollingListWithBlur() {
return ListenableBuilder(
listenable: _scroller,
child: _buildScrollingList(),
builder: (_, child) {
bool showBackdrop = true;
double backdropAmt = 0;
if (_scroller.hasClients && showBackdrop) {
double blurStart = 50;
double maxScroll = 150;
double scrollPx = _scroller.position.pixels - blurStart;
// Normalize scroll position to a value between 0 and 1
backdropAmt = (_scroller.position.pixels - blurStart).clamp(0, maxScroll) / maxScroll;
// Disable backdrop once it is offscreen for an easy perf win
showBackdrop = (scrollPx <= 500);
}
// Container provides a underlay which gets darker as the background blurs
return Stack(
children: [
if (showBackdrop) ...[
AppBackdrop(
strength: backdropAmt,
child: IgnorePointer(
child: Container(
color: $styles.colors.black.withOpacity(backdropAmt * .6),
),
)),
],
child!,
],
);
},
);
}
} }

View File

@ -6,7 +6,6 @@ import 'package:wonders/ui/common/app_icons.dart';
import 'package:wonders/ui/common/curved_clippers.dart'; import 'package:wonders/ui/common/curved_clippers.dart';
import 'package:wonders/ui/common/hidden_collectible.dart'; import 'package:wonders/ui/common/hidden_collectible.dart';
import 'package:wonders/ui/common/list_gradient.dart'; import 'package:wonders/ui/common/list_gradient.dart';
import 'package:wonders/ui/common/pop_router_on_over_scroll.dart';
import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/themed_text.dart';
import 'package:wonders/ui/common/timeline_event_card.dart'; import 'package:wonders/ui/common/timeline_event_card.dart';
import 'package:wonders/ui/common/wonders_timeline_builder.dart'; import 'package:wonders/ui/common/wonders_timeline_builder.dart';

View File

@ -89,8 +89,8 @@ class _AnimatedCloudsState extends State<AnimatedClouds> with SingleTickerProvid
return RepaintBoundary( return RepaintBoundary(
child: ClipRect( child: ClipRect(
child: OverflowBox( child: OverflowBox(
child: AnimatedBuilder( child: ListenableBuilder(
animation: _anim, listenable: _anim,
builder: (_, __) { builder: (_, __) {
// A stack with 2 sets of clouds, one set is moving out of view while the other moves in. // A stack with 2 sets of clouds, one set is moving out of view while the other moves in.
return Stack( return Stack(

View File

@ -12,8 +12,8 @@ class IllustrationTexture extends StatelessWidget {
final Animation<double>? opacity; final Animation<double>? opacity;
@override @override
Widget build(BuildContext context) => AnimatedBuilder( Widget build(BuildContext context) => ListenableBuilder(
animation: opacity ?? AlwaysStoppedAnimation(1), listenable: opacity ?? AlwaysStoppedAnimation(1),
builder: (context, child) => ClipRect( builder: (context, child) => ClipRect(
child: Transform.scale( child: Transform.scale(
scaleX: scale * (flipX ? -1 : 1), scaleX: scale * (flipX ? -1 : 1),