Commit e4e6b01a authored by Adam Barth's avatar Adam Barth Committed by GitHub

Adapt FlexibleSpaceBar to iOS (#5037)

We should center the title of flexible space bars on iOS.

Related to #4962
parent d3cc5548
......@@ -4,6 +4,8 @@
import 'dart:ui' show VoidCallback;
import 'package:flutter/foundation.dart';
import 'animation.dart';
import 'curves.dart';
import 'listener_helpers.dart';
......@@ -388,7 +390,19 @@ class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<do
if (activeCurve == null)
return t;
if (t == 0.0 || t == 1.0) {
assert(activeCurve.transform(t).round() == t);
assert(() {
final double transformedValue = activeCurve.transform(t);
final double roundedTransformedValue = transformedValue.round().toDouble();
if (roundedTransformedValue != t) {
throw new FlutterError(
'Invalided curve endpoint at $t.\n'
'Curves must map 0.0 to near zero and 1.0 to near one but '
'${activeCurve.runtimeType} mapped $t to $transformedValue, which '
'is near $roundedTransformedValue.'
);
}
return true;
});
return t;
}
return activeCurve.transform(t);
......
......@@ -95,6 +95,8 @@ class Interval extends Curve {
assert(end >= 0.0);
assert(end <= 1.0);
assert(end >= start);
if (t == 0.0 || t == 1.0)
return t;
t = ((t - start) / (end - start)).clamp(0.0, 1.0);
if (t == 0.0 || t == 1.0)
return t;
......
......@@ -31,7 +31,12 @@ class FlexibleSpaceBar extends StatefulWidget {
///
/// Most commonly used in the [AppBar.flexibleSpace] field. Requires one of
/// its ancestors to be a [Scaffold] widget.
FlexibleSpaceBar({ Key key, this.title, this.background }) : super(key: key);
FlexibleSpaceBar({
Key key,
this.title,
this.background,
this.centerTitle
}) : super(key: key);
/// The primary contents of the flexible space bar when expanded.
///
......@@ -43,6 +48,11 @@ class FlexibleSpaceBar extends StatefulWidget {
/// Typically an [AssetImage] widget with [AssetImage.fit] set to [ImageFit.cover].
final Widget background;
/// Whether the title should be centered.
///
/// Defaults to being adapted to the current [TargetPlatform].
final bool centerTitle;
@override
_FlexibleSpaceBarState createState() => new _FlexibleSpaceBarState();
}
......@@ -63,6 +73,19 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
super.deactivate();
}
bool _getEffectiveCenterTitle(ThemeData theme) {
if (config.centerTitle != null)
return config.centerTitle;
assert(theme.platform != null);
switch (theme.platform) {
case TargetPlatform.android:
return false;
case TargetPlatform.iOS:
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasScaffold(context));
......@@ -101,6 +124,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
// title
if (config.title != null) {
final ThemeData theme = Theme.of(context);
final double fadeStart = (appBarHeight - toolBarHeight) / appBarHeight;
final double fadeEnd = (appBarHeight - toolBarHeight / 2.0) / appBarHeight;
final CurvedAnimation opacityCurve = new CurvedAnimation(
......@@ -109,7 +133,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
);
final int alpha = new Tween<double>(begin: 255.0, end: 0.0).evaluate(opacityCurve).toInt();
if (alpha > 0) {
TextStyle titleStyle = Theme.of(context).primaryTextTheme.title;
TextStyle titleStyle = theme.primaryTextTheme.title;
titleStyle = titleStyle.copyWith(
color: titleStyle.color.withAlpha(alpha)
);
......@@ -120,18 +144,20 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
parent: _scaffoldAnimation,
curve: new Interval(0.0, scaleAndAlignEnd)
);
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
final FractionalOffset titleAlignment = effectiveCenterTitle ? FractionalOffset.bottomCenter : FractionalOffset.bottomLeft;
children.add(new Padding(
padding: const EdgeInsets.only(left: 72.0, bottom: 14.0),
padding: new EdgeInsets.only(left: effectiveCenterTitle ? 0.0 : 72.0, bottom: 14.0),
child: new Align(
alignment: new Tween<FractionalOffset>(
begin: new FractionalOffset(0.0, yAlignStart),
end: new FractionalOffset(0.0, yAlignEnd)
).evaluate(scaleAndAlignCurve),
child: new ScaleTransition(
alignment: FractionalOffset.bottomLeft,
alignment: titleAlignment,
scale: new Tween<double>(begin: 1.5, end: 1.0).animate(scaleAndAlignCurve),
child: new Align(
alignment: new FractionalOffset(0.0, 1.0),
alignment: titleAlignment,
child: new DefaultTextStyle(style: titleStyle, child: config.title)
)
)
......
// Copyright 2016 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Flexible space back centers on iOS', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(platform: TargetPlatform.android),
home: new Scaffold(
appBar: new AppBar(
flexibleSpace: new FlexibleSpaceBar(
title: new Text('X')
)
)
)
)
);
Finder title = find.text('X');
Point center = tester.getCenter(title);
Size size = tester.getSize(title);
expect(center.x, lessThan(400 - size.width / 2.0));
// Clear the widget tree to avoid animating between Android and iOS.
await tester.pumpWidget(new Container(key: new UniqueKey()));
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(platform: TargetPlatform.iOS),
home: new Scaffold(
appBar: new AppBar(
flexibleSpace: new FlexibleSpaceBar(
title: new Text('X')
)
)
)
)
);
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.x, greaterThan(400 - size.width / 2.0));
expect(center.x, lessThan(400 + size.width / 2.0));
});
}
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