mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

This adds a smoke test for every single API example. It also fixes 17 tests that had bugs in them, or were otherwise broken, and even fixes one actual bug in the framework, and one limitation in the framework. The bug in the framework is that NetworkImage's _loadAsync method had await response.drain<List<int>>();, but if the response is null, it will throw a cryptic exception saying that Null can't be assigned to List<int>. The fix was just to use await response.drain<void>(); instead. The limitation is that RelativePositionedTransition takes an Animation<Rect> rect parameter, and if you want to use a RectTween with it, the value emitted there is Rect?, and one of the examples was just casting from Animation<Rect> to Animation<Rect?>, which is invalid, so I modified RelativePositionedTransition to take a Rect? and just use Rect.zero if the rect is null.
152 lines
4.9 KiB
Dart
152 lines
4.9 KiB
Dart
// 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.
|
|
|
|
// Template: dev/snippets/config/templates/stateless_widget_material.tmpl
|
|
//
|
|
// Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring
|
|
// of samples, and may be ignored if you are just exploring the sample.
|
|
|
|
// Flutter code sample for Curve2D
|
|
//
|
|
//***************************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ description ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
// This example shows how to use a [Curve2D] to modify the position of a widget
|
|
// so that it can follow an arbitrary path.
|
|
|
|
//* ▲▲▲▲▲▲▲▲ description ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//***************************************************************************
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
void main() => runApp(const MyApp());
|
|
|
|
/// This is the main application widget.
|
|
class MyApp extends StatelessWidget {
|
|
const MyApp({Key? key}) : super(key: key);
|
|
|
|
static const String _title = 'Flutter Code Sample';
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const MaterialApp(
|
|
title: _title,
|
|
home: MyStatelessWidget(),
|
|
);
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ code-preamble ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
// This is the path that the child will follow. It's a CatmullRomSpline so
|
|
// that the coordinates can be specified that it must pass through. If the
|
|
// tension is set to 1.0, it will linearly interpolate between those points,
|
|
// instead of interpolating smoothly.
|
|
final CatmullRomSpline path = CatmullRomSpline(
|
|
const <Offset>[
|
|
Offset(0.05, 0.75),
|
|
Offset(0.18, 0.23),
|
|
Offset(0.32, 0.04),
|
|
Offset(0.73, 0.5),
|
|
Offset(0.42, 0.74),
|
|
Offset(0.73, 0.01),
|
|
Offset(0.93, 0.93),
|
|
Offset(0.05, 0.75),
|
|
],
|
|
startHandle: const Offset(0.93, 0.93),
|
|
endHandle: const Offset(0.18, 0.23),
|
|
tension: 0.0,
|
|
);
|
|
|
|
class FollowCurve2D extends StatefulWidget {
|
|
const FollowCurve2D({
|
|
Key? key,
|
|
required this.path,
|
|
this.curve = Curves.easeInOut,
|
|
required this.child,
|
|
this.duration = const Duration(seconds: 1),
|
|
}) : super(key: key);
|
|
|
|
final Curve2D path;
|
|
final Curve curve;
|
|
final Duration duration;
|
|
final Widget child;
|
|
|
|
@override
|
|
State<FollowCurve2D> createState() => _FollowCurve2DState();
|
|
}
|
|
|
|
class _FollowCurve2DState extends State<FollowCurve2D>
|
|
with TickerProviderStateMixin {
|
|
// The animation controller for this animation.
|
|
late AnimationController controller;
|
|
// The animation that will be used to apply the widget's animation curve.
|
|
late Animation<double> animation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
controller = AnimationController(duration: widget.duration, vsync: this);
|
|
animation = CurvedAnimation(parent: controller, curve: widget.curve);
|
|
// Have the controller repeat indefinitely. If you want it to "bounce" back
|
|
// and forth, set the reverse parameter to true.
|
|
controller.repeat(reverse: false);
|
|
controller.addListener(() => setState(() {}));
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// Always have to dispose of animation controllers when done.
|
|
controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// Scale the path values to match the -1.0 to 1.0 domain of the Alignment widget.
|
|
final Offset position =
|
|
widget.path.transform(animation.value) * 2.0 - const Offset(1.0, 1.0);
|
|
return Align(
|
|
alignment: Alignment(position.dx, position.dy),
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|
|
|
|
//* ▲▲▲▲▲▲▲▲ code-preamble ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//*****************************************************************************
|
|
|
|
/// This is the stateless widget that the main application instantiates.
|
|
class MyStatelessWidget extends StatelessWidget {
|
|
const MyStatelessWidget({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
//********************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ code ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
color: Colors.white,
|
|
alignment: Alignment.center,
|
|
child: FollowCurve2D(
|
|
path: path,
|
|
curve: Curves.easeInOut,
|
|
duration: const Duration(seconds: 3),
|
|
child: CircleAvatar(
|
|
backgroundColor: Colors.yellow,
|
|
child: DefaultTextStyle(
|
|
style: Theme.of(context).textTheme.headline6!,
|
|
child: const Text('B'), // Buzz, buzz!
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
//* ▲▲▲▲▲▲▲▲ code ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//********************************************************************
|
|
|
|
}
|