Rename ImageFit to BoxFit (#8871)

This machinery is useful for arbitrary boxes (e.g., with FittedBox).

Fixes #6463
This commit is contained in:
Adam Barth 2017-03-17 15:21:55 -07:00 committed by GitHub
parent d1f4822e07
commit 5cf04b6141
26 changed files with 92 additions and 90 deletions

View file

@ -36,7 +36,7 @@ class SectionCard extends StatelessWidget {
opacity: 0.075,
child: new Image.asset(
section.backgroundAsset,
fit: ImageFit.cover,
fit: BoxFit.cover,
),
),
),
@ -129,7 +129,7 @@ class SectionDetailView extends StatelessWidget {
borderRadius: new BorderRadius.circular(6.0),
backgroundImage: new BackgroundImage(
image: new AssetImage(detail.imageAsset),
fit: ImageFit.cover,
fit: BoxFit.cover,
alignment: FractionalOffset.center,
),
),

View file

@ -149,7 +149,7 @@ class ContactsDemoState extends State<ContactsDemo> {
children: <Widget>[
new Image.asset(
'packages/flutter_gallery_assets/ali_connors.jpg',
fit: ImageFit.cover,
fit: BoxFit.cover,
height: _appBarHeight,
),
// This gradient ensures that the toolbar icons are distinct

View file

@ -63,7 +63,7 @@ class TravelDestinationItem extends StatelessWidget {
new Positioned.fill(
child: new Image.asset(
destination.assetName,
fit: ImageFit.cover,
fit: BoxFit.cover,
),
),
new Positioned(
@ -71,7 +71,7 @@ class TravelDestinationItem extends StatelessWidget {
left: 16.0,
right: 16.0,
child: new FittedBox(
fit: ImageFit.scaleDown,
fit: BoxFit.scaleDown,
alignment: FractionalOffset.centerLeft,
child: new Text(destination.title,
style: titleStyle,

View file

@ -50,7 +50,7 @@ class DualHeaderWithHint extends StatelessWidget {
child: new Container(
margin: const EdgeInsets.only(left: 24.0),
child: new FittedBox(
fit: ImageFit.scaleDown,
fit: BoxFit.scaleDown,
alignment: FractionalOffset.centerLeft,
child: new Text(
name,

View file

@ -44,7 +44,7 @@ class _GridTitleText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new FittedBox(
fit: ImageFit.scaleDown,
fit: BoxFit.scaleDown,
alignment: FractionalOffset.centerLeft,
child: new Text(text),
);
@ -131,7 +131,7 @@ class _GridPhotoViewerState extends State<GridPhotoViewer> with SingleTickerProv
..translate(_offset.dx, _offset.dy)
..scale(_scale),
child: new ClipRect(
child: new Image.asset(config.photo.assetName, fit: ImageFit.cover),
child: new Image.asset(config.photo.assetName, fit: BoxFit.cover),
),
),
);
@ -181,7 +181,7 @@ class GridDemoPhotoItem extends StatelessWidget {
child: new Hero(
key: new Key(photo.assetName),
tag: photo.tag,
child: new Image.asset(photo.assetName, fit: ImageFit.cover)
child: new Image.asset(photo.assetName, fit: BoxFit.cover)
)
);

View file

@ -99,7 +99,7 @@ class _CardDataItem extends StatelessWidget {
new SizedBox(
width: 144.0,
height: 144.0,
child: new Image.asset(data.imageAsset, fit: ImageFit.contain),
child: new Image.asset(data.imageAsset, fit: BoxFit.contain),
),
new Center(
child: new Text(data.title, style: Theme.of(context).textTheme.title),

View file

@ -218,7 +218,7 @@ class _PestoLogoState extends State<PestoLogo> {
children: <Widget>[
new Positioned.fromRect(
rect: _imageRectTween.lerp(config.t),
child: new Image.asset(_kSmallLogoImage, fit: ImageFit.contain),
child: new Image.asset(_kSmallLogoImage, fit: BoxFit.contain),
),
new Positioned.fromRect(
rect: _textRectTween.lerp(config.t),
@ -254,7 +254,7 @@ class RecipeCard extends StatelessWidget {
children: <Widget>[
new Hero(
tag: recipe.imagePath,
child: new Image.asset(recipe.imagePath, fit: ImageFit.contain)
child: new Image.asset(recipe.imagePath, fit: BoxFit.contain)
),
new Expanded(
child: new Row(
@ -325,7 +325,7 @@ class _RecipePageState extends State<RecipePage> {
tag: config.recipe.imagePath,
child: new Image.asset(
config.recipe.imagePath,
fit: fullWidth ? ImageFit.fitWidth : ImageFit.cover,
fit: fullWidth ? BoxFit.fitWidth : BoxFit.cover,
),
),
),
@ -437,7 +437,7 @@ class RecipeSheet extends StatelessWidget {
width: 32.0,
height: 32.0,
alignment: FractionalOffset.centerLeft,
fit: ImageFit.scaleDown
fit: BoxFit.scaleDown
)
),
new TableCell(

View file

@ -132,7 +132,7 @@ class VendorItem extends StatelessWidget {
width: 24.0,
child: new ClipRRect(
borderRadius: new BorderRadius.circular(12.0),
child: new Image.asset(vendor.avatarAsset, fit: ImageFit.cover),
child: new Image.asset(vendor.avatarAsset, fit: BoxFit.cover),
),
),
const SizedBox(width: 8.0),
@ -260,7 +260,7 @@ class FeatureItem extends StatelessWidget {
minHeight: 340.0,
maxHeight: 340.0,
alignment: FractionalOffset.topRight,
child: new Image.asset(product.imageAsset, fit: ImageFit.cover),
child: new Image.asset(product.imageAsset, fit: BoxFit.cover),
),
),
),
@ -320,7 +320,7 @@ class ProductItem extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Hero(
tag: product.tag,
child: new Image.asset(product.imageAsset, fit: ImageFit.contain),
child: new Image.asset(product.imageAsset, fit: BoxFit.contain),
),
),
new Padding(

View file

@ -39,7 +39,7 @@ class OrderItem extends StatelessWidget {
height: 248.0,
child: new Hero(
tag: product.tag,
child: new Image.asset(product.imageAsset, fit: ImageFit.contain),
child: new Image.asset(product.imageAsset, fit: BoxFit.contain),
),
),
),
@ -212,7 +212,7 @@ class _OrderPageState extends State<OrderPage> {
elevation: 1,
child: new Image.asset(
product.imageAsset,
fit: ImageFit.contain,
fit: BoxFit.contain,
),
);
}).toList(),

View file

@ -220,7 +220,7 @@ new GridView.count(
footer: new GridTileBar(
title: new Text(url)
),
child: new Image.network(url, fit: ImageFit.cover)
child: new Image.network(url, fit: BoxFit.cover)
);
}).toList(),
);

View file

@ -53,7 +53,7 @@ class _AppBarBackground extends StatelessWidget {
bottom: 0.0,
child: new Image.asset(
layer.assetName,
fit: ImageFit.cover,
fit: BoxFit.cover,
height: _kFlexibleSpaceMaxHeight
)
);

View file

@ -18,13 +18,13 @@
library painting;
export 'src/painting/basic_types.dart';
export 'src/painting/box_fit.dart';
export 'src/painting/box_painter.dart';
export 'src/painting/colors.dart';
export 'src/painting/decoration.dart';
export 'src/painting/edge_insets.dart';
export 'src/painting/flutter_logo.dart';
export 'src/painting/fractional_offset.dart';
export 'src/painting/image_fit.dart';
export 'src/painting/text_editing.dart';
export 'src/painting/text_painter.dart';
export 'src/painting/text_span.dart';

View file

@ -44,7 +44,7 @@ class FlexibleSpaceBar extends StatefulWidget {
/// Shown behind the [title] when expanded.
///
/// Typically an [AssetImage] widget with [AssetImage.fit] set to [ImageFit.cover].
/// Typically an [AssetImage] widget with [AssetImage.fit] set to [BoxFit.cover].
final Widget background;
/// Whether the title should be centered.

View file

@ -71,7 +71,7 @@ class ImageIcon extends StatelessWidget {
width: iconSize,
height: iconSize,
color: iconColor,
fit: ImageFit.scaleDown,
fit: BoxFit.scaleDown,
alignment: FractionalOffset.center
);
}

View file

@ -6,41 +6,43 @@ import 'dart:math' as math;
import 'basic_types.dart';
/// How an image should be inscribed into a box.
/// How a box should be inscribed into another box.
///
/// See also [applyImageFit], which applies the sizing semantics of these values
/// See also [applyBoxFit], which applies the sizing semantics of these values
/// (though not the alignment semantics).
enum ImageFit {
/// Fill the box by distorting the image's aspect ratio.
enum BoxFit {
/// Fill the target box by distorting the source's aspect ratio.
fill,
/// As large as possible while still containing the image entirely within the box.
/// As large as possible while still containing the source entirely within the
/// target box.
contain,
/// As small as possible while still covering the entire box.
/// As small as possible while still covering the entire target box.
cover,
/// Make sure the full width of the image is shown, regardless of
/// whether this means the image overflows the box vertically.
/// Make sure the full width of the source is shown, regardless of
/// whether this means the source overflows the target box vertically.
fitWidth,
/// Make sure the full height of the image is shown, regardless of
/// whether this means the image overflows the box horizontally.
/// Make sure the full height of the source is shown, regardless of
/// whether this means the source overflows the target box horizontally.
fitHeight,
/// Center the image within the box and discard any portions of the image that
/// lie outside the box.
/// Align the source within the target box (by default, centering) and discard
/// any portions of the source that lie outside the box.
none,
/// Center the image within the box and, if necessary, scale the image down to
/// ensure that the image fits within the box.
/// Align the source within the target box (by default, centering) and, if
/// necessary, scale the source down to ensure that the source fits within the
/// box.
scaleDown
}
/// The pair of sizes returned by [applyImageFit].
/// The pair of sizes returned by [applyBoxFit].
class FittedSizes {
/// Creates an object to store a pair of sizes,
/// as would be returned by [applyImageFit].
/// as would be returned by [applyBoxFit].
const FittedSizes(this.source, this.destination);
/// The size of the part of the input to show on the output.
@ -50,62 +52,62 @@ class FittedSizes {
final Size destination;
}
/// Apply an [ImageFit] value.
/// Apply an [BoxFit] value.
///
/// The arguments to this method, in addition to the [ImageFit] value to apply,
/// are two sizes, ostensibly the sizes of an input image and an output canvas.
/// Specifically, the `inputSize` argument gives the size of the complete image
/// The arguments to this method, in addition to the [BoxFit] value to apply,
/// are two sizes, ostensibly the sizes of an input box and an output box.
/// Specifically, the `inputSize` argument gives the size of the complete source
/// that is being fitted, and the `outputSize` gives the size of the rectangle
/// into which the image is to be drawn.
/// into which the source is to be drawn.
///
/// This function then returns two sizes, combined into a single [FittedSizes]
/// object.
///
/// The [FittedSizes.source] size is the subpart of the `inputSize` that is to
/// be shown. If the entire input image is shown, then this will equal the
/// `inputSize`, but if the input image is to be cropped down, this may be
/// be shown. If the entire input source is shown, then this will equal the
/// `inputSize`, but if the input source is to be cropped down, this may be
/// smaller.
///
/// The [FittedSizes.destination] size is the subpart of the `outputSize` in
/// which to paint the (possibly cropped) input image. If the
/// which to paint the (possibly cropped) source. If the
/// [FittedSizes.destination] size is smaller than the `outputSize` then the
/// input image is being letterboxed (or pillarboxed).
/// source is being letterboxed (or pillarboxed).
///
/// This method does not express an opinion regarding the alignment of the
/// source and destination sizes within the input and output rectangles.
/// Typically they are centered (this is what [BoxDecoration] does, for
/// instance, and is how [ImageFit] is defined). The [FractionalOffset] class
/// instance, and is how [BoxFit] is defined). The [FractionalOffset] class
/// provides a convenience function, [FractionalOffset.inscribe], for resolving
/// the sizes to rects, as shown in the example below.
///
/// == Example ==
///
/// This example paints an [Image] `image` onto the [Rect] `outputRect` on a
/// [Canvas] `canvas`, using a [Paint] paint, applying the [ImageFit] algorithm
/// [Canvas] `canvas`, using a [Paint] paint, applying the [BoxFit] algorithm
/// `fit`:
///
/// ```dart
/// final Size imageSize = new Size(image.width.toDouble(), image.height.toDouble());
/// final FittedSizes sizes = applyImageFit(fit, imageSize, outputRect.size);
/// final FittedSizes sizes = applyBoxFit(fit, imageSize, outputRect.size);
/// final Rect inputSubrect = FractionalOffset.center.inscribe(sizes.source, Point.origin & imageSize);
/// final Rect outputSubrect = FractionalOffset.center.inscribe(sizes.destination, outputRect);
/// canvas.drawImageRect(image, inputSubrect, outputSubrect, paint);
/// ```
FittedSizes applyImageFit(ImageFit fit, Size inputSize, Size outputSize) {
FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) {
Size sourceSize, destinationSize;
switch (fit) {
case ImageFit.fill:
case BoxFit.fill:
sourceSize = inputSize;
destinationSize = outputSize;
break;
case ImageFit.contain:
case BoxFit.contain:
sourceSize = inputSize;
if (outputSize.width / outputSize.height > sourceSize.width / sourceSize.height)
destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, outputSize.height);
else
destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
break;
case ImageFit.cover:
case BoxFit.cover:
if (outputSize.width / outputSize.height > inputSize.width / inputSize.height) {
sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width);
} else {
@ -113,20 +115,20 @@ FittedSizes applyImageFit(ImageFit fit, Size inputSize, Size outputSize) {
}
destinationSize = outputSize;
break;
case ImageFit.fitWidth:
case BoxFit.fitWidth:
sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width);
destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
break;
case ImageFit.fitHeight:
case BoxFit.fitHeight:
sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, inputSize.height);
destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, outputSize.height);
break;
case ImageFit.none:
case BoxFit.none:
sourceSize = new Size(math.min(inputSize.width, outputSize.width),
math.min(inputSize.height, outputSize.height));
destinationSize = sourceSize;
break;
case ImageFit.scaleDown:
case BoxFit.scaleDown:
sourceSize = inputSize;
destinationSize = inputSize;
final double aspectRatio = inputSize.width / inputSize.height;

View file

@ -9,10 +9,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'basic_types.dart';
import 'box_fit.dart';
import 'decoration.dart';
import 'edge_insets.dart';
import 'fractional_offset.dart';
import 'image_fit.dart';
export 'edge_insets.dart' show EdgeInsets;
@ -894,7 +894,7 @@ void paintImage({
@required Rect rect,
@required ui.Image image,
ColorFilter colorFilter,
ImageFit fit,
BoxFit fit,
ImageRepeat repeat: ImageRepeat.noRepeat,
Rect centerSlice,
FractionalOffset alignment
@ -912,9 +912,9 @@ void paintImage({
outputSize -= sliceBorder;
inputSize -= sliceBorder;
}
fit ??= centerSlice == null ? ImageFit.scaleDown : ImageFit.fill;
assert(centerSlice == null || (fit != ImageFit.none && fit != ImageFit.cover));
final FittedSizes fittedSizes = applyImageFit(fit, inputSize, outputSize);
fit ??= centerSlice == null ? BoxFit.scaleDown : BoxFit.fill;
assert(centerSlice == null || (fit != BoxFit.none && fit != BoxFit.cover));
final FittedSizes fittedSizes = applyBoxFit(fit, inputSize, outputSize);
final Size sourceSize = fittedSizes.source;
Size destinationSize = fittedSizes.destination;
if (centerSlice != null) {
@ -984,7 +984,7 @@ class BackgroundImage {
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
final ImageFit fit;
final BoxFit fit;
/// How to paint any portions of the box not covered by the background image.
final ImageRepeat repeat;

View file

@ -9,9 +9,9 @@ import 'dart:ui' as ui show Gradient, TextBox, lerpDouble;
import 'package:flutter/services.dart';
import 'basic_types.dart';
import 'box_fit.dart';
import 'decoration.dart';
import 'fractional_offset.dart';
import 'image_fit.dart';
import 'text_editing.dart';
import 'text_painter.dart';
import 'text_span.dart';
@ -395,7 +395,7 @@ class _FlutterLogoPainter extends BoxPainter {
// only the mark
logoSize = const Size(202.0, 202.0);
}
final FittedSizes fittedSize = applyImageFit(ImageFit.contain, logoSize, canvasSize);
final FittedSizes fittedSize = applyBoxFit(BoxFit.contain, logoSize, canvasSize);
assert(fittedSize.source == logoSize);
final Rect rect = FractionalOffset.center.inscribe(fittedSize.destination, offset & canvasSize);
final double centerSquareHeight = canvasSize.shortestSide;

View file

@ -8,7 +8,7 @@ import 'box.dart';
import 'object.dart';
export 'package:flutter/painting.dart' show
ImageFit,
BoxFit,
ImageRepeat;
/// An image in the render tree.
@ -26,7 +26,7 @@ class RenderImage extends RenderBox {
double height,
double scale: 1.0,
Color color,
ImageFit fit,
BoxFit fit,
FractionalOffset alignment,
ImageRepeat repeat: ImageRepeat.noRepeat,
Rect centerSlice
@ -118,9 +118,9 @@ class RenderImage extends RenderBox {
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
ImageFit get fit => _fit;
ImageFit _fit;
set fit(ImageFit value) {
BoxFit get fit => _fit;
BoxFit _fit;
set fit(BoxFit value) {
if (value == _fit)
return;
_fit = value;

View file

@ -1597,7 +1597,7 @@ class RenderFittedBox extends RenderProxyBox {
/// The [fit] and [alignment] arguments must not be null.
RenderFittedBox({
RenderBox child,
ImageFit fit: ImageFit.contain,
BoxFit fit: BoxFit.contain,
FractionalOffset alignment: FractionalOffset.center
}) : _fit = fit, _alignment = alignment, super(child) {
assert(fit != null);
@ -1605,9 +1605,9 @@ class RenderFittedBox extends RenderProxyBox {
}
/// How to inscribe the child into the space allocated during layout.
ImageFit get fit => _fit;
ImageFit _fit;
set fit(ImageFit value) {
BoxFit get fit => _fit;
BoxFit _fit;
set fit(BoxFit value) {
assert(value != null);
if (_fit == value)
return;
@ -1660,7 +1660,7 @@ class RenderFittedBox extends RenderProxyBox {
_transform = new Matrix4.identity();
} else {
final Size childSize = child.size;
final FittedSizes sizes = applyImageFit(_fit, childSize, size);
final FittedSizes sizes = applyBoxFit(_fit, childSize, size);
final double scaleX = sizes.destination.width / sizes.source.width;
final double scaleY = sizes.destination.height / sizes.source.height;
final Rect sourceRect = _alignment.inscribe(sizes.source, Point.origin & childSize);

View file

@ -554,7 +554,7 @@ class FittedBox extends SingleChildRenderObjectWidget {
/// The [fit] and [alignment] arguments must not be null.
FittedBox({
Key key,
this.fit: ImageFit.contain,
this.fit: BoxFit.contain,
this.alignment: FractionalOffset.center,
Widget child
}) : super(key: key, child: child) {
@ -563,7 +563,7 @@ class FittedBox extends SingleChildRenderObjectWidget {
}
/// How to inscribe the child into the space allocated during layout.
final ImageFit fit;
final BoxFit fit;
/// How to align the child within its parent's bounds.
///
@ -2489,7 +2489,7 @@ class RawImage extends LeafRenderObjectWidget {
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
final ImageFit fit;
final BoxFit fit;
/// How to align the image within its bounds.
///

View file

@ -163,7 +163,7 @@ class Image extends StatefulWidget {
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
final ImageFit fit;
final BoxFit fit;
/// How to align the image within its bounds.
///

View file

@ -10,19 +10,19 @@ void main() {
test('applyImageFit', () {
FittedSizes result;
result = applyImageFit(ImageFit.scaleDown, const Size(100.0, 1000.0), const Size(200.0, 2000.0));
result = applyBoxFit(BoxFit.scaleDown, const Size(100.0, 1000.0), const Size(200.0, 2000.0));
expect(result.source, equals(const Size(100.0, 1000.0)));
expect(result.destination, equals(const Size(100.0, 1000.0)));
result = applyImageFit(ImageFit.scaleDown, const Size(300.0, 3000.0), const Size(200.0, 2000.0));
result = applyBoxFit(BoxFit.scaleDown, const Size(300.0, 3000.0), const Size(200.0, 2000.0));
expect(result.source, equals(const Size(300.0, 3000.0)));
expect(result.destination, equals(const Size(200.0, 2000.0)));
result = applyImageFit(ImageFit.fitWidth, const Size(2000.0, 400.0), const Size(1000.0, 100.0));
result = applyBoxFit(BoxFit.fitWidth, const Size(2000.0, 400.0), const Size(1000.0, 100.0));
expect(result.source, equals(const Size(2000.0, 200.0)));
expect(result.destination, equals(const Size(1000.0, 100.0)));
result = applyImageFit(ImageFit.fitHeight, const Size(400.0, 2000.0), const Size(100.0, 1000.0));
result = applyBoxFit(BoxFit.fitHeight, const Size(400.0, 2000.0), const Size(100.0, 1000.0));
expect(result.source, equals(const Size(200.0, 2000.0)));
expect(result.destination, equals(const Size(100.0, 1000.0)));
});

View file

@ -38,7 +38,7 @@ void main() {
canvas: canvas,
rect: new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0),
image: image,
fit: ImageFit.cover,
fit: BoxFit.cover,
alignment: const FractionalOffset(0.0, 0.5)
);

View file

@ -88,7 +88,7 @@ void main() {
height: 200.0,
child: new FittedBox(
key: outside,
fit: ImageFit.cover,
fit: BoxFit.cover,
child: new Container(
key: inside,
width: 100.0,

View file

@ -124,7 +124,7 @@ Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize) {
image: new TestAssetImage(image),
height: imageSize,
width: imageSize,
fit: ImageFit.fill
fit: BoxFit.fill
)
)
)

View file

@ -772,7 +772,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
/// A [ViewConfiguration] that pretends the display is of a particular size. The
/// size is in logical pixels. The resulting ViewConfiguration maps the given
/// size onto the actual display using the [ImageFit.contain] algorithm.
/// size onto the actual display using the [BoxFit.contain] algorithm.
class TestViewConfiguration extends ViewConfiguration {
/// Creates a [TestViewConfiguration] with the given size. Defaults to 800x600.
TestViewConfiguration({ Size size: _kDefaultTestViewportSize })