Add Container.align and Container.position (#5128)
These let you add Align widget to the inside or outside of a container. Several customers have asked for these properties. Fixes #4950
This commit is contained in:
parent
534097ffb6
commit
79364f0a06
@ -284,10 +284,8 @@ class CardCollectionState extends State<CardCollection> {
|
|||||||
flexibleSpace: new Container(
|
flexibleSpace: new Container(
|
||||||
padding: const EdgeInsets.only(left: 72.0),
|
padding: const EdgeInsets.only(left: 72.0),
|
||||||
height: 128.0,
|
height: 128.0,
|
||||||
child: new Align(
|
align: const FractionalOffset(0.0, 0.75),
|
||||||
alignment: const FractionalOffset(0.0, 0.75),
|
child: new Text('Swipe Away: ${_cardModels.length}', style: Theme.of(context).primaryTextTheme.title)
|
||||||
child: new Text('Swipe Away: ${_cardModels.length}', style: Theme.of(context).primaryTextTheme.title)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -166,20 +166,16 @@ class FullScreenDialogDemoState extends State<FullScreenDialogDemo> {
|
|||||||
decoration: new BoxDecoration(
|
decoration: new BoxDecoration(
|
||||||
border: new Border(bottom: new BorderSide(color: theme.dividerColor))
|
border: new Border(bottom: new BorderSide(color: theme.dividerColor))
|
||||||
),
|
),
|
||||||
child: new Align(
|
align: FractionalOffset.bottomLeft,
|
||||||
alignment: FractionalOffset.bottomLeft,
|
child: new Text('Event name', style: theme.textTheme.display2)
|
||||||
child: new Text('Event name', style: theme.textTheme.display2)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
new Container(
|
new Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
decoration: new BoxDecoration(
|
decoration: new BoxDecoration(
|
||||||
border: new Border(bottom: new BorderSide(color: theme.dividerColor))
|
border: new Border(bottom: new BorderSide(color: theme.dividerColor))
|
||||||
),
|
),
|
||||||
child: new Align(
|
align: FractionalOffset.bottomLeft,
|
||||||
alignment: FractionalOffset.bottomLeft,
|
child: new Text('Location', style: theme.textTheme.title.copyWith(color: Colors.black54))
|
||||||
child: new Text('Location', style: theme.textTheme.title.copyWith(color: Colors.black54))
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
new Column(
|
new Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -331,7 +331,7 @@ class _RecipePageState extends State<_RecipePage> {
|
|||||||
const double fabHalfSize = 28.0; // TODO(mpcomplete): needs to adapt to screen size
|
const double fabHalfSize = 28.0; // TODO(mpcomplete): needs to adapt to screen size
|
||||||
return new Hero(
|
return new Hero(
|
||||||
tag: config.recipe.imagePath,
|
tag: config.recipe.imagePath,
|
||||||
child: new DecoratedBox(
|
child: new Container(
|
||||||
decoration: new BoxDecoration(
|
decoration: new BoxDecoration(
|
||||||
backgroundColor: Theme.of(context).canvasColor,
|
backgroundColor: Theme.of(context).canvasColor,
|
||||||
backgroundImage: new BackgroundImage(
|
backgroundImage: new BackgroundImage(
|
||||||
@ -340,33 +340,31 @@ class _RecipePageState extends State<_RecipePage> {
|
|||||||
fit: fullWidth ? ImageFit.fitWidth : ImageFit.cover
|
fit: fullWidth ? ImageFit.fitWidth : ImageFit.cover
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
child: new Align(
|
align: FractionalOffset.bottomCenter,
|
||||||
alignment: FractionalOffset.bottomCenter,
|
child: new Block(
|
||||||
child: new Block(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
new Padding(
|
||||||
new Padding(
|
padding: new EdgeInsets.only(top: _getAppBarHeight(context)),
|
||||||
padding: new EdgeInsets.only(top: _getAppBarHeight(context)),
|
child: new Stack(
|
||||||
child: new Stack(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
new Padding(
|
||||||
new Padding(
|
padding: new EdgeInsets.only(top: fabHalfSize),
|
||||||
padding: new EdgeInsets.only(top: fabHalfSize),
|
child: new SizedBox(
|
||||||
child: new SizedBox(
|
width: fullWidth ? null : _kRecipePageMaxWidth,
|
||||||
width: fullWidth ? null : _kRecipePageMaxWidth,
|
child: new _RecipeSheet(recipe: config.recipe)
|
||||||
child: new _RecipeSheet(recipe: config.recipe)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
new Positioned(
|
|
||||||
right: 16.0,
|
|
||||||
child: new FloatingActionButton(
|
|
||||||
child: new Icon(isFavorite ? Icons.favorite : Icons.favorite_border),
|
|
||||||
onPressed: _toggleFavorite
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
]
|
),
|
||||||
)
|
new Positioned(
|
||||||
|
right: 16.0,
|
||||||
|
child: new FloatingActionButton(
|
||||||
|
child: new Icon(isFavorite ? Icons.favorite : Icons.favorite_border),
|
||||||
|
onPressed: _toggleFavorite
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
]
|
)
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -71,10 +71,8 @@ class GalleryHomeState extends State<GalleryHome> {
|
|||||||
new Container(
|
new Container(
|
||||||
height: 48.0,
|
height: 48.0,
|
||||||
padding: const EdgeInsets.only(left: 16.0),
|
padding: const EdgeInsets.only(left: 16.0),
|
||||||
child: new Align(
|
align: FractionalOffset.centerLeft,
|
||||||
alignment: FractionalOffset.centerLeft,
|
child: new Text(galleryItem.category, style: headerStyle)
|
||||||
child: new Text(galleryItem.category, style: headerStyle)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
category = galleryItem.category;
|
category = galleryItem.category;
|
||||||
|
@ -406,21 +406,19 @@ class DataTable extends StatelessWidget {
|
|||||||
label = new Container(
|
label = new Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: _kHeadingRowHeight,
|
height: _kHeadingRowHeight,
|
||||||
child: new Align(
|
align: new FractionalOffset(numeric ? 1.0 : 0.0, 0.5), // TODO(ianh): RTL for non-numeric
|
||||||
alignment: new FractionalOffset(numeric ? 1.0 : 0.0, 0.5), // TODO(ianh): RTL for non-numeric
|
child: new AnimatedDefaultTextStyle(
|
||||||
child: new AnimatedDefaultTextStyle(
|
style: new TextStyle(
|
||||||
style: new TextStyle(
|
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
||||||
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
fontWeight: FontWeight.w500,
|
||||||
fontWeight: FontWeight.w500,
|
fontSize: _kHeadingFontSize,
|
||||||
fontSize: _kHeadingFontSize,
|
height: _kHeadingRowHeight / _kHeadingFontSize,
|
||||||
height: _kHeadingRowHeight / _kHeadingFontSize,
|
color: (Theme.of(context).brightness == Brightness.light)
|
||||||
color: (Theme.of(context).brightness == Brightness.light)
|
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
|
||||||
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
|
: ((onSort != null && sorted) ? Colors.white : Colors.white70)
|
||||||
: ((onSort != null && sorted) ? Colors.white : Colors.white70)
|
),
|
||||||
),
|
duration: _kSortArrowAnimationDuration,
|
||||||
duration: _kSortArrowAnimationDuration,
|
child: label
|
||||||
child: label
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (tooltip != null) {
|
if (tooltip != null) {
|
||||||
@ -458,23 +456,21 @@ class DataTable extends StatelessWidget {
|
|||||||
label = new Container(
|
label = new Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: _kDataRowHeight,
|
height: _kDataRowHeight,
|
||||||
child: new Align(
|
align: new FractionalOffset(numeric ? 1.0 : 0.0, 0.5), // TODO(ianh): RTL for non-numeric
|
||||||
alignment: new FractionalOffset(numeric ? 1.0 : 0.0, 0.5), // TODO(ianh): RTL for non-numeric
|
child: new DefaultTextStyle(
|
||||||
child: new DefaultTextStyle(
|
style: new TextStyle(
|
||||||
style: new TextStyle(
|
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
||||||
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
fontSize: 13.0,
|
||||||
fontSize: 13.0,
|
color: isLightTheme
|
||||||
color: isLightTheme
|
? (placeholder ? Colors.black38 : Colors.black87)
|
||||||
? (placeholder ? Colors.black38 : Colors.black87)
|
: (placeholder ? Colors.white30 : Colors.white70)
|
||||||
: (placeholder ? Colors.white30 : Colors.white70)
|
),
|
||||||
|
child: new IconTheme.merge(
|
||||||
|
context: context,
|
||||||
|
data: new IconThemeData(
|
||||||
|
color: isLightTheme ? Colors.black54 : Colors.white70
|
||||||
),
|
),
|
||||||
child: new IconTheme.merge(
|
child: new DropDownButtonHideUnderline(child: label)
|
||||||
context: context,
|
|
||||||
data: new IconThemeData(
|
|
||||||
color: isLightTheme ? Colors.black54 : Colors.white70
|
|
||||||
),
|
|
||||||
child: new DropDownButtonHideUnderline(child: label)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -337,10 +337,8 @@ class DropDownMenuItem<T> extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return new Container(
|
return new Container(
|
||||||
height: _kMenuItemHeight,
|
height: _kMenuItemHeight,
|
||||||
child: new Align(
|
align: FractionalOffset.centerLeft,
|
||||||
alignment: FractionalOffset.centerLeft,
|
child: child
|
||||||
child: child
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,20 +146,18 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
|
|||||||
);
|
);
|
||||||
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
|
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
|
||||||
final FractionalOffset titleAlignment = effectiveCenterTitle ? FractionalOffset.bottomCenter : FractionalOffset.bottomLeft;
|
final FractionalOffset titleAlignment = effectiveCenterTitle ? FractionalOffset.bottomCenter : FractionalOffset.bottomLeft;
|
||||||
children.add(new Padding(
|
children.add(new Container(
|
||||||
padding: new EdgeInsets.only(left: effectiveCenterTitle ? 0.0 : 72.0, bottom: 14.0),
|
padding: new EdgeInsets.only(left: effectiveCenterTitle ? 0.0 : 72.0, bottom: 14.0),
|
||||||
child: new Align(
|
align: new Tween<FractionalOffset>(
|
||||||
alignment: new Tween<FractionalOffset>(
|
begin: new FractionalOffset(0.0, yAlignStart),
|
||||||
begin: new FractionalOffset(0.0, yAlignStart),
|
end: new FractionalOffset(0.0, yAlignEnd)
|
||||||
end: new FractionalOffset(0.0, yAlignEnd)
|
).evaluate(scaleAndAlignCurve),
|
||||||
).evaluate(scaleAndAlignCurve),
|
child: new ScaleTransition(
|
||||||
child: new ScaleTransition(
|
alignment: titleAlignment,
|
||||||
|
scale: new Tween<double>(begin: 1.5, end: 1.0).animate(scaleAndAlignCurve),
|
||||||
|
child: new Align(
|
||||||
alignment: titleAlignment,
|
alignment: titleAlignment,
|
||||||
scale: new Tween<double>(begin: 1.5, end: 1.0).animate(scaleAndAlignCurve),
|
child: new DefaultTextStyle(style: titleStyle, child: config.title)
|
||||||
child: new Align(
|
|
||||||
alignment: titleAlignment,
|
|
||||||
child: new DefaultTextStyle(style: titleStyle, child: config.title)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
@ -154,10 +154,8 @@ class ListItem extends StatelessWidget {
|
|||||||
children.add(new Container(
|
children.add(new Container(
|
||||||
margin: const EdgeInsets.only(right: 16.0),
|
margin: const EdgeInsets.only(right: 16.0),
|
||||||
width: 40.0,
|
width: 40.0,
|
||||||
child: new Align(
|
align: FractionalOffset.centerLeft,
|
||||||
alignment: FractionalOffset.centerLeft,
|
child: leading
|
||||||
child: leading
|
|
||||||
)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,10 +186,8 @@ class ListItem extends StatelessWidget {
|
|||||||
if (trailing != null) {
|
if (trailing != null) {
|
||||||
children.add(new Container(
|
children.add(new Container(
|
||||||
margin: const EdgeInsets.only(left: 16.0),
|
margin: const EdgeInsets.only(left: 16.0),
|
||||||
child: new Align(
|
align: FractionalOffset.centerRight,
|
||||||
alignment: FractionalOffset.centerRight,
|
child: trailing
|
||||||
child: trailing
|
|
||||||
)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,22 +370,20 @@ class RefreshIndicatorState extends State<RefreshIndicator> {
|
|||||||
padding: _isIndicatorAtTop
|
padding: _isIndicatorAtTop
|
||||||
? new EdgeInsets.only(top: config.displacement)
|
? new EdgeInsets.only(top: config.displacement)
|
||||||
: new EdgeInsets.only(bottom: config.displacement),
|
: new EdgeInsets.only(bottom: config.displacement),
|
||||||
child: new Align(
|
align: _isIndicatorAtTop
|
||||||
alignment: _isIndicatorAtTop
|
? FractionalOffset.bottomCenter
|
||||||
? FractionalOffset.bottomCenter
|
: FractionalOffset.topCenter,
|
||||||
: FractionalOffset.topCenter,
|
child: new ScaleTransition(
|
||||||
child: new ScaleTransition(
|
scale: _scaleFactor,
|
||||||
scale: _scaleFactor,
|
child: new AnimatedBuilder(
|
||||||
child: new AnimatedBuilder(
|
animation: _sizeController,
|
||||||
animation: _sizeController,
|
builder: (BuildContext context, Widget child) {
|
||||||
builder: (BuildContext context, Widget child) {
|
return new RefreshProgressIndicator(
|
||||||
return new RefreshProgressIndicator(
|
value: showIndeterminateIndicator ? null : _value.value,
|
||||||
value: showIndeterminateIndicator ? null : _value.value,
|
valueColor: _valueColor,
|
||||||
valueColor: _valueColor,
|
backgroundColor: config.backgroundColor
|
||||||
backgroundColor: config.backgroundColor
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -74,6 +74,7 @@ class Container extends StatelessWidget {
|
|||||||
/// Creates a widget that combines common painting, positioning, and sizing widgets.
|
/// Creates a widget that combines common painting, positioning, and sizing widgets.
|
||||||
Container({
|
Container({
|
||||||
Key key,
|
Key key,
|
||||||
|
this.align,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.decoration,
|
this.decoration,
|
||||||
this.foregroundDecoration,
|
this.foregroundDecoration,
|
||||||
@ -99,6 +100,12 @@ class Container extends StatelessWidget {
|
|||||||
/// If null, the container will expand to fill all available space in its parent.
|
/// If null, the container will expand to fill all available space in its parent.
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
|
/// Align the child within the container.
|
||||||
|
///
|
||||||
|
/// If non-null, the container will expand to fill its parent and position its
|
||||||
|
/// child within itself according to the given value.
|
||||||
|
final FractionalOffset align;
|
||||||
|
|
||||||
/// Empty space to inscribe inside the decoration.
|
/// Empty space to inscribe inside the decoration.
|
||||||
final EdgeInsets padding;
|
final EdgeInsets padding;
|
||||||
|
|
||||||
@ -133,6 +140,9 @@ class Container extends StatelessWidget {
|
|||||||
if (child == null && (constraints == null || !constraints.isTight))
|
if (child == null && (constraints == null || !constraints.isTight))
|
||||||
current = new ConstrainedBox(constraints: const BoxConstraints.expand());
|
current = new ConstrainedBox(constraints: const BoxConstraints.expand());
|
||||||
|
|
||||||
|
if (align != null)
|
||||||
|
current = new Align(alignment: align, child: current);
|
||||||
|
|
||||||
EdgeInsets effectivePadding = _paddingIncludingDecoration;
|
EdgeInsets effectivePadding = _paddingIncludingDecoration;
|
||||||
if (effectivePadding != null)
|
if (effectivePadding != null)
|
||||||
current = new Padding(padding: effectivePadding, child: current);
|
current = new Padding(padding: effectivePadding, child: current);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user