Unverified Commit 46c4fc11 authored by Hari07's avatar Hari07 Committed by GitHub

Animated fractionally sized box (#106795)

parent d7f7e9d9
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flutter code sample for AnimatedFractionallySizedBox
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool selected = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
selected = !selected;
});
},
child: Center(
child: SizedBox(
width: 200,
height: 200,
child: Container(
color: Colors.red,
child: AnimatedFractionallySizedBox(
widthFactor: selected ? 0.25 : 0.75,
heightFactor: selected ? 0.75 : 0.25,
alignment: selected ? Alignment.topLeft : Alignment.bottomRight,
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
child: Container(
color: Colors.blue,
child: const FlutterLogo(size: 75),
),
),
),
),
),
);
}
}
......@@ -2798,6 +2798,7 @@ class FractionallySizedBox extends SingleChildRenderObjectWidget {
assert(widthFactor == null || widthFactor >= 0.0),
assert(heightFactor == null || heightFactor >= 0.0);
/// {@template flutter.widgets.basic.fractionallySizedBox.widthFactor}
/// If non-null, the fraction of the incoming width given to the child.
///
/// If non-null, the child is given a tight width constraint that is the max
......@@ -2805,8 +2806,10 @@ class FractionallySizedBox extends SingleChildRenderObjectWidget {
///
/// If null, the incoming width constraints are passed to the child
/// unmodified.
/// {@endtemplate}
final double? widthFactor;
/// {@template flutter.widgets.basic.fractionallySizedBox.heightFactor}
/// If non-null, the fraction of the incoming height given to the child.
///
/// If non-null, the child is given a tight height constraint that is the max
......@@ -2814,8 +2817,10 @@ class FractionallySizedBox extends SingleChildRenderObjectWidget {
///
/// If null, the incoming height constraints are passed to the child
/// unmodified.
/// {@endtemplate}
final double? heightFactor;
/// {@template flutter.widgets.basic.fractionallySizedBox.alignment}
/// How to align the child.
///
/// The x and y values of the alignment control the horizontal and vertical
......@@ -2834,6 +2839,7 @@ class FractionallySizedBox extends SingleChildRenderObjectWidget {
/// specify an [AlignmentGeometry].
/// * [AlignmentDirectional], like [Alignment] for specifying alignments
/// relative to text direction.
/// {@endtemplate}
final AlignmentGeometry alignment;
@override
......
......@@ -2108,3 +2108,110 @@ class _AnimatedPhysicalModelState extends AnimatedWidgetBaseState<AnimatedPhysic
);
}
}
/// Animated version of [FractionallySizedBox] which automatically transitions the
/// child's size over a given duration whenever the given [widthFactor] or
/// [heightFactor] changes, as well as the position whenever the given [alignment]
/// changes.
///
/// For the animation, you can choose a [curve] as well as a [duration] and the
/// widget will automatically animate to the new target [widthFactor] or
/// [heightFactor].
///
/// {@tool dartpad}
/// The following example transitions an [AnimatedFractionallySizedBox]
/// between two states. It adjusts the [heightFactor], [widthFactor], and
/// [alignment] properties when tapped, using a [curve] of [Curves.fastOutSlowIn]
///
/// ** See code in examples/api/lib/widgets/implicit_animations/animated_fractionally_sized_box.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [AnimatedAlign], which is an implicitly animated version of [Align].
/// * [AnimatedContainer], which can transition more values at once.
/// * [AnimatedSlide], which can animate the translation of child by a given offset relative to its size.
/// * [AnimatedPositioned], which, as a child of a [Stack], automatically
/// transitions its child's position over a given duration whenever the given
/// position changes.
class AnimatedFractionallySizedBox extends ImplicitlyAnimatedWidget {
/// Creates a widget that sizes its child to a fraction of the total available
/// space that animates implicitly, and positions its child by an alignment
/// that animates implicitly.
///
/// The [curve] and [duration] argument must not be null
/// If non-null, the [widthFactor] and [heightFactor] arguments must be
/// non-negative.
const AnimatedFractionallySizedBox({
super.key,
this.alignment = Alignment.center,
this.child,
this.heightFactor,
this.widthFactor,
super.curve,
required super.duration,
super.onEnd,
}) : assert(alignment != null),
assert(widthFactor == null || widthFactor >= 0.0),
assert(heightFactor == null || heightFactor >= 0.0);
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.ProxyWidget.child}
final Widget? child;
/// {@macro flutter.widgets.basic.fractionallySizedBox.heightFactor}
final double? heightFactor;
/// {@macro flutter.widgets.basic.fractionallySizedBox.widthFactor}
final double? widthFactor;
/// {@macro flutter.widgets.basic.fractionallySizedBox.alignment}
final AlignmentGeometry alignment;
@override
AnimatedWidgetBaseState<AnimatedFractionallySizedBox> createState() => _AnimatedFractionallySizedBoxState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
properties.add(DiagnosticsProperty<double>('widthFactor', widthFactor));
properties.add(DiagnosticsProperty<double>('heightFactor', heightFactor));
}
}
class _AnimatedFractionallySizedBoxState extends AnimatedWidgetBaseState<AnimatedFractionallySizedBox> {
AlignmentGeometryTween? _alignment;
Tween<double>? _heightFactorTween;
Tween<double>? _widthFactorTween;
@override
void forEachTween(TweenVisitor<dynamic> visitor) {
_alignment = visitor(_alignment, widget.alignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
if(widget.heightFactor != null) {
_heightFactorTween = visitor(_heightFactorTween, widget.heightFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
}
if(widget.widthFactor != null) {
_widthFactorTween = visitor(_widthFactorTween, widget.widthFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
}
}
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
alignment: _alignment!.evaluate(animation)!,
heightFactor: _heightFactorTween?.evaluate(animation),
widthFactor: _widthFactorTween?.evaluate(animation),
child: widget.child,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description.add(DiagnosticsProperty<AlignmentGeometryTween>('alignment', _alignment, defaultValue: null));
description.add(DiagnosticsProperty<Tween<double>>('widthFactor', _widthFactorTween, defaultValue: null));
description.add(DiagnosticsProperty<Tween<double>>('heightFactor', _heightFactorTween, defaultValue: null));
}
}
......@@ -421,6 +421,27 @@ void main() {
expect(state.builds, equals(2));
});
testWidgets('AnimatedFractionallySizedBox onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap(
child: TestAnimatedWidget(
callback: mockOnEndFunction.handler,
switchKey: switchKey,
state: _TestAnimatedFractionallySizedBoxWidgetState(),
),
));
final Finder widgetFinder = find.byKey(switchKey);
await tester.tap(widgetFinder);
await tester.pump();
expect(mockOnEndFunction.called, 0);
await tester.pump(animationDuration);
expect(mockOnEndFunction.called, 0);
await tester.pump(additionalDelay);
expect(mockOnEndFunction.called, 1);
await tapTest2and3(tester, widgetFinder, mockOnEndFunction);
});
testWidgets('SliverAnimatedOpacity onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(TestAnimatedWidget(
......@@ -812,6 +833,19 @@ class _TestAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
}
}
class _TestAnimatedFractionallySizedBoxWidgetState extends _TestAnimatedWidgetState {
@override
Widget getAnimatedWidget() {
return AnimatedFractionallySizedBox(
duration: duration,
onEnd: widget.callback,
heightFactor: toggle ? 0.25 : 0.75,
widthFactor: toggle ? 0.25 : 0.75,
child: child,
);
}
}
class _TestSliverAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
@override
Widget getAnimatedWidget() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment