Separate width and height parameters for Image widgets

This change makes it easier to defined only the width or the height of an image
and let the other value be filled in from the image's intrinsic aspect ratio.

Fixes #175
This commit is contained in:
Adam Barth 2015-07-21 13:46:10 -07:00
parent 310412fde5
commit 012b915704
5 changed files with 69 additions and 47 deletions

View file

@ -25,15 +25,15 @@ class Touch {
class RenderImageGrow extends RenderImage {
final Size _startingSize;
RenderImageGrow(Image image, Size size) : _startingSize = size, super(image, size);
RenderImageGrow(Image image, Size size)
: _startingSize = size, super(image: image, width: size.width, height: size.height);
double _growth = 0.0;
double get growth => _growth;
void set growth(double value) {
_growth = value;
double newWidth = _startingSize.width == null ? null : _startingSize.width + growth;
double newHeight = _startingSize.height == null ? null : _startingSize.height + growth;
requestedSize = new Size(newWidth, newHeight);
width = _startingSize.width == null ? null : _startingSize.width + growth;
height = _startingSize.height == null ? null : _startingSize.height + growth;
}
}

View file

@ -16,7 +16,8 @@ class ContainerApp extends App {
decoration: new BoxDecoration(backgroundColor: const Color(0xFFCCCCCC)),
child: new NetworkImage(
src: "https://www.dartlang.org/logos/dart-logo.png",
size: new Size(300.0, 300.0)
width: 300.0,
height: 300.0
)
),
new Container(

View file

@ -1249,9 +1249,10 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
class RenderImage extends RenderBox {
RenderImage(sky.Image image, Size requestedSize, { sky.ColorFilter colorFilter })
RenderImage({ sky.Image image, double width, double height, sky.ColorFilter colorFilter })
: _image = image,
_requestedSize = requestedSize,
_width = width,
_height = height,
_colorFilter = colorFilter;
sky.Image _image;
@ -1261,18 +1262,25 @@ class RenderImage extends RenderBox {
return;
_image = value;
markNeedsPaint();
if (_requestedSize.width == null || _requestedSize.height == null)
if (_width == null || _height == null)
markNeedsLayout();
}
Size _requestedSize;
Size get requestedSize => _requestedSize;
void set requestedSize (Size value) {
if (value == null)
value = const Size(null, null);
if (value == _requestedSize)
double _width;
double get width => _width;
void set width (double value) {
if (value == _width)
return;
_requestedSize = value;
_width = value;
markNeedsLayout();
}
double _height;
double get height => _height;
void set height (double value) {
if (value == _height)
return;
_height = value;
markNeedsLayout();
}
@ -1299,8 +1307,8 @@ class RenderImage extends RenderBox {
Size _sizeForConstraints(BoxConstraints constraints) {
// If there's no image, we can't size ourselves automatically
if (_image == null) {
double width = requestedSize.width == null ? 0.0 : requestedSize.width;
double height = requestedSize.height == null ? 0.0 : requestedSize.height;
double width = _width == null ? 0.0 : _width;
double height = _height == null ? 0.0 : _height;
return constraints.constrain(new Size(width, height));
}
@ -1310,8 +1318,8 @@ class RenderImage extends RenderBox {
// other dimension to maintain the aspect ratio. In both cases,
// constrain dimensions first, otherwise we end up losing the
// ratio after constraining.
if (requestedSize.width == null) {
if (requestedSize.height == null) {
if (_width == null) {
if (_height == null) {
// autosize
double width = constraints.constrainWidth(_image.width.toDouble());
double maxHeight = constraints.constrainHeight(_image.height.toDouble());
@ -1323,21 +1331,21 @@ class RenderImage extends RenderBox {
}
return constraints.constrain(new Size(width, height));
}
// determine width from height
double width = requestedSize.height * _image.width / _image.height;
return constraints.constrain(new Size(width, requestedSize.height));
// Determine width from height
double width = _height * _image.width / _image.height;
return constraints.constrain(new Size(width, height));
}
if (requestedSize.height == null) {
// determine height from width
double height = requestedSize.width * _image.height / _image.width;
return constraints.constrain(new Size(requestedSize.width, height));
if (_height == null) {
// Determine height from width
double height = _width * _image.height / _image.width;
return constraints.constrain(new Size(width, height));
}
}
return constraints.constrain(requestedSize);
return constraints.constrain(new Size(width, height));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (requestedSize.width == null && requestedSize.height == null)
if (_width == null && _height == null)
return constraints.constrainWidth(0.0);
return _sizeForConstraints(constraints).width;
}
@ -1347,7 +1355,7 @@ class RenderImage extends RenderBox {
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (requestedSize.width == null && requestedSize.height == null)
if (_width == null && _height == null)
return constraints.constrainHeight(0.0);
return _sizeForConstraints(constraints).height;
}
@ -1377,7 +1385,7 @@ class RenderImage extends RenderBox {
canvas.restore();
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}dimensions: ${requestedSize}\n';
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';
}
class RenderDecoratedBox extends RenderProxyBox {

View file

@ -488,31 +488,34 @@ class Text extends Component {
}
class Image extends LeafRenderObjectWrapper {
Image({ sky.Image image, this.size, this.colorFilter })
Image({ sky.Image image, this.width, this.height, this.colorFilter })
: image = image,
super(key: image.hashCode.toString()); // TODO(ianh): Find a way to uniquely identify the sky.Image rather than using hashCode, which could collide
final sky.Image image;
final Size size;
final double width;
final double height;
final sky.ColorFilter colorFilter;
RenderImage createNode() => new RenderImage(image, size, colorFilter: colorFilter);
RenderImage createNode() => new RenderImage(image: image, width: width, height: height, colorFilter: colorFilter);
RenderImage get root => super.root;
void syncRenderObject(Widget old) {
super.syncRenderObject(old);
root.image = image;
root.requestedSize = size;
root.width = width;
root.height = height;
root.colorFilter = colorFilter;
}
}
class FutureImage extends StatefulComponent {
FutureImage({ String key, this.image, this.size, this.colorFilter })
FutureImage({ String key, this.image, this.width, this.height, this.colorFilter })
: super(key: key);
Future<sky.Image> image;
Size size;
double width;
double height;
sky.ColorFilter colorFilter;
sky.Image _resolvedImage;
@ -535,48 +538,57 @@ class FutureImage extends StatefulComponent {
void syncFields(FutureImage source) {
bool needToResolveImage = (image != source.image);
image = source.image;
size = source.size;
width = source.width;
height = source.height;
if (needToResolveImage)
_resolveImage();
}
Widget build() {
return new Image(image: _resolvedImage, size: size, colorFilter: colorFilter);
return new Image(
image: _resolvedImage,
width: width,
height: height,
colorFilter: colorFilter
);
}
}
class NetworkImage extends Component {
NetworkImage({ String src, this.size, this.colorFilter })
: src = src,
super(key: src);
NetworkImage({ String src, this.width, this.height, this.colorFilter })
: src = src, super(key: src);
final String src;
final Size size;
final double width;
final double height;
final sky.ColorFilter colorFilter;
Widget build() {
return new FutureImage(
image: image_cache.load(src),
size: size,
width: width,
height: height,
colorFilter: colorFilter
);
}
}
class AssetImage extends Component {
AssetImage({ String name, this.bundle, this.size, this.colorFilter })
AssetImage({ String name, this.bundle, this.width, this.height, this.colorFilter })
: name = name,
super(key: name);
final String name;
final AssetBundle bundle;
final Size size;
final double width;
final double height;
final sky.ColorFilter colorFilter;
Widget build() {
return new FutureImage(
image: bundle.loadImage(name),
size: size,
width: width,
height: height,
colorFilter: colorFilter
);
}

View file

@ -93,7 +93,8 @@ class Icon extends Component {
return new AssetImage(
bundle: _iconBundle,
name: '${category}/${density}/ic_${subtype}_${colorSuffix}_${size}dp.png',
size: new Size(size.toDouble(), size.toDouble()),
width: size.toDouble(),
height: size.toDouble(),
colorFilter: colorFilter
);
}