mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Changed the pageable_list.dart example: tapping on the toolbar changes the scroll direction. This exposed some problems: - Scrollable.syncFields() didn't update scrollDirection - Viewport updated its RenderObject fields in the wrong order - FixedHeightScrollable scrollDirection changes didn't update the scrollBehavior There may be similar problems with VariableHeightList and ScrollableViewport. I will fix those in a separate CL.
749 lines
21 KiB
Dart
749 lines
21 KiB
Dart
// 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 'dart:sky' as sky;
|
|
|
|
import 'package:vector_math/vector_math.dart';
|
|
|
|
import 'package:sky/base/image_resource.dart';
|
|
import 'package:sky/mojo/asset_bundle.dart';
|
|
import 'package:sky/mojo/net/image_cache.dart' as image_cache;
|
|
import 'package:sky/painting/text_style.dart';
|
|
import 'package:sky/painting/paragraph_painter.dart';
|
|
import 'package:sky/rendering/block.dart';
|
|
import 'package:sky/rendering/box.dart';
|
|
import 'package:sky/rendering/flex.dart';
|
|
import 'package:sky/rendering/image.dart';
|
|
import 'package:sky/rendering/object.dart';
|
|
import 'package:sky/rendering/paragraph.dart';
|
|
import 'package:sky/rendering/proxy_box.dart';
|
|
import 'package:sky/rendering/shifted_box.dart';
|
|
import 'package:sky/rendering/stack.dart';
|
|
import 'package:sky/rendering/viewport.dart';
|
|
import 'package:sky/widgets/default_text_style.dart';
|
|
import 'package:sky/widgets/framework.dart';
|
|
|
|
export 'package:sky/base/hit_test.dart' show EventDisposition, combineEventDispositions;
|
|
export 'package:sky/painting/text_style.dart';
|
|
export 'package:sky/rendering/block.dart' show BlockDirection;
|
|
export 'package:sky/rendering/box.dart' show BoxConstraints;
|
|
export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems;
|
|
export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
|
|
export 'package:sky/rendering/proxy_box.dart' show BackgroundImage, BoxDecoration, BoxDecorationPosition, BoxShadow, Border, BorderSide, EdgeDims, Shape;
|
|
export 'package:sky/rendering/toggleable.dart' show ValueChanged;
|
|
export 'package:sky/rendering/viewport.dart' show ScrollDirection;
|
|
export 'package:sky/widgets/framework.dart' show Key, GlobalKey, Widget, Component, StatefulComponent, App, runApp, Listener, ParentDataNode;
|
|
|
|
// PAINTING NODES
|
|
|
|
class Opacity extends OneChildRenderObjectWrapper {
|
|
Opacity({ Key key, this.opacity, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double opacity;
|
|
|
|
RenderOpacity createNode() => new RenderOpacity(opacity: opacity);
|
|
RenderOpacity get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Opacity old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.opacity = opacity;
|
|
}
|
|
}
|
|
|
|
class ColorFilter extends OneChildRenderObjectWrapper {
|
|
ColorFilter({ Key key, this.color, this.transferMode, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final Color color;
|
|
final sky.TransferMode transferMode;
|
|
|
|
RenderColorFilter createNode() => new RenderColorFilter(color: color, transferMode: transferMode);
|
|
RenderColorFilter get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(ColorFilter old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.color = color;
|
|
renderObject.transferMode = transferMode;
|
|
}
|
|
}
|
|
|
|
class DecoratedBox extends OneChildRenderObjectWrapper {
|
|
DecoratedBox({
|
|
Key key,
|
|
this.decoration,
|
|
this.position: BoxDecorationPosition.background,
|
|
Widget child
|
|
}) : super(key: key, child: child);
|
|
|
|
final BoxDecoration decoration;
|
|
final BoxDecorationPosition position;
|
|
|
|
RenderDecoratedBox createNode() => new RenderDecoratedBox(decoration: decoration, position: position);
|
|
RenderDecoratedBox get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(DecoratedBox old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.decoration = decoration;
|
|
renderObject.position = position;
|
|
}
|
|
}
|
|
|
|
class CustomPaint extends OneChildRenderObjectWrapper {
|
|
CustomPaint({ Key key, this.callback, this.token, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final CustomPaintCallback callback;
|
|
final dynamic token; // set this to be repainted automatically when the token changes
|
|
|
|
RenderCustomPaint createNode() => new RenderCustomPaint(callback: callback);
|
|
RenderCustomPaint get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(CustomPaint old) {
|
|
super.syncRenderObject(old);
|
|
if (old != null && old.token != token)
|
|
renderObject.markNeedsPaint();
|
|
renderObject.callback = callback;
|
|
}
|
|
|
|
void remove() {
|
|
renderObject.callback = null;
|
|
super.remove();
|
|
}
|
|
}
|
|
|
|
class ClipRect extends OneChildRenderObjectWrapper {
|
|
ClipRect({ Key key, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
RenderClipRect createNode() => new RenderClipRect();
|
|
RenderClipRect get renderObject => super.renderObject;
|
|
|
|
// Nothing to sync, so we don't implement syncRenderObject()
|
|
}
|
|
|
|
class ClipRRect extends OneChildRenderObjectWrapper {
|
|
ClipRRect({ Key key, this.xRadius, this.yRadius, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double xRadius;
|
|
final double yRadius;
|
|
|
|
RenderClipRRect createNode() => new RenderClipRRect(xRadius: xRadius, yRadius: yRadius);
|
|
RenderClipRRect get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(ClipRRect old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.xRadius = xRadius;
|
|
renderObject.yRadius = yRadius;
|
|
}
|
|
}
|
|
|
|
class ClipOval extends OneChildRenderObjectWrapper {
|
|
ClipOval({ Key key, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
RenderClipOval createNode() => new RenderClipOval();
|
|
RenderClipOval get renderObject => super.renderObject;
|
|
|
|
// Nothing to sync, so we don't implement syncRenderObject()
|
|
}
|
|
|
|
|
|
// POSITIONING AND SIZING NODES
|
|
|
|
class Transform extends OneChildRenderObjectWrapper {
|
|
Transform({ Key key, this.transform, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final Matrix4 transform;
|
|
|
|
RenderTransform createNode() => new RenderTransform(transform: transform);
|
|
RenderTransform get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Transform old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.transform = transform;
|
|
}
|
|
}
|
|
|
|
class Padding extends OneChildRenderObjectWrapper {
|
|
Padding({ Key key, this.padding, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final EdgeDims padding;
|
|
|
|
RenderPadding createNode() => new RenderPadding(padding: padding);
|
|
RenderPadding get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Padding old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.padding = padding;
|
|
}
|
|
}
|
|
|
|
class Center extends OneChildRenderObjectWrapper {
|
|
Center({ Key key, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
RenderPositionedBox createNode() => new RenderPositionedBox();
|
|
RenderPositionedBox get renderObject => super.renderObject;
|
|
|
|
// Nothing to sync, so we don't implement syncRenderObject()
|
|
}
|
|
|
|
class SizedBox extends OneChildRenderObjectWrapper {
|
|
SizedBox({ Key key, this.width, this.height, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double width;
|
|
final double height;
|
|
|
|
RenderConstrainedBox createNode() => new RenderConstrainedBox(additionalConstraints: _additionalConstraints());
|
|
RenderConstrainedBox get renderObject => super.renderObject;
|
|
|
|
BoxConstraints _additionalConstraints() {
|
|
BoxConstraints result = const BoxConstraints();
|
|
if (width != null)
|
|
result = result.applyWidth(width);
|
|
if (height != null)
|
|
result = result.applyHeight(height);
|
|
return result;
|
|
}
|
|
|
|
void syncRenderObject(SizedBox old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.additionalConstraints = _additionalConstraints();
|
|
}
|
|
}
|
|
|
|
class ConstrainedBox extends OneChildRenderObjectWrapper {
|
|
ConstrainedBox({ Key key, this.constraints, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final BoxConstraints constraints;
|
|
|
|
RenderConstrainedBox createNode() => new RenderConstrainedBox(additionalConstraints: constraints);
|
|
RenderConstrainedBox get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(ConstrainedBox old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.additionalConstraints = constraints;
|
|
}
|
|
}
|
|
|
|
class AspectRatio extends OneChildRenderObjectWrapper {
|
|
AspectRatio({ Key key, this.aspectRatio, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double aspectRatio;
|
|
|
|
RenderAspectRatio createNode() => new RenderAspectRatio(aspectRatio: aspectRatio);
|
|
RenderAspectRatio get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(AspectRatio old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.aspectRatio = aspectRatio;
|
|
}
|
|
}
|
|
|
|
class ShrinkWrapWidth extends OneChildRenderObjectWrapper {
|
|
ShrinkWrapWidth({ Key key, this.stepWidth, this.stepHeight, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double stepWidth;
|
|
final double stepHeight;
|
|
|
|
RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth();
|
|
RenderShrinkWrapWidth get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(ShrinkWrapWidth old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.stepWidth = stepWidth;
|
|
renderObject.stepHeight = stepHeight;
|
|
}
|
|
}
|
|
|
|
class Baseline extends OneChildRenderObjectWrapper {
|
|
Baseline({ Key key, this.baseline, this.baselineType: TextBaseline.alphabetic, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final double baseline; // in pixels
|
|
final TextBaseline baselineType;
|
|
|
|
RenderBaseline createNode() => new RenderBaseline(baseline: baseline, baselineType: baselineType);
|
|
RenderBaseline get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Baseline old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.baseline = baseline;
|
|
renderObject.baselineType = baselineType;
|
|
}
|
|
}
|
|
|
|
class Viewport extends OneChildRenderObjectWrapper {
|
|
Viewport({
|
|
Key key,
|
|
this.scrollDirection: ScrollDirection.vertical,
|
|
this.scrollOffset: Offset.zero,
|
|
Widget child
|
|
}) : super(key: key, child: child);
|
|
|
|
final ScrollDirection scrollDirection;
|
|
final Offset scrollOffset;
|
|
|
|
RenderViewport createNode() => new RenderViewport(scrollDirection: scrollDirection, scrollOffset: scrollOffset);
|
|
RenderViewport get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Viewport old) {
|
|
super.syncRenderObject(old);
|
|
// Order dependency: RenderViewport validates scrollOffset based on scrollDirection.
|
|
renderObject.scrollDirection = scrollDirection;
|
|
renderObject.scrollOffset = scrollOffset;
|
|
}
|
|
}
|
|
|
|
class SizeObserver extends OneChildRenderObjectWrapper {
|
|
SizeObserver({ Key key, this.callback, Widget child })
|
|
: super(key: key, child: child);
|
|
|
|
final SizeChangedCallback callback;
|
|
|
|
RenderSizeObserver createNode() => new RenderSizeObserver(callback: callback);
|
|
RenderSizeObserver get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(SizeObserver old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.callback = callback;
|
|
}
|
|
|
|
void remove() {
|
|
renderObject.callback = null;
|
|
super.remove();
|
|
}
|
|
}
|
|
|
|
|
|
// CONVENIENCE CLASS TO COMBINE COMMON PAINTING, POSITIONING, AND SIZING NODES
|
|
|
|
class Container extends Component {
|
|
|
|
Container({
|
|
Key key,
|
|
this.child,
|
|
this.constraints,
|
|
this.decoration,
|
|
this.foregroundDecoration,
|
|
this.width,
|
|
this.height,
|
|
this.margin,
|
|
this.padding,
|
|
this.transform
|
|
}) : super(key: key);
|
|
|
|
final Widget child;
|
|
final BoxConstraints constraints;
|
|
final BoxDecoration decoration;
|
|
final BoxDecoration foregroundDecoration;
|
|
final EdgeDims margin;
|
|
final EdgeDims padding;
|
|
final Matrix4 transform;
|
|
final double width;
|
|
final double height;
|
|
|
|
EdgeDims get _paddingIncludingBorder {
|
|
if (decoration == null || decoration.border == null)
|
|
return padding;
|
|
EdgeDims borderPadding = decoration.border.dimensions;
|
|
if (padding == null)
|
|
return borderPadding;
|
|
return padding + borderPadding;
|
|
}
|
|
|
|
Widget build() {
|
|
Widget current = child;
|
|
|
|
if (child == null && (width == null || height == null))
|
|
current = new ConstrainedBox(constraints: BoxConstraints.expand);
|
|
|
|
EdgeDims effectivePadding = _paddingIncludingBorder;
|
|
if (effectivePadding != null)
|
|
current = new Padding(padding: effectivePadding, child: current);
|
|
|
|
if (decoration != null)
|
|
current = new DecoratedBox(decoration: decoration, child: current);
|
|
|
|
if (foregroundDecoration != null) {
|
|
current = new DecoratedBox(
|
|
decoration: foregroundDecoration,
|
|
position: BoxDecorationPosition.foreground,
|
|
child: current
|
|
);
|
|
}
|
|
|
|
if (width != null || height != null) {
|
|
current = new SizedBox(
|
|
width: width,
|
|
height: height,
|
|
child: current
|
|
);
|
|
}
|
|
|
|
if (constraints != null)
|
|
current = new ConstrainedBox(constraints: constraints, child: current);
|
|
|
|
if (margin != null)
|
|
current = new Padding(padding: margin, child: current);
|
|
|
|
if (transform != null)
|
|
current = new Transform(transform: transform, child: current);
|
|
|
|
return current;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// LAYOUT NODES
|
|
|
|
class Block extends MultiChildRenderObjectWrapper {
|
|
Block(List<Widget> children, {
|
|
Key key,
|
|
this.direction: BlockDirection.vertical
|
|
}) : super(key: key, children: children);
|
|
|
|
final BlockDirection direction;
|
|
|
|
RenderBlock createNode() => new RenderBlock(direction: direction);
|
|
RenderBlock get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Widget old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.direction = direction;
|
|
}
|
|
}
|
|
|
|
class Stack extends MultiChildRenderObjectWrapper {
|
|
Stack(List<Widget> children, { Key key })
|
|
: super(key: key, children: children);
|
|
|
|
RenderStack createNode() => new RenderStack();
|
|
RenderStack get renderObject => super.renderObject;
|
|
}
|
|
|
|
class Positioned extends ParentDataNode {
|
|
Positioned({
|
|
Key key,
|
|
Widget child,
|
|
double top,
|
|
double right,
|
|
double bottom,
|
|
double left
|
|
}) : super(child,
|
|
new StackParentData()..top = top
|
|
..right = right
|
|
..bottom = bottom
|
|
..left = left,
|
|
key: key);
|
|
}
|
|
|
|
class Flex extends MultiChildRenderObjectWrapper {
|
|
|
|
Flex(List<Widget> children, {
|
|
Key key,
|
|
this.direction: FlexDirection.horizontal,
|
|
this.justifyContent: FlexJustifyContent.start,
|
|
this.alignItems: FlexAlignItems.center,
|
|
this.textBaseline
|
|
}) : super(key: key, children: children);
|
|
|
|
final FlexDirection direction;
|
|
final FlexJustifyContent justifyContent;
|
|
final FlexAlignItems alignItems;
|
|
final TextBaseline textBaseline;
|
|
|
|
RenderFlex createNode() => new RenderFlex(direction: direction);
|
|
RenderFlex get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Widget old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.direction = direction;
|
|
renderObject.justifyContent = justifyContent;
|
|
renderObject.alignItems = alignItems;
|
|
renderObject.textBaseline = textBaseline;
|
|
}
|
|
|
|
}
|
|
|
|
class Flexible extends ParentDataNode {
|
|
Flexible({ Key key, int flex: 1, Widget child })
|
|
: super(child, new FlexBoxParentData()..flex = flex, key: key);
|
|
}
|
|
|
|
class Paragraph extends LeafRenderObjectWrapper {
|
|
Paragraph({ Key key, this.text }) : super(key: key);
|
|
|
|
final TextSpan text;
|
|
|
|
RenderParagraph createNode() => new RenderParagraph(text);
|
|
RenderParagraph get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Widget old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.text = text;
|
|
}
|
|
}
|
|
|
|
class StyledText extends Component {
|
|
// elements ::= "string" | [<text-style> <elements>*]
|
|
// Where "string" is text to display and text-style is an instance of
|
|
// TextStyle. The text-style applies to all of the elements that follow.
|
|
StyledText({ this.elements, Key key }) : super(key: key) {
|
|
assert(_toSpan(elements) != null);
|
|
}
|
|
|
|
final dynamic elements;
|
|
|
|
TextSpan _toSpan(dynamic element) {
|
|
if (element is String)
|
|
return new PlainTextSpan(element);
|
|
if (element is Iterable) {
|
|
dynamic first = element.first;
|
|
if (first is! TextStyle)
|
|
throw new ArgumentError("First element of Iterable is a ${first.runtimeType} not a TextStyle");
|
|
return new StyledTextSpan(first, element.skip(1).map(_toSpan).toList());
|
|
}
|
|
throw new ArgumentError("Element is ${element.runtimeType} not a String or an Iterable");
|
|
}
|
|
|
|
Widget build() {
|
|
return new Paragraph(text: _toSpan(elements));
|
|
}
|
|
}
|
|
|
|
class Text extends Component {
|
|
Text(this.data, { Key key, TextStyle this.style }) : super(key: key);
|
|
|
|
final String data;
|
|
final TextStyle style;
|
|
|
|
Widget build() {
|
|
TextSpan text = new PlainTextSpan(data);
|
|
TextStyle defaultStyle = DefaultTextStyle.of(this);
|
|
TextStyle combinedStyle;
|
|
if (defaultStyle != null) {
|
|
if (style != null)
|
|
combinedStyle = defaultStyle.merge(style);
|
|
else
|
|
combinedStyle = defaultStyle;
|
|
} else {
|
|
combinedStyle = style;
|
|
}
|
|
if (combinedStyle != null)
|
|
text = new StyledTextSpan(combinedStyle, [text]);
|
|
return new Paragraph(text: text);
|
|
}
|
|
}
|
|
|
|
class Image extends LeafRenderObjectWrapper {
|
|
Image({
|
|
Key key,
|
|
this.image,
|
|
this.width,
|
|
this.height,
|
|
this.colorFilter,
|
|
this.fit: ImageFit.scaleDown,
|
|
this.repeat: ImageRepeat.noRepeat
|
|
}) : super(key: key);
|
|
|
|
final sky.Image image;
|
|
final double width;
|
|
final double height;
|
|
final sky.ColorFilter colorFilter;
|
|
final ImageFit fit;
|
|
final ImageRepeat repeat;
|
|
|
|
RenderImage createNode() => new RenderImage(
|
|
image: image,
|
|
width: width,
|
|
height: height,
|
|
colorFilter: colorFilter,
|
|
fit: fit,
|
|
repeat: repeat);
|
|
RenderImage get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Widget old) {
|
|
super.syncRenderObject(old);
|
|
renderObject.image = image;
|
|
renderObject.width = width;
|
|
renderObject.height = height;
|
|
renderObject.colorFilter = colorFilter;
|
|
renderObject.fit = fit;
|
|
renderObject.repeat = repeat;
|
|
}
|
|
}
|
|
|
|
class ImageListener extends StatefulComponent {
|
|
ImageListener({
|
|
Key key,
|
|
this.image,
|
|
this.width,
|
|
this.height,
|
|
this.colorFilter,
|
|
this.fit: ImageFit.scaleDown,
|
|
this.repeat: ImageRepeat.noRepeat
|
|
}) : super(key: key);
|
|
|
|
ImageResource image;
|
|
double width;
|
|
double height;
|
|
sky.ColorFilter colorFilter;
|
|
ImageFit fit;
|
|
ImageRepeat repeat;
|
|
|
|
sky.Image _resolvedImage;
|
|
|
|
void _handleImageChanged(sky.Image resolvedImage) {
|
|
if (!mounted)
|
|
return;
|
|
setState(() {
|
|
_resolvedImage = resolvedImage;
|
|
});
|
|
}
|
|
|
|
void didMount() {
|
|
super.didMount();
|
|
image.addListener(_handleImageChanged);
|
|
}
|
|
|
|
void didUnmount() {
|
|
super.didUnmount();
|
|
image.removeListener(_handleImageChanged);
|
|
}
|
|
|
|
void syncFields(ImageListener source) {
|
|
final bool needToUpdateListeners = (image != source.image) && mounted;
|
|
if (needToUpdateListeners)
|
|
image.removeListener(_handleImageChanged);
|
|
image = source.image;
|
|
width = source.width;
|
|
height = source.height;
|
|
colorFilter = source.colorFilter;
|
|
fit = source.fit;
|
|
repeat = source.repeat;
|
|
if (needToUpdateListeners)
|
|
image.addListener(_handleImageChanged);
|
|
}
|
|
|
|
Widget build() {
|
|
return new Image(
|
|
image: _resolvedImage,
|
|
width: width,
|
|
height: height,
|
|
colorFilter: colorFilter,
|
|
fit: fit,
|
|
repeat: repeat
|
|
);
|
|
}
|
|
}
|
|
|
|
class NetworkImage extends Component {
|
|
NetworkImage({
|
|
Key key,
|
|
this.src,
|
|
this.width,
|
|
this.height,
|
|
this.colorFilter,
|
|
this.fit: ImageFit.scaleDown,
|
|
this.repeat: ImageRepeat.noRepeat
|
|
}) : super(key: key);
|
|
|
|
final String src;
|
|
final double width;
|
|
final double height;
|
|
final sky.ColorFilter colorFilter;
|
|
final ImageFit fit;
|
|
final ImageRepeat repeat;
|
|
|
|
Widget build() {
|
|
return new ImageListener(
|
|
image: image_cache.load(src),
|
|
width: width,
|
|
height: height,
|
|
colorFilter: colorFilter,
|
|
fit: fit,
|
|
repeat: repeat
|
|
);
|
|
}
|
|
}
|
|
|
|
class AssetImage extends Component {
|
|
AssetImage({
|
|
Key key,
|
|
this.name,
|
|
this.bundle,
|
|
this.width,
|
|
this.height,
|
|
this.colorFilter,
|
|
this.fit: ImageFit.scaleDown,
|
|
this.repeat: ImageRepeat.noRepeat
|
|
}) : super(key: key);
|
|
|
|
final String name;
|
|
final AssetBundle bundle;
|
|
final double width;
|
|
final double height;
|
|
final sky.ColorFilter colorFilter;
|
|
final ImageFit fit;
|
|
final ImageRepeat repeat;
|
|
|
|
Widget build() {
|
|
return new ImageListener(
|
|
image: bundle.loadImage(name),
|
|
width: width,
|
|
height: height,
|
|
colorFilter: colorFilter,
|
|
fit: fit,
|
|
repeat: repeat
|
|
);
|
|
}
|
|
}
|
|
|
|
class WidgetToRenderBoxAdapter extends LeafRenderObjectWrapper {
|
|
WidgetToRenderBoxAdapter(RenderBox renderBox)
|
|
: renderBox = renderBox,
|
|
super(key: new Key.fromObjectIdentity(renderBox));
|
|
|
|
final RenderBox renderBox;
|
|
|
|
RenderBox createNode() => this.renderBox;
|
|
RenderBox get renderObject => super.renderObject;
|
|
|
|
void syncRenderObject(Widget old) {
|
|
super.syncRenderObject(old);
|
|
if (old != null) {
|
|
assert(old is WidgetToRenderBoxAdapter);
|
|
assert(renderObject == old.renderObject);
|
|
}
|
|
}
|
|
|
|
void remove() {
|
|
RenderObjectWrapper ancestor = findAncestorRenderObjectWrapper();
|
|
assert(ancestor is RenderObjectWrapper);
|
|
assert(ancestor.renderObject == renderObject.parent);
|
|
ancestor.detachChildRoot(this);
|
|
super.remove();
|
|
}
|
|
}
|
|
|
|
|
|
// EVENT HANDLING
|
|
|
|
class IgnorePointer extends OneChildRenderObjectWrapper {
|
|
IgnorePointer({ Key key, Widget child })
|
|
: super(key: key, child: child);
|
|
RenderIgnorePointer createNode() => new RenderIgnorePointer();
|
|
RenderIgnorePointer get renderObject => super.renderObject;
|
|
}
|