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
b23aed7a
Commit
b23aed7a
authored
Jan 09, 2017
by
Hans Muller
Committed by
GitHub
Jan 09, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New Tabs API (#7387)
parent
e82b18d4
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1361 additions
and
1407 deletions
+1361
-1407
main.dart
dev/benchmarks/complex_layout/lib/main.dart
+4
-4
material_arc.dart
dev/manual_tests/material_arc.dart
+16
-16
colors_demo.dart
examples/flutter_gallery/lib/demo/colors_demo.dart
+9
-19
page_selector_demo.dart
examples/flutter_gallery/lib/demo/page_selector_demo.dart
+68
-63
scrollable_tabs_demo.dart
examples/flutter_gallery/lib/demo/scrollable_tabs_demo.dart
+82
-76
tabs_demo.dart
examples/flutter_gallery/lib/demo/tabs_demo.dart
+11
-20
tabs_fab_demo.dart
examples/flutter_gallery/lib/demo/tabs_fab_demo.dart
+50
-40
demo.dart
examples/flutter_gallery/lib/gallery/demo.dart
+16
-22
stock_home.dart
examples/stocks/lib/stock_home.dart
+8
-8
material.dart
packages/flutter/lib/material.dart
+1
-0
constants.dart
packages/flutter/lib/src/material/constants.dart
+3
-0
tab_controller.dart
packages/flutter/lib/src/material/tab_controller.dart
+202
-0
tabs.dart
packages/flutter/lib/src/material/tabs.dart
+612
-1057
tabs_test.dart
packages/flutter/test/material/tabs_test.dart
+279
-82
No files found.
dev/benchmarks/complex_layout/lib/main.dart
View file @
b23aed7a
...
@@ -470,12 +470,12 @@ class ItemGalleryBox extends StatelessWidget {
...
@@ -470,12 +470,12 @@ class ItemGalleryBox extends StatelessWidget {
return
new
SizedBox
(
return
new
SizedBox
(
height:
200.0
,
height:
200.0
,
child:
new
TabBarSelection
<
String
>
(
child:
new
DefaultTabController
(
values:
tabNames
,
length:
tabNames
.
length
,
child:
new
Column
(
child:
new
Column
(
children:
<
Widget
>[
children:
<
Widget
>[
new
Expanded
(
new
Expanded
(
child:
new
TabBarView
<
String
>
(
child:
new
TabBarView
(
children:
tabNames
.
map
((
String
tabName
)
{
children:
tabNames
.
map
((
String
tabName
)
{
return
new
Container
(
return
new
Container
(
key:
new
Key
(
'Tab
$index
-
$tabName
'
),
key:
new
Key
(
'Tab
$index
-
$tabName
'
),
...
@@ -521,7 +521,7 @@ class ItemGalleryBox extends StatelessWidget {
...
@@ -521,7 +521,7 @@ class ItemGalleryBox extends StatelessWidget {
)
)
),
),
new
Container
(
new
Container
(
child:
new
TabPageSelector
<
String
>
()
child:
new
TabPageSelector
()
)
)
]
]
)
)
...
...
dev/manual_tests/material_arc.dart
View file @
b23aed7a
...
@@ -412,8 +412,6 @@ class AnimationDemo extends StatefulWidget {
...
@@ -412,8 +412,6 @@ class AnimationDemo extends StatefulWidget {
}
}
class
_AnimationDemoState
extends
State
<
AnimationDemo
>
with
TickerProviderStateMixin
{
class
_AnimationDemoState
extends
State
<
AnimationDemo
>
with
TickerProviderStateMixin
{
static
final
GlobalKey
<
TabBarSelectionState
<
_ArcDemo
>>
_tabsKey
=
new
GlobalKey
<
TabBarSelectionState
<
_ArcDemo
>>();
List
<
_ArcDemo
>
_allDemos
;
List
<
_ArcDemo
>
_allDemos
;
@override
@override
...
@@ -435,8 +433,7 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
...
@@ -435,8 +433,7 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
];
];
}
}
Future
<
Null
>
_play
()
async
{
Future
<
Null
>
_play
(
_ArcDemo
demo
)
async
{
_ArcDemo
demo
=
_tabsKey
.
currentState
.
value
;
await
demo
.
controller
.
forward
();
await
demo
.
controller
.
forward
();
if
(
demo
.
key
.
currentState
!=
null
&&
demo
.
key
.
currentState
.
mounted
)
if
(
demo
.
key
.
currentState
!=
null
&&
demo
.
key
.
currentState
.
mounted
)
demo
.
controller
.
reverse
();
demo
.
controller
.
reverse
();
...
@@ -444,23 +441,26 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
...
@@ -444,23 +441,26 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
_ArcDemo
>(
return
new
DefaultTabController
(
key:
_tabsKey
,
length:
_allDemos
.
length
,
values:
_allDemos
,
child:
new
Scaffold
(
child:
new
Scaffold
(
appBar:
new
AppBar
(
appBar:
new
AppBar
(
title:
new
Text
(
'Animation'
),
title:
new
Text
(
'Animation'
),
bottom:
new
TabBar
<
_ArcDemo
>(
bottom:
new
TabBar
(
labels:
new
Map
<
_ArcDemo
,
TabLabel
>.
fromIterable
(
_allDemos
,
value:
(
_ArcDemo
demo
)
{
tabs:
_allDemos
.
map
((
_ArcDemo
demo
)
=>
new
Tab
(
text:
demo
.
title
)).
toList
(),
return
new
TabLabel
(
text:
demo
.
title
);
),
})
)
),
),
floatingActionButton:
new
FloatingActionButton
(
floatingActionButton:
new
Builder
(
onPressed:
_play
,
builder:
(
BuildContext
context
)
{
child:
new
Icon
(
Icons
.
refresh
)
return
new
FloatingActionButton
(
child:
new
Icon
(
Icons
.
refresh
),
onPressed:
()
{
_play
(
_allDemos
[
DefaultTabController
.
of
(
context
).
index
]);
},
);
},
),
),
body:
new
TabBarView
<
_ArcDemo
>
(
body:
new
TabBarView
(
children:
_allDemos
.
map
((
_ArcDemo
demo
)
=>
demo
.
builder
(
demo
)).
toList
()
children:
_allDemos
.
map
((
_ArcDemo
demo
)
=>
demo
.
builder
(
demo
)).
toList
()
)
)
)
)
...
...
examples/flutter_gallery/lib/demo/colors_demo.dart
View file @
b23aed7a
...
@@ -107,38 +107,28 @@ class ColorSwatchTabView extends StatelessWidget {
...
@@ -107,38 +107,28 @@ class ColorSwatchTabView extends StatelessWidget {
}
}
}
}
class
ColorsDemo
extends
StatefulWidget
{
class
ColorsDemo
extends
StatelessWidget
{
ColorsDemo
({
Key
key
})
:
super
(
key:
key
);
static
const
String
routeName
=
'/colors'
;
static
const
String
routeName
=
'/colors'
;
@override
_ColorsDemoState
createState
()
=>
new
_ColorsDemoState
();
}
class
_ColorsDemoState
extends
State
<
ColorsDemo
>
{
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
ColorSwatch
>
(
return
new
DefaultTabController
(
values:
colorSwatches
,
length:
colorSwatches
.
length
,
child:
new
Scaffold
(
child:
new
Scaffold
(
appBar:
new
AppBar
(
appBar:
new
AppBar
(
elevation:
0
,
elevation:
0
,
title:
new
Text
(
'Colors'
),
title:
new
Text
(
'Colors'
),
bottom:
new
TabBar
<
ColorSwatch
>
(
bottom:
new
TabBar
(
isScrollable:
true
,
isScrollable:
true
,
labels:
new
Map
<
ColorSwatch
,
TabLabel
>.
fromIterable
(
colorSwatches
,
value:
(
ColorSwatch
swatch
)
{
tabs:
colorSwatches
.
map
((
ColorSwatch
swatch
)
=>
new
Tab
(
text:
swatch
.
name
)).
toList
(),
return
new
TabLabel
(
text:
swatch
.
name
);
})
)
)
),
),
body:
new
TabBarView
<
ColorSwatch
>
(
body:
new
TabBarView
(
children:
colorSwatches
.
map
((
ColorSwatch
swatch
)
{
children:
colorSwatches
.
map
((
ColorSwatch
swatch
)
{
return
new
ColorSwatchTabView
(
swatch:
swatch
);
return
new
ColorSwatchTabView
(
swatch:
swatch
);
})
}).
toList
(),
.
toList
()
),
)
),
)
);
);
}
}
}
}
examples/flutter_gallery/lib/demo/page_selector_demo.dart
View file @
b23aed7a
...
@@ -4,78 +4,83 @@
...
@@ -4,78 +4,83 @@
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
class
PageSelectorDemo
extends
StatelessWidget
{
class
_PageSelector
extends
StatelessWidget
{
_PageSelector
({
this
.
icons
});
static
const
String
routeName
=
'/page-selector'
;
final
List
<
IconData
>
icons
;
void
_handleArrowButtonPress
(
BuildContext
context
,
int
delta
)
{
void
_handleArrowButtonPress
(
BuildContext
context
,
int
delta
)
{
final
TabBarSelectionState
<
IconData
>
selection
=
TabBarSelection
.
of
/*<IconData>*/
(
context
);
TabController
controller
=
DefaultTabController
.
of
(
context
);
if
(!
selection
.
value
IsChanging
)
if
(!
controller
.
index
IsChanging
)
selection
.
value
=
selection
.
values
[(
selection
.
index
+
delta
).
clamp
(
0
,
selection
.
values
.
length
-
1
)]
;
controller
.
animateTo
(
controller
.
index
+
delta
)
;
}
}
@override
@override
Widget
build
(
BuildContext
notUsed
)
{
// Can't find the TabBarSelection from this context.
Widget
build
(
BuildContext
context
)
{
final
List
<
IconData
>
icons
=
<
IconData
>[
final
TabController
controller
=
DefaultTabController
.
of
(
context
);
Icons
.
event
,
final
Color
color
=
Theme
.
of
(
context
).
accentColor
;
Icons
.
home
,
return
new
Column
(
Icons
.
android
,
children:
<
Widget
>[
Icons
.
alarm
,
new
Container
(
Icons
.
face
,
margin:
const
EdgeInsets
.
only
(
top:
16.0
),
Icons
.
language
,
child:
new
Row
(
];
children:
<
Widget
>[
new
IconButton
(
icon:
new
Icon
(
Icons
.
chevron_left
),
color:
color
,
onPressed:
()
{
_handleArrowButtonPress
(
context
,
-
1
);
},
tooltip:
'Page back'
),
new
TabPageSelector
(
controller:
controller
),
new
IconButton
(
icon:
new
Icon
(
Icons
.
chevron_right
),
color:
color
,
onPressed:
()
{
_handleArrowButtonPress
(
context
,
1
);
},
tooltip:
'Page forward'
)
],
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
)
),
new
Expanded
(
child:
new
TabBarView
(
children:
icons
.
map
((
IconData
icon
)
{
return
new
Container
(
key:
new
ObjectKey
(
icon
),
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
new
Card
(
child:
new
Center
(
child:
new
Icon
(
icon
,
size:
128.0
,
color:
color
)
),
),
);
}).
toList
()
),
),
],
);
}
}
class
PageSelectorDemo
extends
StatelessWidget
{
static
const
String
routeName
=
'/page-selector'
;
static
final
List
<
IconData
>
icons
=
<
IconData
>[
Icons
.
event
,
Icons
.
home
,
Icons
.
android
,
Icons
.
alarm
,
Icons
.
face
,
Icons
.
language
,
];
@override
Widget
build
(
BuildContext
context
)
{
return
new
Scaffold
(
return
new
Scaffold
(
appBar:
new
AppBar
(
title:
new
Text
(
'Page selector'
)),
appBar:
new
AppBar
(
title:
new
Text
(
'Page selector'
)),
body:
new
TabBarSelection
<
IconData
>(
body:
new
DefaultTabController
(
values:
icons
,
length:
icons
.
length
,
child:
new
Builder
(
child:
new
_PageSelector
(
icons:
icons
),
builder:
(
BuildContext
context
)
{
),
final
Color
color
=
Theme
.
of
(
context
).
accentColor
;
return
new
Column
(
children:
<
Widget
>[
new
Container
(
margin:
const
EdgeInsets
.
only
(
top:
16.0
),
child:
new
Row
(
children:
<
Widget
>[
new
IconButton
(
icon:
new
Icon
(
Icons
.
chevron_left
),
color:
color
,
onPressed:
()
{
_handleArrowButtonPress
(
context
,
-
1
);
},
tooltip:
'Page back'
),
new
TabPageSelector
<
IconData
>(),
new
IconButton
(
icon:
new
Icon
(
Icons
.
chevron_right
),
color:
color
,
onPressed:
()
{
_handleArrowButtonPress
(
context
,
1
);
},
tooltip:
'Page forward'
)
],
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
)
),
new
Expanded
(
child:
new
TabBarView
<
IconData
>(
children:
icons
.
map
((
IconData
icon
)
{
return
new
Container
(
key:
new
ObjectKey
(
icon
),
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
new
Card
(
child:
new
Center
(
child:
new
Icon
(
icon
,
size:
128.0
,
color:
color
)
)
)
);
})
.
toList
()
)
)
]
);
}
)
)
);
);
}
}
}
}
examples/flutter_gallery/lib/demo/scrollable_tabs_demo.dart
View file @
b23aed7a
...
@@ -10,6 +10,21 @@ enum TabsDemoStyle {
...
@@ -10,6 +10,21 @@ enum TabsDemoStyle {
textOnly
textOnly
}
}
class
_Page
{
_Page
({
this
.
icon
,
this
.
text
});
final
IconData
icon
;
final
String
text
;
}
final
List
<
_Page
>
_allPages
=
<
_Page
>[
new
_Page
(
icon:
Icons
.
event
,
text:
'EVENT'
),
new
_Page
(
icon:
Icons
.
home
,
text:
'HOME'
),
new
_Page
(
icon:
Icons
.
android
,
text:
'ANDROID'
),
new
_Page
(
icon:
Icons
.
alarm
,
text:
'ALARM'
),
new
_Page
(
icon:
Icons
.
face
,
text:
'FACE'
),
new
_Page
(
icon:
Icons
.
language
,
text:
'LANGAUGE'
),
];
class
ScrollableTabsDemo
extends
StatefulWidget
{
class
ScrollableTabsDemo
extends
StatefulWidget
{
static
const
String
routeName
=
'/scrollable-tabs'
;
static
const
String
routeName
=
'/scrollable-tabs'
;
...
@@ -17,26 +32,21 @@ class ScrollableTabsDemo extends StatefulWidget {
...
@@ -17,26 +32,21 @@ class ScrollableTabsDemo extends StatefulWidget {
ScrollableTabsDemoState
createState
()
=>
new
ScrollableTabsDemoState
();
ScrollableTabsDemoState
createState
()
=>
new
ScrollableTabsDemoState
();
}
}
class
ScrollableTabsDemoState
extends
State
<
ScrollableTabsDemo
>
{
class
ScrollableTabsDemoState
extends
State
<
ScrollableTabsDemo
>
with
SingleTickerProviderStateMixin
{
final
List
<
IconData
>
icons
=
<
IconData
>[
TabController
_controller
;
Icons
.
event
,
TabsDemoStyle
_demoStyle
=
TabsDemoStyle
.
iconsAndText
;
Icons
.
home
,
Icons
.
android
,
Icons
.
alarm
,
Icons
.
face
,
Icons
.
language
,
];
final
Map
<
IconData
,
String
>
labels
=
<
IconData
,
String
>{
@override
Icons
.
event
:
'EVENT'
,
void
initState
()
{
Icons
.
home
:
'HOME'
,
super
.
initState
();
Icons
.
android
:
'ANDROID'
,
_controller
=
new
TabController
(
vsync:
this
,
length:
_allPages
.
length
);
Icons
.
alarm
:
'ALARM'
,
}
Icons
.
face
:
'FACE'
,
Icons
.
language
:
'LANGUAGE'
,
};
TabsDemoStyle
_demoStyle
=
TabsDemoStyle
.
iconsAndText
;
@override
void
dispose
()
{
_controller
.
dispose
();
super
.
dispose
();
}
void
changeDemoStyle
(
TabsDemoStyle
style
)
{
void
changeDemoStyle
(
TabsDemoStyle
style
)
{
setState
(()
{
setState
(()
{
...
@@ -47,65 +57,61 @@ class ScrollableTabsDemoState extends State<ScrollableTabsDemo> {
...
@@ -47,65 +57,61 @@ class ScrollableTabsDemoState extends State<ScrollableTabsDemo> {
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Color
iconColor
=
Theme
.
of
(
context
).
accentColor
;
final
Color
iconColor
=
Theme
.
of
(
context
).
accentColor
;
return
new
TabBarSelection
<
IconData
>(
return
new
Scaffold
(
values:
icons
,
appBar:
new
AppBar
(
child:
new
Scaffold
(
title:
new
Text
(
'Scrollable tabs'
),
appBar:
new
AppBar
(
actions:
<
Widget
>[
title:
new
Text
(
'Scrollable tabs'
),
new
PopupMenuButton
<
TabsDemoStyle
>(
actions:
<
Widget
>[
onSelected:
changeDemoStyle
,
new
PopupMenuButton
<
TabsDemoStyle
>(
itemBuilder:
(
BuildContext
context
)
=>
<
PopupMenuItem
<
TabsDemoStyle
>>[
onSelected:
changeDemoStyle
,
new
PopupMenuItem
<
TabsDemoStyle
>(
itemBuilder:
(
BuildContext
context
)
=>
<
PopupMenuItem
<
TabsDemoStyle
>>[
value:
TabsDemoStyle
.
iconsAndText
,
new
PopupMenuItem
<
TabsDemoStyle
>(
child:
new
Text
(
'Icons and text'
)
value:
TabsDemoStyle
.
iconsAndText
,
),
child:
new
Text
(
'Icons and text'
)
new
PopupMenuItem
<
TabsDemoStyle
>(
),
value:
TabsDemoStyle
.
iconsOnly
,
new
PopupMenuItem
<
TabsDemoStyle
>(
child:
new
Text
(
'Icons only'
)
value:
TabsDemoStyle
.
iconsOnly
,
),
child:
new
Text
(
'Icons only'
)
new
PopupMenuItem
<
TabsDemoStyle
>(
),
value:
TabsDemoStyle
.
textOnly
,
new
PopupMenuItem
<
TabsDemoStyle
>(
child:
new
Text
(
'Text only'
)
value:
TabsDemoStyle
.
textOnly
,
),
child:
new
Text
(
'Text only'
)
],
),
),
]
],
)
bottom:
new
TabBar
(
],
controller:
_controller
,
bottom:
new
TabBar
<
IconData
>(
isScrollable:
true
,
isScrollable:
true
,
tabs:
_allPages
.
map
((
_Page
page
)
{
labels:
new
Map
<
IconData
,
TabLabel
>.
fromIterable
(
switch
(
_demoStyle
)
{
icons
,
case
TabsDemoStyle
.
iconsAndText
:
value:
(
IconData
icon
)
{
return
new
Tab
(
text:
page
.
text
,
icon:
new
Icon
(
page
.
icon
));
switch
(
_demoStyle
)
{
case
TabsDemoStyle
.
iconsOnly
:
case
TabsDemoStyle
.
iconsAndText
:
return
new
Tab
(
icon:
new
Icon
(
page
.
icon
));
return
new
TabLabel
(
text:
labels
[
icon
],
icon:
new
Icon
(
icon
));
case
TabsDemoStyle
.
textOnly
:
case
TabsDemoStyle
.
iconsOnly
:
return
new
Tab
(
text:
page
.
text
);
return
new
TabLabel
(
icon:
new
Icon
(
icon
));
}
case
TabsDemoStyle
.
textOnly
:
}).
toList
(),
return
new
TabLabel
(
text:
labels
[
icon
]);
}
}
)
)
),
),
body:
new
TabBarView
<
IconData
>(
),
children:
icons
.
map
((
IconData
icon
)
{
body:
new
TabBarView
(
return
new
Container
(
controller:
_controller
,
key:
new
ObjectKey
(
icon
),
children:
_allPages
.
map
((
_Page
page
)
{
padding:
const
EdgeInsets
.
all
(
12.0
),
return
new
Container
(
child:
new
Card
(
key:
new
ObjectKey
(
page
.
icon
),
child:
new
Center
(
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
new
Icon
(
child:
new
Card
(
icon
,
child:
new
Center
(
color:
iconColor
,
child:
new
Icon
(
size:
128.0
page
.
icon
,
)
color:
iconColor
,
)
size:
128.0
,
)
),
);
),
}).
toList
()
),
)
);
)
}).
toList
()
),
);
);
}
}
}
}
examples/flutter_gallery/lib/demo/tabs_demo.dart
View file @
b23aed7a
...
@@ -111,30 +111,21 @@ class _CardDataItem extends StatelessWidget {
...
@@ -111,30 +111,21 @@ class _CardDataItem extends StatelessWidget {
}
}
}
}
class
TabsDemo
extends
StatefulWidget
{
class
TabsDemo
extends
StatelessWidget
{
TabsDemo
({
Key
key
})
:
super
(
key:
key
);
static
const
String
routeName
=
'/tabs'
;
static
const
String
routeName
=
'/tabs'
;
@override
_TabsDemoState
createState
()
=>
new
_TabsDemoState
();
}
class
_TabsDemoState
extends
State
<
TabsDemo
>
{
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
_Page
>
(
return
new
DefaultTabController
(
values:
_allPages
.
keys
.
toList
()
,
length:
_allPages
.
length
,
child:
new
Scaffold
(
child:
new
Scaffold
(
appBar:
new
AppBar
(
appBar:
new
AppBar
(
title:
new
Text
(
'Tabs and scrolling'
),
title:
new
Text
(
'Tabs and scrolling'
),
bottom:
new
TabBar
<
_Page
>(
bottom:
new
TabBar
(
labels:
new
Map
<
_Page
,
TabLabel
>.
fromIterable
(
_allPages
.
keys
,
value:
(
_Page
page
)
{
tabs:
_allPages
.
keys
.
map
((
_Page
page
)
=>
new
Tab
(
text:
page
.
label
)).
toList
(),
return
new
TabLabel
(
text:
page
.
label
);
),
})
)
),
),
body:
new
TabBarView
<
_Page
>
(
body:
new
TabBarView
(
children:
_allPages
.
keys
.
map
((
_Page
page
)
{
children:
_allPages
.
keys
.
map
((
_Page
page
)
{
return
new
ScrollableList
(
return
new
ScrollableList
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
,
horizontal:
16.0
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
,
horizontal:
16.0
),
...
@@ -144,11 +135,11 @@ class _TabsDemoState extends State<TabsDemo> {
...
@@ -144,11 +135,11 @@ class _TabsDemoState extends State<TabsDemo> {
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
),
child:
new
_CardDataItem
(
page:
page
,
data:
data
)
child:
new
_CardDataItem
(
page:
page
,
data:
data
)
);
);
}).
toList
()
}).
toList
()
,
);
);
}).
toList
()
}).
toList
()
,
)
)
,
)
)
,
);
);
}
}
}
}
examples/flutter_gallery/lib/demo/tabs_fab_demo.dart
View file @
b23aed7a
...
@@ -4,6 +4,12 @@
...
@@ -4,6 +4,12 @@
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
const
String
_explanatoryText
=
"When the Scaffold's floating action button changes, the new button fades and "
"turns into view. In this demo, changing tabs can cause the app to be rebuilt "
"with a FloatingActionButton that the Scaffold distinguishes from the others "
"by its key."
;
class
_Page
{
class
_Page
{
_Page
({
this
.
label
,
this
.
colors
,
this
.
icon
});
_Page
({
this
.
label
,
this
.
colors
,
this
.
icon
});
...
@@ -11,7 +17,6 @@ class _Page {
...
@@ -11,7 +17,6 @@ class _Page {
final
Map
<
int
,
Color
>
colors
;
final
Map
<
int
,
Color
>
colors
;
final
IconData
icon
;
final
IconData
icon
;
TabLabel
get
tabLabel
=>
new
TabLabel
(
text:
label
.
toUpperCase
());
Color
get
labelColor
=>
colors
!=
null
?
colors
[
300
]
:
Colors
.
grey
[
300
];
Color
get
labelColor
=>
colors
!=
null
?
colors
[
300
]
:
Colors
.
grey
[
300
];
bool
get
fabDefined
=>
colors
!=
null
&&
icon
!=
null
;
bool
get
fabDefined
=>
colors
!=
null
&&
icon
!=
null
;
Color
get
fabColor
=>
colors
[
400
];
Color
get
fabColor
=>
colors
[
400
];
...
@@ -19,11 +24,13 @@ class _Page {
...
@@ -19,11 +24,13 @@ class _Page {
Key
get
fabKey
=>
new
ValueKey
<
Color
>(
fabColor
);
Key
get
fabKey
=>
new
ValueKey
<
Color
>(
fabColor
);
}
}
const
String
_explanatoryText
=
final
List
<
_Page
>
_allPages
=
<
_Page
>[
"When the Scaffold's floating action button changes, the new button fades and "
new
_Page
(
label:
'Blue'
,
colors:
Colors
.
indigo
,
icon:
Icons
.
add
),
"turns into view. In this demo, changing tabs can cause the app to be rebuilt "
new
_Page
(
label:
'Eco'
,
colors:
Colors
.
green
,
icon:
Icons
.
create
),
"with a FloatingActionButton that the Scaffold distinguishes from the others "
new
_Page
(
label:
'No'
),
"by its key."
;
new
_Page
(
label:
'Teal'
,
colors:
Colors
.
teal
,
icon:
Icons
.
add
),
new
_Page
(
label:
'Red'
,
colors:
Colors
.
red
,
icon:
Icons
.
create
),
];
class
TabsFabDemo
extends
StatefulWidget
{
class
TabsFabDemo
extends
StatefulWidget
{
static
const
String
routeName
=
'/tabs-fab'
;
static
const
String
routeName
=
'/tabs-fab'
;
...
@@ -32,31 +39,34 @@ class TabsFabDemo extends StatefulWidget {
...
@@ -32,31 +39,34 @@ class TabsFabDemo extends StatefulWidget {
_TabsFabDemoState
createState
()
=>
new
_TabsFabDemoState
();
_TabsFabDemoState
createState
()
=>
new
_TabsFabDemoState
();
}
}
class
_TabsFabDemoState
extends
State
<
TabsFabDemo
>
{
class
_TabsFabDemoState
extends
State
<
TabsFabDemo
>
with
SingleTickerProviderStateMixin
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
new
GlobalKey
<
ScaffoldState
>();
final
GlobalKey
<
ScaffoldState
>
_scaffoldKey
=
new
GlobalKey
<
ScaffoldState
>();
final
List
<
_Page
>
pages
=
<
_Page
>[
new
_Page
(
label:
'Blue'
,
colors:
Colors
.
indigo
,
icon:
Icons
.
add
),
TabController
_controller
;
new
_Page
(
label:
'Eco'
,
colors:
Colors
.
green
,
icon:
Icons
.
create
),
_Page
_selectedPage
;
new
_Page
(
label:
'No'
),
new
_Page
(
label:
'Teal'
,
colors:
Colors
.
teal
,
icon:
Icons
.
add
),
new
_Page
(
label:
'Red'
,
colors:
Colors
.
red
,
icon:
Icons
.
create
),
];
_Page
selectedPage
;
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
selectedPage
=
pages
[
0
];
_controller
=
new
TabController
(
vsync:
this
,
length:
_allPages
.
length
);
_controller
.
addListener
(
_handleTabSelection
);
_selectedPage
=
_allPages
[
0
];
}
@override
void
dispose
()
{
_controller
.
dispose
();
super
.
dispose
();
}
}
void
_handleTabSelection
(
_Page
page
)
{
void
_handleTabSelection
()
{
setState
(()
{
setState
(()
{
selectedPage
=
page
;
_selectedPage
=
_allPages
[
_controller
.
index
]
;
});
});
}
}
void
_showExplanatoryText
()
{
void
_showExplanatoryText
()
{
scaffoldKey
.
currentState
.
showBottomSheet
((
BuildContext
context
)
{
_
scaffoldKey
.
currentState
.
showBottomSheet
((
BuildContext
context
)
{
return
new
Container
(
return
new
Container
(
decoration:
new
BoxDecoration
(
decoration:
new
BoxDecoration
(
border:
new
Border
(
top:
new
BorderSide
(
color:
Theme
.
of
(
context
).
dividerColor
))
border:
new
Border
(
top:
new
BorderSide
(
color:
Theme
.
of
(
context
).
dividerColor
))
...
@@ -93,26 +103,26 @@ class _TabsFabDemoState extends State<TabsFabDemo> {
...
@@ -93,26 +103,26 @@ class _TabsFabDemoState extends State<TabsFabDemo> {
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
_Page
>
(
return
new
Scaffold
(
values:
pages
,
key:
_scaffoldKey
,
onChanged:
_handleTabSelection
,
appBar:
new
AppBar
(
child:
new
Scaffold
(
title:
new
Text
(
'FAB per tab'
),
key:
scaffoldKey
,
bottom:
new
TabBar
(
appBar:
new
AppBar
(
controller:
_controller
,
t
itle:
new
Text
(
'FAB per tab'
),
t
abs:
_allPages
.
map
((
_Page
page
)
=>
new
Tab
(
text:
page
.
label
.
toUpperCase
())).
toList
(
),
bottom:
new
TabBar
<
_Page
>(
)
labels:
new
Map
<
_Page
,
TabLabel
>.
fromIterable
(
pages
,
value:
(
_Page
page
)
=>
page
.
tabLabel
)
),
)
floatingActionButton:
!
_selectedPage
.
fabDefined
?
null
:
new
FloatingActionButton
(
)
,
key:
_selectedPage
.
fabKey
,
floatingActionButton:
!
selectedPage
.
fabDefined
?
null
:
new
FloatingActionButton
(
tooltip:
'Show explanation'
,
key:
selectedPage
.
fabKey
,
backgroundColor:
_selectedPage
.
fabColor
,
tooltip:
'Show explanation'
,
child:
_selectedPage
.
fabIcon
,
backgroundColor:
selectedPage
.
fabColor
,
onPressed:
_showExplanatoryText
child:
selectedPage
.
fabIcon
,
)
,
onPressed:
_showExplanatoryText
body:
new
TabBarView
(
)
,
controller:
_controller
,
body:
new
TabBarView
<
_Page
>(
children:
pages
.
map
(
buildTabView
).
toList
()
)
children:
_allPages
.
map
(
buildTabView
).
toList
(
)
)
)
,
);
);
}
}
}
}
examples/flutter_gallery/lib/gallery/demo.dart
View file @
b23aed7a
...
@@ -20,13 +20,6 @@ class ComponentDemoTabData {
...
@@ -20,13 +20,6 @@ class ComponentDemoTabData {
final
String
description
;
final
String
description
;
final
String
tabName
;
final
String
tabName
;
static
Map
<
ComponentDemoTabData
,
TabLabel
>
buildTabLabels
(
List
<
ComponentDemoTabData
>
demos
)
{
return
new
Map
<
ComponentDemoTabData
,
TabLabel
>.
fromIterable
(
demos
,
value:
(
ComponentDemoTabData
demo
)
=>
new
TabLabel
(
text:
demo
.
tabName
)
);
}
@override
@override
bool
operator
==(
Object
other
)
{
bool
operator
==(
Object
other
)
{
if
(
other
.
runtimeType
!=
runtimeType
)
if
(
other
.
runtimeType
!=
runtimeType
)
...
@@ -49,8 +42,7 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
...
@@ -49,8 +42,7 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
final
String
title
;
final
String
title
;
void
_showExampleCode
(
BuildContext
context
)
{
void
_showExampleCode
(
BuildContext
context
)
{
TabBarSelectionState
<
ComponentDemoTabData
>
selection
=
TabBarSelection
.
of
(
context
);
String
tag
=
demos
[
DefaultTabController
.
of
(
context
).
index
].
exampleCodeTag
;
String
tag
=
selection
.
value
?.
exampleCodeTag
;
if
(
tag
!=
null
)
{
if
(
tag
!=
null
)
{
Navigator
.
push
(
context
,
new
MaterialPageRoute
<
FullScreenCodeDialog
>(
Navigator
.
push
(
context
,
new
MaterialPageRoute
<
FullScreenCodeDialog
>(
builder:
(
BuildContext
context
)
=>
new
FullScreenCodeDialog
(
exampleCodeTag:
tag
)
builder:
(
BuildContext
context
)
=>
new
FullScreenCodeDialog
(
exampleCodeTag:
tag
)
...
@@ -60,8 +52,8 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
...
@@ -60,8 +52,8 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
ComponentDemoTabData
>
(
return
new
DefaultTabController
(
values:
demos
,
length:
demos
.
length
,
child:
new
Scaffold
(
child:
new
Scaffold
(
appBar:
new
AppBar
(
appBar:
new
AppBar
(
title:
new
Text
(
title
),
title:
new
Text
(
title
),
...
@@ -71,17 +63,19 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
...
@@ -71,17 +63,19 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
return
new
IconButton
(
return
new
IconButton
(
icon:
new
Icon
(
Icons
.
description
),
icon:
new
Icon
(
Icons
.
description
),
tooltip:
'Show example code'
,
tooltip:
'Show example code'
,
onPressed:
()
{
_showExampleCode
(
context
);
}
onPressed:
()
{
_showExampleCode
(
context
);
},
);
);
}
}
,
)
)
,
],
],
bottom:
new
TabBar
<
ComponentDemoTabData
>
(
bottom:
new
TabBar
(
isScrollable:
true
,
isScrollable:
true
,
labels:
ComponentDemoTabData
.
buildTabLabels
(
demos
)
tabs:
demos
.
map
((
ComponentDemoTabData
data
)
=>
new
Tab
(
text:
data
.
tabName
)).
toList
(),
)
)
,
),
),
body:
new
TabBarView
<
ComponentDemoTabData
>
(
body:
new
TabBarView
(
children:
demos
.
map
((
ComponentDemoTabData
demo
)
{
children:
demos
.
map
((
ComponentDemoTabData
demo
)
{
return
new
Column
(
return
new
Column
(
children:
<
Widget
>[
children:
<
Widget
>[
...
@@ -92,11 +86,11 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
...
@@ -92,11 +86,11 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
)
)
),
),
new
Expanded
(
child:
demo
.
widget
)
new
Expanded
(
child:
demo
.
widget
)
]
]
,
);
);
}).
toList
()
}).
toList
()
,
)
)
,
)
)
,
);
);
}
}
}
}
...
...
examples/stocks/lib/stock_home.dart
View file @
b23aed7a
...
@@ -222,11 +222,11 @@ class StockHomeState extends State<StockHome> {
...
@@ -222,11 +222,11 @@ class StockHomeState extends State<StockHome> {
]
]
)
)
],
],
bottom:
new
TabBar
<
StockHomeTab
>
(
bottom:
new
TabBar
(
labels:
<
StockHomeTab
,
TabLabel
>{
tabs:
<
Widget
>[
StockHomeTab
.
market
:
new
TabLabel
(
text:
StockStrings
.
of
(
context
).
market
()),
new
Tab
(
text:
StockStrings
.
of
(
context
).
market
()),
StockHomeTab
.
portfolio
:
new
TabLabel
(
text:
StockStrings
.
of
(
context
).
portfolio
())
new
Tab
(
text:
StockStrings
.
of
(
context
).
portfolio
()),
}
]
)
)
);
);
}
}
...
@@ -318,14 +318,14 @@ class StockHomeState extends State<StockHome> {
...
@@ -318,14 +318,14 @@ class StockHomeState extends State<StockHome> {
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
TabBarSelection
<
StockHomeTab
>
(
return
new
DefaultTabController
(
values:
<
StockHomeTab
>[
StockHomeTab
.
market
,
StockHomeTab
.
portfolio
]
,
length:
2
,
child:
new
Scaffold
(
child:
new
Scaffold
(
key:
_scaffoldKey
,
key:
_scaffoldKey
,
appBar:
_isSearching
?
buildSearchBar
()
:
buildAppBar
(),
appBar:
_isSearching
?
buildSearchBar
()
:
buildAppBar
(),
floatingActionButton:
buildFloatingActionButton
(),
floatingActionButton:
buildFloatingActionButton
(),
drawer:
_buildDrawer
(
context
),
drawer:
_buildDrawer
(
context
),
body:
new
TabBarView
<
StockHomeTab
>
(
body:
new
TabBarView
(
children:
<
Widget
>[
children:
<
Widget
>[
_buildStockTab
(
context
,
StockHomeTab
.
market
,
config
.
symbols
),
_buildStockTab
(
context
,
StockHomeTab
.
market
,
config
.
symbols
),
_buildStockTab
(
context
,
StockHomeTab
.
portfolio
,
portfolioSymbols
),
_buildStockTab
(
context
,
StockHomeTab
.
portfolio
,
portfolioSymbols
),
...
...
packages/flutter/lib/material.dart
View file @
b23aed7a
...
@@ -71,6 +71,7 @@ export 'src/material/snack_bar.dart';
...
@@ -71,6 +71,7 @@ export 'src/material/snack_bar.dart';
export
'src/material/stepper.dart'
;
export
'src/material/stepper.dart'
;
export
'src/material/switch.dart'
;
export
'src/material/switch.dart'
;
export
'src/material/tabs.dart'
;
export
'src/material/tabs.dart'
;
export
'src/material/tab_controller.dart'
;
export
'src/material/theme.dart'
;
export
'src/material/theme.dart'
;
export
'src/material/theme_data.dart'
;
export
'src/material/theme_data.dart'
;
export
'src/material/time_picker.dart'
;
export
'src/material/time_picker.dart'
;
...
...
packages/flutter/lib/src/material/constants.dart
View file @
b23aed7a
...
@@ -22,3 +22,6 @@ const Duration kRadialReactionDuration = const Duration(milliseconds: 200);
...
@@ -22,3 +22,6 @@ const Duration kRadialReactionDuration = const Duration(milliseconds: 200);
/// The value of the alpha channel to use when drawing a circular material ink response.
/// The value of the alpha channel to use when drawing a circular material ink response.
const
int
kRadialReactionAlpha
=
0x33
;
const
int
kRadialReactionAlpha
=
0x33
;
/// The duration
const
Duration
kTabScrollDuration
=
const
Duration
(
milliseconds:
200
);
packages/flutter/lib/src/material/tab_controller.dart
0 → 100644
View file @
b23aed7a
// Copyright 2015 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/foundation.dart'
;
import
'package:flutter/widgets.dart'
;
import
'constants.dart'
;
/// Coordinates tab selection between a [TabBar] and a [TabBarView].
///
/// The [index] property is the index of the selected tab and the [animation]
/// represents the current scroll positions of the tab bar and the tar bar view.
/// The selected tab's index can be changed with [animateTo].
///
/// See also:
///
/// * [DefaultTabController], which simplifies sharing a TabController with
/// its [TabBar] and a [TabBarView] descendants.
class
TabController
extends
ChangeNotifier
{
/// Creates an object that manages the state required by [TabBar] and a [TabBarView].
TabController
({
int
initialIndex:
0
,
@required
this
.
length
,
@required
TickerProvider
vsync
})
:
_index
=
initialIndex
,
_previousIndex
=
initialIndex
,
_animationController
=
new
AnimationController
(
value:
initialIndex
.
toDouble
(),
upperBound:
(
length
-
1
).
toDouble
(),
vsync:
vsync
)
{
assert
(
length
!=
null
&&
length
>
1
);
assert
(
initialIndex
!=
null
&&
initialIndex
>=
0
&&
initialIndex
<
length
);
}
/// An animation whose value represents the current position of the [TabBar]'s
/// selected tab indicator as well as the scrollOffsets of the [TabBar]
/// and [TabBarView].
///
/// The animation's value ranges from 0.0 to [length] - 1.0. After the
/// selected tab is changed, the animation's value equals [index]. The
/// animation's value can be [offset] by +/- 1.0 to reflect [TabBarView]
/// drag scrolling.
final
AnimationController
_animationController
;
Animation
<
double
>
get
animation
=>
_animationController
.
view
;
/// The total number of tabs. Must be greater than one.
final
int
length
;
void
_changeIndex
(
int
value
,
{
Duration
duration
,
Curve
curve
})
{
assert
(
value
!=
null
);
assert
(
value
>=
0
&&
value
<
length
);
assert
(
duration
==
null
?
curve
==
null
:
true
);
assert
(
_indexIsChangingCount
>=
0
);
if
(
value
==
_index
)
return
;
_previousIndex
=
index
;
_index
=
value
;
if
(
duration
!=
null
)
{
_indexIsChangingCount
+=
1
;
_animationController
..
animateTo
(
_index
.
toDouble
(),
duration:
duration
,
curve:
curve
).
then
((
_
)
{
_indexIsChangingCount
-=
1
;
notifyListeners
();
});
}
else
{
_indexIsChangingCount
+=
1
;
_animationController
.
value
=
_index
.
toDouble
();
_indexIsChangingCount
-=
1
;
notifyListeners
();
}
}
/// The index of the currently selected tab. Changing the index also updates
/// [previousIndex], sets the [animation]'s value to index, resets
/// [indexIsChanging] to false, and notifies listeners.
///
/// To change the currently selected tab and play the [animation] use [animateTo].
int
get
index
=>
_index
;
int
_index
;
set
index
(
int
value
)
{
_changeIndex
(
value
);
}
/// The index of the previously selected tab. Initially the same as [index].
int
get
previousIndex
=>
_previousIndex
;
int
_previousIndex
;
/// True while we're animating from [previousIndex] to [index].
bool
get
indexIsChanging
=>
_indexIsChangingCount
!=
0
;
int
_indexIsChangingCount
=
0
;
/// Immediately sets [index] and [previousIndex] and then plays the
/// [animation] from its current value to [index].
///
/// While the animation is running [indexIsChanging] is true. When the
/// animation completes [offset] will be 0.0.
void
animateTo
(
int
value
,
{
Duration
duration:
kTabScrollDuration
,
Curve
curve:
Curves
.
ease
})
{
_changeIndex
(
value
,
duration:
duration
,
curve:
curve
);
}
/// The difference between the [animation]'s value and [index]. The offset
/// value must be between -1.0 and 1.0.
///
/// This property is typically set by the [TabBarView] when the user
/// drags left or right. A value between -1.0 and 0.0 implies that the
/// TabBarView has been dragged to the left. Similarly a value between
/// 0.0 and 1.0 implies that the TabBarView has been dragged to the right.
double
get
offset
=>
_animationController
.
value
-
_index
.
toDouble
();
set
offset
(
double
newOffset
)
{
assert
(
newOffset
!=
null
);
assert
(
newOffset
>=
-
1.0
&&
newOffset
<=
1.0
);
assert
(!
indexIsChanging
);
if
(
newOffset
==
offset
)
return
;
_animationController
.
value
=
newOffset
+
_index
.
toDouble
();
}
@override
void
dispose
()
{
_animationController
.
dispose
();
super
.
dispose
();
}
}
class
_TabControllerScope
extends
InheritedWidget
{
_TabControllerScope
({
Key
key
,
this
.
controller
,
this
.
enabled
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
final
TabController
controller
;
final
bool
enabled
;
@override
bool
updateShouldNotify
(
_TabControllerScope
old
)
{
return
enabled
!=
old
.
enabled
||
controller
!=
old
.
controller
;
}
}
/// The [TabController] for descendant widgets that don't specify one explicitly.
class
DefaultTabController
extends
StatefulWidget
{
DefaultTabController
({
Key
key
,
@required
this
.
length
,
this
.
initialIndex
:
0
,
this
.
child
})
:
super
(
key:
key
);
/// The total number of tabs. Must be greater than one.
final
int
length
;
/// The initial index of the selected tab.
final
int
initialIndex
;
/// This widget's child. Often a [Scaffold] whose [AppBar] includes a [TabBar].
final
Widget
child
;
/// The closest instance of this class that encloses the given context.
///
/// Typical usage:
///
/// ```dart
/// TabController controller = DefaultTabBarController.of(context);
/// ```
static
TabController
of
(
BuildContext
context
)
{
_TabControllerScope
scope
=
context
.
inheritFromWidgetOfExactType
(
_TabControllerScope
);
return
scope
?.
controller
;
}
@override
_DefaultTabControllerState
createState
()
=>
new
_DefaultTabControllerState
();
}
class
_DefaultTabControllerState
extends
State
<
DefaultTabController
>
with
SingleTickerProviderStateMixin
{
TabController
_controller
;
@override
void
initState
()
{
super
.
initState
();
_controller
=
new
TabController
(
vsync:
this
,
length:
config
.
length
,
initialIndex:
config
.
initialIndex
,
);
}
@override
void
dispose
()
{
_controller
.
dispose
();
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
new
_TabControllerScope
(
controller:
_controller
,
enabled:
TickerMode
.
of
(
context
),
child:
config
.
child
,
);
}
}
packages/flutter/lib/src/material/tabs.dart
View file @
b23aed7a
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/tabs_test.dart
View file @
b23aed7a
This diff is collapsed.
Click to expand it.
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