Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
34a85b39
Unverified
Commit
34a85b39
authored
Mar 09, 2019
by
xster
Committed by
GitHub
Mar 09, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix CupertinoTabView tree re-shape on view inset change (#29024)
parent
3af88c55
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
326 additions
and
45 deletions
+326
-45
tab_scaffold.dart
packages/flutter/lib/src/cupertino/tab_scaffold.dart
+7
-9
README.md
packages/flutter/test/cupertino/README.md
+4
-1
README.md
packages/flutter/test/cupertino/material/README.md
+4
-0
tab_scaffold_test.dart
...es/flutter/test/cupertino/material/tab_scaffold_test.dart
+241
-0
tab_scaffold_test.dart
packages/flutter/test/cupertino/tab_scaffold_test.dart
+70
-35
No files found.
packages/flutter/lib/src/cupertino/tab_scaffold.dart
View file @
34a85b39
...
...
@@ -194,14 +194,12 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
tabNumber:
widget
.
tabBar
.
items
.
length
,
tabBuilder:
widget
.
tabBuilder
,
);
EdgeInsets
contentPadding
=
EdgeInsets
.
zero
;
if
(
widget
.
resizeToAvoidBottomInset
)
{
// Remove the view inset and add it back as a padding in the inner content.
newMediaQuery
=
newMediaQuery
.
removeViewInsets
(
removeBottom:
true
);
content
=
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
existingMediaQuery
.
viewInsets
.
bottom
),
child:
content
,
);
contentPadding
=
EdgeInsets
.
only
(
bottom:
existingMediaQuery
.
viewInsets
.
bottom
);
}
if
(
widget
.
tabBar
!=
null
&&
...
...
@@ -219,10 +217,7 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
// translucent, let main content draw behind the tab bar but hint the
// obstructed area.
if
(
widget
.
tabBar
.
opaque
(
context
))
{
content
=
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
bottomPadding
),
child:
content
,
);
contentPadding
=
EdgeInsets
.
only
(
bottom:
bottomPadding
);
}
else
{
newMediaQuery
=
newMediaQuery
.
copyWith
(
padding:
newMediaQuery
.
padding
.
copyWith
(
...
...
@@ -234,7 +229,10 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
content
=
MediaQuery
(
data:
newMediaQuery
,
child:
Padding
(
padding:
contentPadding
,
child:
content
,
),
);
// The main content being at the bottom is added to the stack first.
...
...
packages/flutter/test/cupertino/README.md
View file @
34a85b39
...
...
@@ -3,5 +3,8 @@
Avoid importing the Material 'package:flutter/material.dart' in these tests as
we're trying to test the Cupertino package in standalone scenarios.
Some tests may be replicated in the Material tests when Material reuses
The 'material' subdirectory contains tests for cross-interactions of Material
Cupertino widgets in hybridized apps.
Some tests may also be replicated in the Material tests when Material reuses
Cupertino components on iOS such as page transitions and text editing.
packages/flutter/test/cupertino/material/README.md
0 → 100644
View file @
34a85b39
# Tests for the Cupertino+Material mixed usages
In this package, we test for interactions between Material and Cupertino
widgets.
packages/flutter/test/cupertino/material/tab_scaffold_test.dart
0 → 100644
View file @
34a85b39
// Copyright 2019 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/cupertino.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../../painting/mocks_for_image_cache.dart'
;
List
<
int
>
selectedTabs
;
void
main
(
)
{
setUp
(()
{
selectedTabs
=
<
int
>[];
});
testWidgets
(
'Last tab gets focus'
,
(
WidgetTester
tester
)
async
{
// 2 nodes for 2 tabs
final
List
<
FocusNode
>
focusNodes
=
<
FocusNode
>[
FocusNode
(),
FocusNode
()];
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
TextField
(
focusNode:
focusNodes
[
index
],
autofocus:
true
,
);
},
),
),
),
);
expect
(
focusNodes
[
0
].
hasFocus
,
isTrue
);
await
tester
.
tap
(
find
.
text
(
'Tab 2'
));
await
tester
.
pump
();
expect
(
focusNodes
[
0
].
hasFocus
,
isFalse
);
expect
(
focusNodes
[
1
].
hasFocus
,
isTrue
);
await
tester
.
tap
(
find
.
text
(
'Tab 1'
));
await
tester
.
pump
();
expect
(
focusNodes
[
0
].
hasFocus
,
isTrue
);
expect
(
focusNodes
[
1
].
hasFocus
,
isFalse
);
});
testWidgets
(
'Do not affect focus order in the route'
,
(
WidgetTester
tester
)
async
{
final
List
<
FocusNode
>
focusNodes
=
<
FocusNode
>[
FocusNode
(),
FocusNode
(),
FocusNode
(),
FocusNode
(),
];
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
Column
(
children:
<
Widget
>[
TextField
(
focusNode:
focusNodes
[
index
*
2
],
decoration:
const
InputDecoration
(
hintText:
'TextField 1'
,
),
),
TextField
(
focusNode:
focusNodes
[
index
*
2
+
1
],
decoration:
const
InputDecoration
(
hintText:
'TextField 2'
,
),
),
],
);
},
),
),
),
);
expect
(
focusNodes
.
any
((
FocusNode
node
)
=>
node
.
hasFocus
),
isFalse
,
);
await
tester
.
tap
(
find
.
widgetWithText
(
TextField
,
'TextField 2'
));
expect
(
focusNodes
.
indexOf
(
focusNodes
.
singleWhere
((
FocusNode
node
)
=>
node
.
hasFocus
)),
1
,
);
await
tester
.
tap
(
find
.
text
(
'Tab 2'
));
await
tester
.
pump
();
await
tester
.
tap
(
find
.
widgetWithText
(
TextField
,
'TextField 1'
));
expect
(
focusNodes
.
indexOf
(
focusNodes
.
singleWhere
((
FocusNode
node
)
=>
node
.
hasFocus
)),
2
,
);
await
tester
.
tap
(
find
.
text
(
'Tab 1'
));
await
tester
.
pump
();
// Upon going back to tab 1, the item it tab 1 that previously had the focus
// (TextField 2) gets it back.
expect
(
focusNodes
.
indexOf
(
focusNodes
.
singleWhere
((
FocusNode
node
)
=>
node
.
hasFocus
)),
1
,
);
});
testWidgets
(
'Tab bar respects themes'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
Placeholder
();
},
),
),
);
BoxDecoration
tabDecoration
=
tester
.
widget
<
DecoratedBox
>(
find
.
descendant
(
of:
find
.
byType
(
CupertinoTabBar
),
matching:
find
.
byType
(
DecoratedBox
),
)).
decoration
;
expect
(
tabDecoration
.
color
,
const
Color
(
0xCCF8F8F8
));
await
tester
.
tap
(
find
.
text
(
'Tab 2'
));
await
tester
.
pump
();
// Pump again but with dark theme.
await
tester
.
pumpWidget
(
CupertinoApp
(
theme:
const
CupertinoThemeData
(
brightness:
Brightness
.
dark
,
primaryColor:
CupertinoColors
.
destructiveRed
,
),
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
Placeholder
();
},
),
),
);
tabDecoration
=
tester
.
widget
<
DecoratedBox
>(
find
.
descendant
(
of:
find
.
byType
(
CupertinoTabBar
),
matching:
find
.
byType
(
DecoratedBox
),
)).
decoration
;
expect
(
tabDecoration
.
color
,
const
Color
(
0xB7212121
));
final
RichText
tab1
=
tester
.
widget
(
find
.
descendant
(
of:
find
.
text
(
'Tab 1'
),
matching:
find
.
byType
(
RichText
),
));
// Tab 2 should still be selected after changing theme.
expect
(
tab1
.
text
.
style
.
color
,
CupertinoColors
.
inactiveGray
);
final
RichText
tab2
=
tester
.
widget
(
find
.
descendant
(
of:
find
.
text
(
'Tab 2'
),
matching:
find
.
byType
(
RichText
),
));
expect
(
tab2
.
text
.
style
.
color
,
CupertinoColors
.
destructiveRed
);
});
testWidgets
(
'Does not lose state when focusing on text input'
,
(
WidgetTester
tester
)
async
{
// Regression testing for https://github.com/flutter/flutter/issues/28457.
await
tester
.
pumpWidget
(
MediaQuery
(
data:
const
MediaQueryData
(
viewInsets:
EdgeInsets
.
only
(
bottom:
0
),
),
child:
MaterialApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
TextField
();
},
),
),
),
),
);
final
EditableTextState
editableState
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
await
tester
.
enterText
(
find
.
byType
(
TextField
),
"don't lose me"
);
await
tester
.
pumpWidget
(
MediaQuery
(
data:
const
MediaQueryData
(
viewInsets:
EdgeInsets
.
only
(
bottom:
100
),
),
child:
MaterialApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
TextField
();
},
),
),
),
),
);
// The exact same state instance is still there.
expect
(
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
)),
editableState
);
expect
(
find
.
text
(
"don't lose me"
),
findsOneWidget
);
});
}
CupertinoTabBar
_buildTabBar
(
{
int
selectedTab
=
0
})
{
return
CupertinoTabBar
(
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
ImageIcon
(
TestImageProvider
(
24
,
24
)),
title:
Text
(
'Tab 1'
),
),
BottomNavigationBarItem
(
icon:
ImageIcon
(
TestImageProvider
(
24
,
24
)),
title:
Text
(
'Tab 2'
),
),
],
currentIndex:
selectedTab
,
onTap:
(
int
newTab
)
=>
selectedTabs
.
add
(
newTab
),
);
}
packages/flutter/test/cupertino/tab_scaffold_test.dart
View file @
34a85b39
...
...
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../painting/mocks_for_image_cache.dart'
;
...
...
@@ -111,18 +110,16 @@ void main() {
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
TextField
(
return
Cupertino
TextField
(
focusNode:
focusNodes
[
index
],
autofocus:
true
,
);
},
),
),
),
);
expect
(
focusNodes
[
0
].
hasFocus
,
isTrue
);
...
...
@@ -147,30 +144,24 @@ void main() {
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Material
(
child:
CupertinoTabScaffold
(
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
Column
(
children:
<
Widget
>[
TextField
(
Cupertino
TextField
(
focusNode:
focusNodes
[
index
*
2
],
decoration:
const
InputDecoration
(
hintText:
'TextField 1'
,
placeholder:
'TextField 1'
,
),
),
TextField
(
CupertinoTextField
(
focusNode:
focusNodes
[
index
*
2
+
1
],
decoration:
const
InputDecoration
(
hintText:
'TextField 2'
,
),
placeholder:
'TextField 2'
,
),
],
);
},
),
),
),
);
expect
(
...
...
@@ -178,7 +169,7 @@ void main() {
isFalse
,
);
await
tester
.
tap
(
find
.
widgetWithText
(
TextField
,
'TextField 2'
));
await
tester
.
tap
(
find
.
widgetWithText
(
Cupertino
TextField
,
'TextField 2'
));
expect
(
focusNodes
.
indexOf
(
focusNodes
.
singleWhere
((
FocusNode
node
)
=>
node
.
hasFocus
)),
...
...
@@ -188,7 +179,7 @@ void main() {
await
tester
.
tap
(
find
.
text
(
'Tab 2'
));
await
tester
.
pump
();
await
tester
.
tap
(
find
.
widgetWithText
(
TextField
,
'TextField 1'
));
await
tester
.
tap
(
find
.
widgetWithText
(
Cupertino
TextField
,
'TextField 1'
));
expect
(
focusNodes
.
indexOf
(
focusNodes
.
singleWhere
((
FocusNode
node
)
=>
node
.
hasFocus
)),
...
...
@@ -471,6 +462,50 @@ void main() {
expect
(
find
.
text
(
'Page 2'
,
skipOffstage:
false
),
findsNothing
);
expect
(
find
.
text
(
'Page 4'
,
skipOffstage:
false
),
findsNothing
);
});
testWidgets
(
'Does not lose state when focusing on text input'
,
(
WidgetTester
tester
)
async
{
// Regression testing for https://github.com/flutter/flutter/issues/28457.
await
tester
.
pumpWidget
(
MediaQuery
(
data:
const
MediaQueryData
(
viewInsets:
EdgeInsets
.
only
(
bottom:
0
),
),
child:
CupertinoApp
(
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
CupertinoTextField
();
},
),
),
),
);
final
EditableTextState
editableState
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
await
tester
.
enterText
(
find
.
byType
(
CupertinoTextField
),
"don't lose me"
);
await
tester
.
pumpWidget
(
MediaQuery
(
data:
const
MediaQueryData
(
viewInsets:
EdgeInsets
.
only
(
bottom:
100
),
),
child:
CupertinoApp
(
home:
CupertinoTabScaffold
(
tabBar:
_buildTabBar
(),
tabBuilder:
(
BuildContext
context
,
int
index
)
{
return
const
CupertinoTextField
();
},
),
),
),
);
// The exact same state instance is still there.
expect
(
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
)),
editableState
);
expect
(
find
.
text
(
"don't lose me"
),
findsOneWidget
);
});
}
CupertinoTabBar
_buildTabBar
(
{
int
selectedTab
=
0
})
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment