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

Add RTL support to Scaffold (#11833)

Fixes #11369
parent 7b549def
...@@ -37,12 +37,14 @@ enum _ScaffoldSlot { ...@@ -37,12 +37,14 @@ enum _ScaffoldSlot {
class _ScaffoldLayout extends MultiChildLayoutDelegate { class _ScaffoldLayout extends MultiChildLayoutDelegate {
_ScaffoldLayout({ _ScaffoldLayout({
this.padding, @required this.padding,
this.statusBarHeight, @required this.statusBarHeight,
@required this.textDirection,
}); });
final EdgeInsets padding; final EdgeInsets padding;
final double statusBarHeight; final double statusBarHeight;
final TextDirection textDirection;
@override @override
void performLayout(Size size) { void performLayout(Size size) {
...@@ -111,7 +113,16 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -111,7 +113,16 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
if (hasChild(_ScaffoldSlot.floatingActionButton)) { if (hasChild(_ScaffoldSlot.floatingActionButton)) {
final Size fabSize = layoutChild(_ScaffoldSlot.floatingActionButton, looseConstraints); final Size fabSize = layoutChild(_ScaffoldSlot.floatingActionButton, looseConstraints);
final double fabX = size.width - fabSize.width - _kFloatingActionButtonMargin; double fabX;
assert(textDirection != null);
switch (textDirection) {
case TextDirection.rtl:
fabX = _kFloatingActionButtonMargin;
break;
case TextDirection.ltr:
fabX = size.width - fabSize.width - _kFloatingActionButtonMargin;
break;
}
double fabY = contentBottom - fabSize.height - _kFloatingActionButtonMargin; double fabY = contentBottom - fabSize.height - _kFloatingActionButtonMargin;
if (snackBarSize.height > 0.0) if (snackBarSize.height > 0.0)
fabY = math.min(fabY, contentBottom - snackBarSize.height - fabSize.height - _kFloatingActionButtonMargin); fabY = math.min(fabY, contentBottom - snackBarSize.height - fabSize.height - _kFloatingActionButtonMargin);
...@@ -133,8 +144,9 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -133,8 +144,9 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
@override @override
bool shouldRelayout(_ScaffoldLayout oldDelegate) { bool shouldRelayout(_ScaffoldLayout oldDelegate) {
return padding != oldDelegate.padding return oldDelegate.padding != padding
|| statusBarHeight != oldDelegate.statusBarHeight; || oldDelegate.statusBarHeight != statusBarHeight
|| oldDelegate.textDirection != textDirection;
} }
} }
...@@ -868,6 +880,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin { ...@@ -868,6 +880,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
delegate: new _ScaffoldLayout( delegate: new _ScaffoldLayout(
padding: padding, padding: padding,
statusBarHeight: padding.top, statusBarHeight: padding.top,
textDirection: Directionality.of(context),
), ),
), ),
), ),
......
...@@ -11,9 +11,12 @@ import '../widgets/semantics_tester.dart'; ...@@ -11,9 +11,12 @@ import '../widgets/semantics_tester.dart';
void main() { void main() {
testWidgets('Scaffold control test', (WidgetTester tester) async { testWidgets('Scaffold control test', (WidgetTester tester) async {
final Key bodyKey = new UniqueKey(); final Key bodyKey = new UniqueKey();
await tester.pumpWidget(new Scaffold( await tester.pumpWidget(new Directionality(
appBar: new AppBar(title: const Text('Title')), textDirection: TextDirection.ltr,
body: new Container(key: bodyKey), child: new Scaffold(
appBar: new AppBar(title: const Text('Title')),
body: new Container(key: bodyKey),
),
)); ));
expect(tester.takeException(), isFlutterError); expect(tester.takeException(), isFlutterError);
...@@ -26,24 +29,30 @@ void main() { ...@@ -26,24 +29,30 @@ void main() {
RenderBox bodyBox = tester.renderObject(find.byKey(bodyKey)); RenderBox bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(const Size(800.0, 544.0))); expect(bodyBox.size, equals(const Size(800.0, 544.0)));
await tester.pumpWidget(new MediaQuery( await tester.pumpWidget(new Directionality(
data: const MediaQueryData(padding: const EdgeInsets.only(bottom: 100.0)), textDirection: TextDirection.ltr,
child: new Scaffold( child: new MediaQuery(
appBar: new AppBar(title: const Text('Title')), data: const MediaQueryData(padding: const EdgeInsets.only(bottom: 100.0)),
body: new Container(key: bodyKey) child: new Scaffold(
) appBar: new AppBar(title: const Text('Title')),
body: new Container(key: bodyKey),
),
),
)); ));
bodyBox = tester.renderObject(find.byKey(bodyKey)); bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(const Size(800.0, 444.0))); expect(bodyBox.size, equals(const Size(800.0, 444.0)));
await tester.pumpWidget(new MediaQuery( await tester.pumpWidget(new Directionality(
data: const MediaQueryData(padding: const EdgeInsets.only(bottom: 100.0)), textDirection: TextDirection.ltr,
child: new Scaffold( child: new MediaQuery(
appBar: new AppBar(title: const Text('Title')), data: const MediaQueryData(padding: const EdgeInsets.only(bottom: 100.0)),
body: new Container(key: bodyKey), child: new Scaffold(
resizeToAvoidBottomPadding: false appBar: new AppBar(title: const Text('Title')),
) body: new Container(key: bodyKey),
resizeToAvoidBottomPadding: false,
),
),
)); ));
bodyBox = tester.renderObject(find.byKey(bodyKey)); bodyBox = tester.renderObject(find.byKey(bodyKey));
...@@ -52,38 +61,47 @@ void main() { ...@@ -52,38 +61,47 @@ void main() {
testWidgets('Scaffold large bottom padding test', (WidgetTester tester) async { testWidgets('Scaffold large bottom padding test', (WidgetTester tester) async {
final Key bodyKey = new UniqueKey(); final Key bodyKey = new UniqueKey();
await tester.pumpWidget(new MediaQuery( await tester.pumpWidget(new Directionality(
data: const MediaQueryData( textDirection: TextDirection.ltr,
padding: const EdgeInsets.only(bottom: 700.0), child: new MediaQuery(
), data: const MediaQueryData(
child: new Scaffold( padding: const EdgeInsets.only(bottom: 700.0),
body: new Container(key: bodyKey), ),
child: new Scaffold(
body: new Container(key: bodyKey),
),
), ),
)); ));
final RenderBox bodyBox = tester.renderObject(find.byKey(bodyKey)); final RenderBox bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(const Size(800.0, 0.0))); expect(bodyBox.size, equals(const Size(800.0, 0.0)));
await tester.pumpWidget(new MediaQuery( await tester.pumpWidget(new Directionality(
data: const MediaQueryData( textDirection: TextDirection.ltr,
padding: const EdgeInsets.only(bottom: 500.0), child: new MediaQuery(
), data: const MediaQueryData(
child: new Scaffold( padding: const EdgeInsets.only(bottom: 500.0),
body: new Container(key: bodyKey), ),
child: new Scaffold(
body: new Container(key: bodyKey),
),
), ),
)); ));
expect(bodyBox.size, equals(const Size(800.0, 100.0))); expect(bodyBox.size, equals(const Size(800.0, 100.0)));
await tester.pumpWidget(new MediaQuery( await tester.pumpWidget(new Directionality(
data: const MediaQueryData( textDirection: TextDirection.ltr,
padding: const EdgeInsets.only(bottom: 580.0), child: new MediaQuery(
), data: const MediaQueryData(
child: new Scaffold( padding: const EdgeInsets.only(bottom: 580.0),
appBar: new AppBar( ),
title: const Text('Title'), child: new Scaffold(
appBar: new AppBar(
title: const Text('Title'),
),
body: new Container(key: bodyKey),
), ),
body: new Container(key: bodyKey),
), ),
)); ));
...@@ -95,8 +113,8 @@ void main() { ...@@ -95,8 +113,8 @@ void main() {
floatingActionButton: const FloatingActionButton( floatingActionButton: const FloatingActionButton(
key: const Key('one'), key: const Key('one'),
onPressed: null, onPressed: null,
child: const Text("1") child: const Text('1'),
) ),
))); )));
expect(tester.binding.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
...@@ -105,8 +123,8 @@ void main() { ...@@ -105,8 +123,8 @@ void main() {
floatingActionButton: const FloatingActionButton( floatingActionButton: const FloatingActionButton(
key: const Key('two'), key: const Key('two'),
onPressed: null, onPressed: null,
child: const Text("2") child: const Text('2'),
) ),
))); )));
expect(tester.binding.transientCallbackCount, greaterThan(0)); expect(tester.binding.transientCallbackCount, greaterThan(0));
...@@ -119,13 +137,40 @@ void main() { ...@@ -119,13 +137,40 @@ void main() {
floatingActionButton: const FloatingActionButton( floatingActionButton: const FloatingActionButton(
key: const Key('one'), key: const Key('one'),
onPressed: null, onPressed: null,
child: const Text("1") child: const Text('1'),
) ),
))); )));
expect(tester.binding.transientCallbackCount, greaterThan(0)); expect(tester.binding.transientCallbackCount, greaterThan(0));
}); });
testWidgets('Floating action button position', (WidgetTester tester) async {
Widget build(TextDirection textDirection) {
return new Directionality(
textDirection: textDirection,
child: new MediaQuery(
data: const MediaQueryData(
padding: const EdgeInsets.only(bottom: 200.0),
),
child: new Scaffold(
floatingActionButton: const FloatingActionButton(
onPressed: null,
child: const Text('1'),
),
),
),
);
}
await tester.pumpWidget(build(TextDirection.ltr));
expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(756.0, 356.0));
await tester.pumpWidget(build(TextDirection.rtl));
expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(44.0, 356.0));
});
testWidgets('Drawer scrolling', (WidgetTester tester) async { testWidgets('Drawer scrolling', (WidgetTester tester) async {
final Key drawerKey = new UniqueKey(); final Key drawerKey = new UniqueKey();
const double appBarHeight = 256.0; const double appBarHeight = 256.0;
...@@ -375,8 +420,9 @@ void main() { ...@@ -375,8 +420,9 @@ void main() {
group('body size', () { group('body size', () {
testWidgets('body size with container', (WidgetTester tester) async { testWidgets('body size with container', (WidgetTester tester) async {
final Key testKey = new UniqueKey(); final Key testKey = new UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new MediaQuery( textDirection: TextDirection.ltr,
child: new MediaQuery(
data: const MediaQueryData(), data: const MediaQueryData(),
child: new Scaffold( child: new Scaffold(
body: new Container( body: new Container(
...@@ -384,15 +430,16 @@ void main() { ...@@ -384,15 +430,16 @@ void main() {
), ),
), ),
), ),
); ));
expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 600.0)); expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 600.0));
expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0)); expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0));
}); });
testWidgets('body size with sized container', (WidgetTester tester) async { testWidgets('body size with sized container', (WidgetTester tester) async {
final Key testKey = new UniqueKey(); final Key testKey = new UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new MediaQuery( textDirection: TextDirection.ltr,
child: new MediaQuery(
data: const MediaQueryData(), data: const MediaQueryData(),
child: new Scaffold( child: new Scaffold(
body: new Container( body: new Container(
...@@ -401,15 +448,16 @@ void main() { ...@@ -401,15 +448,16 @@ void main() {
), ),
), ),
), ),
); ));
expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 100.0)); expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 100.0));
expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0)); expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0));
}); });
testWidgets('body size with centered container', (WidgetTester tester) async { testWidgets('body size with centered container', (WidgetTester tester) async {
final Key testKey = new UniqueKey(); final Key testKey = new UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new MediaQuery( textDirection: TextDirection.ltr,
child: new MediaQuery(
data: const MediaQueryData(), data: const MediaQueryData(),
child: new Scaffold( child: new Scaffold(
body: new Center( body: new Center(
...@@ -419,15 +467,16 @@ void main() { ...@@ -419,15 +467,16 @@ void main() {
), ),
), ),
), ),
); ));
expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 600.0)); expect(tester.element(find.byKey(testKey)).size, const Size(800.0, 600.0));
expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0)); expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0));
}); });
testWidgets('body size with button', (WidgetTester tester) async { testWidgets('body size with button', (WidgetTester tester) async {
final Key testKey = new UniqueKey(); final Key testKey = new UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new MediaQuery( textDirection: TextDirection.ltr,
child: new MediaQuery(
data: const MediaQueryData(), data: const MediaQueryData(),
child: new Scaffold( child: new Scaffold(
body: new FlatButton( body: new FlatButton(
...@@ -437,7 +486,7 @@ void main() { ...@@ -437,7 +486,7 @@ void main() {
), ),
), ),
), ),
); ));
expect(tester.element(find.byKey(testKey)).size, const Size(88.0, 36.0)); expect(tester.element(find.byKey(testKey)).size, const Size(88.0, 36.0));
expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.0)); expect(tester.renderObject<RenderBox>(find.byKey(testKey)).localToGlobal(Offset.zero), const Offset(0.0, 0.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