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
9eb4d15c
Commit
9eb4d15c
authored
Mar 23, 2016
by
Ian Hickson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2826 from Hixie/overflow
CustomPaint documentation
parents
e6cffd28
94284074
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
251 additions
and
33 deletions
+251
-33
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+121
-11
image_cache.dart
packages/flutter/lib/src/services/image_cache.dart
+71
-0
image_resource.dart
packages/flutter/lib/src/services/image_resource.dart
+42
-11
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+17
-11
No files found.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
9eb4d15c
...
...
@@ -678,7 +678,7 @@ abstract class CustomClipper<T> {
/// same size as the RenderObject (e.g. it's a rounded rectangle
/// with very small arcs in the corners), then this may be adequate.
Rect
getApproximateClipRect
(
Size
size
)
=>
Point
.
origin
&
size
;
/// Returns
true
if the new instance will result in a different clip
/// Returns
`true`
if the new instance will result in a different clip
/// than the oldClipper instance.
bool
shouldRepaint
(
CustomClipper
<
T
>
oldClipper
);
}
...
...
@@ -992,8 +992,8 @@ class RenderTransform extends RenderProxyBox {
markNeedsPaint
();
}
/// When set to
true
, hit tests are performed based on the position of the
/// child as it is painted. When set to
false
, hit tests are performed
/// When set to
`true`
, hit tests are performed based on the position of the
/// child as it is painted. When set to
`false`
, hit tests are performed
/// ignoring the transformation.
///
/// applyPaintTransform(), and therefore localToGlobal() and globalToLocal(),
...
...
@@ -1139,8 +1139,8 @@ class RenderFractionalTranslation extends RenderProxyBox {
markNeedsPaint
();
}
/// When set to
true
, hit tests are performed based on the position of the
/// child as it is painted. When set to
false
, hit tests are performed
/// When set to
`true`
, hit tests are performed based on the position of the
/// child as it is painted. When set to
`false`
, hit tests are performed
/// ignoring the transformation.
///
/// applyPaintTransform(), and therefore localToGlobal() and globalToLocal(),
...
...
@@ -1176,13 +1176,93 @@ class RenderFractionalTranslation extends RenderProxyBox {
}
}
/// The interface used by [CustomPaint] (in the widgets library) and
/// [RenderCustomPaint] (in the rendering library).
///
/// To implement a custom painter, subclass this interface to define your custom
/// paint delegate. [CustomPaint] subclasses must implement the [paint] and
/// [shouldRepaint] methods, and may optionally also implement the [hitTest]
/// method.
///
/// The [paint] method is called whenever the custom object needs to be repainted.
///
/// The [shouldRepaint] method is called when a new instance of the class
/// is provided, to check if the new instance actually represents different
/// information.
///
/// The [hitTest] method is invoked when the user interacts with the underlying
/// render object, to determine if the user hit the object or missed it.
abstract
class
CustomPainter
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
CustomPainter
();
/// Called whenever the object needs to paint. The given [Canvas] has its
/// coordinate space configured such that the origin is at the top left of the
/// box. The area of the box is the size of the [size] argument.
///
/// Paint operations should remain inside the given area. Graphical operations
/// outside the bounds may be silently ignored, clipped, or not clipped.
///
/// Implementations should be wary of correctly pairing any calls to
/// [Canvas.save]/[Canvas.saveLayer] and [Canvas.restore], otherwise all
/// subsequent painting on this canvas may be affected, with potentially
/// hilarious but confusing results.
///
/// To paint text on a [Canvas], use a [TextPainter].
///
/// To paint an image on a [Canvas]:
///
/// 1. Obtain an [ImageResource], for example by using the [ImageCache.load]
/// method on the [imageCache] singleton.
///
/// 2. Whenever the [ImageResource]'s underlying [ImageInfo] object changes
/// (see [ImageResource.addListener]), create a new instance of your custom
/// paint delegate, giving it the new [ImageInfo] object.
///
/// 3. In your delegate's [paint] method, call the [Canvas.drawImage],
/// [Canvas.drawImageRect], or [Canvas.drawImageNine] methods to paint the
/// [ImageInfo.image] object, applying the [ImageInfo.scale] value to
/// obtain the correct rendering size.
void
paint
(
Canvas
canvas
,
Size
size
);
/// Called whenever a new instance of the custom painter delegate class is
/// provided to the [RenderCustomPaint] object, or any time that a new
/// [CustomPaint] object is created with a new instance of the custom painter
/// delegate class (which amounts to the same thing, since the latter is
/// implemented in terms of the former).
///
/// If the new instance represents different information than the old
/// instance, then the method should return `true`, otherwise it should return
/// `false`.
///
/// If the method returns `false`, then the paint call might be optimized away.
///
/// It's possible that the [paint] method will get invoked even if
/// [shouldRepaint] returns `false` (e.g. if an ancestor or descendant needed to
/// be repainted). It's also possible that the [paint] method will get invoked
/// without [shouldRepaint] being called at all (e.g. if the box changes
/// size).
///
/// If a custom delegate has a particularly expensive paint function such that
/// repaints should be avoided as much as possible, a [RepaintBoundary] or
/// [RenderRepaintBoundary] (or other render object with [isRepaintBoundary]
/// set to `true`) might be helpful.
bool
shouldRepaint
(
CustomPainter
oldDelegate
);
/// Called whenever a hit test is being performed on an object that is using
/// this custom paint delegate.
///
/// The given point is relative to the same coordinate space as the last
/// [paint] call.
///
/// The default behavior is to consider all points to be hits for
/// background painters, and no points to be hits for foreground painters.
///
/// Return `true` if the given position corresponds to a point on the drawn
/// image that should be considered a "hit", `false` if it corresponds to a
/// point that should be considered outside the painted image, and null to use
/// the default behavior.
bool
hitTest
(
Point
position
)
=>
null
;
}
...
...
@@ -1206,8 +1286,23 @@ class RenderCustomPaint extends RenderProxyBox {
RenderBox
child
})
:
_painter
=
painter
,
_foregroundPainter
=
foregroundPainter
,
super
(
child
);
/// The background custom paint delegate.
///
/// This painter, if non-null, is invoked to paint behind the children.
CustomPainter
get
painter
=>
_painter
;
CustomPainter
_painter
;
/// Set a new background custom paint delegate.
///
/// If the new delegate is the same as the previous one, this does nothing.
///
/// If the new delegate is the same class as the previous one, then the new
/// delegate has its [CustomPainter.shouldRepaint] invoked; if the result is
/// `true`, then the delegate will be invoked.
///
/// If the new delegate is a different class than the previous one, then the
/// delegate will be invoked.
///
/// If the new value is null, then there is no background custom painter.
void
set
painter
(
CustomPainter
newPainter
)
{
if
(
_painter
==
newPainter
)
return
;
...
...
@@ -1216,8 +1311,23 @@ class RenderCustomPaint extends RenderProxyBox {
_checkForRepaint
(
_painter
,
oldPainter
);
}
/// The foreground custom paint delegate.
///
/// This painter, if non-null, is invoked to paint in front of the children.
CustomPainter
get
foregroundPainter
=>
_foregroundPainter
;
CustomPainter
_foregroundPainter
;
/// Set a new foreground custom paint delegate.
///
/// If the new delegate is the same as the previous one, this does nothing.
///
/// If the new delegate is the same class as the previous one, then the new
/// delegate has its [CustomPainter.shouldRepaint] invoked; if the result is
/// `true`, then the delegate will be invoked.
///
/// If the new delegate is a different class than the previous one, then the
/// delegate will be invoked.
///
/// If the new value is null, then there is no foreground custom painter.
void
set
foregroundPainter
(
CustomPainter
newPainter
)
{
if
(
_foregroundPainter
==
newPainter
)
return
;
...
...
@@ -1470,12 +1580,12 @@ class RenderRepaintBoundary extends RenderProxyBox {
/// Is invisible during hit testing.
///
/// When [ignoring] is
true
, this render object (and its subtree) is invisible
/// When [ignoring] is
`true`
, this render object (and its subtree) is invisible
/// to hit testing. It still consumes space during layout and paints its child
/// as usual. It just cannot be the target of located events because it returns
///
false
from [hitTest].
///
`false`
from [hitTest].
///
/// When [ignoringSemantics] is
true
, the subtree will be invisible to
/// When [ignoringSemantics] is
`true`
, the subtree will be invisible to
/// the semantics layer (and thus e.g. accessibility tools). If
/// [ignoringSemantics] is null, it uses the value of [ignoring].
class
RenderIgnorePointer
extends
RenderProxyBox
{
...
...
@@ -1693,11 +1803,11 @@ class RenderSemanticAnnotations extends RenderProxyBox {
assert
(
container
!=
null
);
}
/// If 'container' is
true
, this RenderObject will introduce a new
/// If 'container' is
`true`
, this RenderObject will introduce a new
/// node in the semantics tree. Otherwise, the semantics will be
/// merged with the semantics of any ancestors.
///
/// The 'container' flag is implicitly set to
true
on the immediate
/// The 'container' flag is implicitly set to
`true`
on the immediate
/// semantics-providing descendants of a node where multiple
/// children have semantics or have descendants providing semantics.
/// In other words, the semantics of siblings are not merged. To
...
...
@@ -1713,7 +1823,7 @@ class RenderSemanticAnnotations extends RenderProxyBox {
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the "hasCheckedState" semantic to
true
and the
/// If non-null, sets the "hasCheckedState" semantic to
`true`
and the
/// "isChecked" semantic to the given value.
bool
get
checked
=>
_checked
;
bool
_checked
;
...
...
packages/flutter/lib/src/services/image_cache.dart
View file @
9eb4d15c
...
...
@@ -14,8 +14,28 @@ import 'image_resource.dart';
/// Implements a way to retrieve an image, for example by fetching it from the
/// network. Also used as a key in the image cache.
///
/// This is the interface implemented by objects that can be used as the
/// argument to [ImageCache.loadProvider].
///
/// The [ImageCache.load] function uses an [ImageProvider] that fetches images
/// described by URLs. One could create an [ImageProvider] that used a custom
/// protocol, e.g. a direct TCP connection to a remote host, or using a
/// screenshot API from the host platform; such an image provider would then
/// share the same cache as all the other image loading codepaths that used the
/// [imageCache].
abstract
class
ImageProvider
{
// ignore: one_member_abstracts
Future
<
ImageInfo
>
loadImage
();
/// Subclasses must implement the `==` operator so that the image cache can
/// distinguish identical requests.
@override
bool
operator
==(
dynamic
other
);
/// Subclasses must implement the `hashCode` operator so that the image cache
/// can efficiently store the providers in a map.
@override
int
get
hashCode
;
}
class
_UrlFetcher
implements
ImageProvider
{
...
...
@@ -51,24 +71,75 @@ class _UrlFetcher implements ImageProvider {
const
int
_kDefaultSize
=
1000
;
/// Class for the [imageCache] object.
///
/// Implements a least-recently-used cache of up to 1000 images. The maximum
/// size can be adjusted using [maximumSize]. Images that are actively in use
/// (i.e. to which the application is holding references, either via
/// [ImageResource] objects, [ImageInfo] objects, or raw [ui.Image] objects) may
/// get evicted from the cache (and thus need to be refetched from the network
/// if they are referenced in the [load] method), but the raw bits are kept in
/// memory for as long as the application is using them.
///
/// The [load] method fetches the image with the given URL and scale.
///
/// For more complicated use cases, the [loadProvider] method can be used with a
/// custom [ImageProvider].
class
ImageCache
{
ImageCache
.
_
();
final
LruMap
<
ImageProvider
,
ImageResource
>
_cache
=
new
LruMap
<
ImageProvider
,
ImageResource
>(
maximumSize:
_kDefaultSize
);
/// Maximum number of entries to store in the cache.
///
/// Once this many entries have been cached, the least-recently-used entry is
/// evicted when adding a new entry.
int
get
maximumSize
=>
_cache
.
maximumSize
;
/// Changes the maximum cache size.
///
/// If the new size is smaller than the current number of elements, the
/// extraneous elements are evicted immediately. Setting this to zero and then
/// returning it to its original value will therefore immediately clear the
/// cache. However, doing this is not very efficient.
// (the quiver library does it one at a time rather than using clear())
void
set
maximumSize
(
int
value
)
{
_cache
.
maximumSize
=
value
;
}
/// Calls the [ImageProvider.loadImage] method on the given image provider, if
/// necessary, and returns an [ImageResource] that encapsulates a [Future] for
/// the given image.
///
/// If the given [ImageProvider] has already been used and is still in the
/// cache, then the [ImageResource] object is immediately usable and the
/// provider is not invoked.
ImageResource
loadProvider
(
ImageProvider
provider
)
{
return
_cache
.
putIfAbsent
(
provider
,
()
{
return
new
ImageResource
(
provider
.
loadImage
());
});
}
/// Fetches the given URL, associating it with the given scale.
///
/// The return value is an [ImageResource], which encapsulates a [Future] for
/// the given image.
///
/// If the given URL has already been fetched for the given scale, and it is
/// still in the cache, then the [ImageResource] object is immediately usable.
ImageResource
load
(
String
url
,
{
double
scale:
1.0
})
{
assert
(
url
!=
null
);
assert
(
scale
!=
null
);
return
loadProvider
(
new
_UrlFetcher
(
url
,
scale
));
}
}
/// The singleton that implements the Flutter framework's image cache.
///
/// The simplest use of this object is as follows:
///
/// ```dart
/// imageCache.load(myImageUrl).first.then(myImageHandler);
/// ```
///
/// ...where `myImageHandler` is a function with one argument, an [ImageInfo]
/// object.
final
ImageCache
imageCache
=
new
ImageCache
.
_
();
packages/flutter/lib/src/services/image_resource.dart
View file @
9eb4d15c
...
...
@@ -7,24 +7,55 @@ import 'dart:ui' as ui show Image;
import
'print.dart'
;
/// A [ui.Image] object with its corresponding scale.
///
/// ImageInfo objects are used by [ImageResource] objects to represent the
/// actual data of the image once it has been obtained.
class
ImageInfo
{
ImageInfo
({
this
.
image
,
this
.
scale
:
1.0
});
/// Creates an [ImageInfo] object for the given image and scale.
///
/// Both the image and the scale must be non-null.
ImageInfo
({
this
.
image
,
this
.
scale
:
1.0
})
{
assert
(
image
!=
null
);
assert
(
scale
!=
null
);
}
/// The raw image pixels.
///
/// This is the object to pass to the [Canvas.drawImage],
/// [Canvas.drawImageRect], or [Canvas.drawImageNine] methods when painting
/// the image.
final
ui
.
Image
image
;
/// The linear scale factor for drawing this image at its intended size.
///
/// The scale factor applies to the width and the height.
///
/// For example, if this is 2.0 it means that there are four image pixels for
/// every one logical pixel, and the image's actual width and height (as given
/// by the [ui.Image.width] and [ui.Image.height] properties) are double the
/// height and width that should be used when painting the image (e.g. in the
/// arguments given to [Canvas.drawImage]).
final
double
scale
;
@override
String
toString
()
=>
'
$image
@
${scale}
x'
;
}
/// A callback for when the image is available.
/// Signature for callbacks reporting that an image is available.
///
/// Used by [ImageResource].
typedef
void
ImageListener
(
ImageInfo
image
);
/// A handle to an image resource
/// A handle to an image resource.
///
/// ImageResource represents a handle to a [ui.Image] object and its scale
/// (together represented by an [ImageInfo] object). The underlying image object
/// might change over time, either because the image is animating or because the
/// underlying image resource was mutated.
///
/// ImageResource represents a handle to a [ui.Image] object. The underlying
/// image object might change over time, either because the image is animating
/// or because the underlying image resource was mutated.
/// ImageResource objects can also represent an image that hasn't finished
/// loading.
class
ImageResource
{
ImageResource
(
this
.
_futureImage
)
{
_futureImage
.
then
(
...
...
@@ -40,15 +71,15 @@ class ImageResource {
ImageInfo
_image
;
final
List
<
ImageListener
>
_listeners
=
new
List
<
ImageListener
>();
/// The first concrete [
ui.Image
] object represented by this handle.
/// The first concrete [
ImageInfo
] object represented by this handle.
///
/// Instead of receivingly only the first image, most clients will want to
/// [addListener] to be notified whenever a a concrete image is available.
Future
<
ImageInfo
>
get
first
=>
_futureImage
;
/// Adds a listener callback that is called whenever a concrete [
ui.Image
]
/// object is available.
Note: If a concrete image is available currently,
///
this object
will call the listener synchronously.
/// Adds a listener callback that is called whenever a concrete [
ImageInfo
]
/// object is available.
If a concrete image is already available, this object
/// will call the listener synchronously.
void
addListener
(
ImageListener
listener
)
{
_listeners
.
add
(
listener
);
if
(
_resolved
)
{
...
...
@@ -60,7 +91,7 @@ class ImageResource {
}
}
/// Stop listening for new concrete [
ui.Image
] objects.
/// Stop listening for new concrete [
ImageInfo
] objects.
void
removeListener
(
ImageListener
listener
)
{
_listeners
.
remove
(
listener
);
}
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
9eb4d15c
...
...
@@ -147,19 +147,25 @@ class DecoratedBox extends SingleChildRenderObjectWidget {
}
}
///
Delegates its painting
.
///
Provides a canvas on which to draw during the paint phase
.
///
/// When asked to paint, custom paint first asks painter to paint with the
/// current canvas and then paints its children. After painting its children,
/// custom paint asks foregroundPainter to paint. The coodinate system of the
/// canvas matches the coordinate system of the custom paint object. The
/// painters are expected to paint within a rectangle starting at the origin
/// and encompassing a region of the given size. If the painters paints outside
/// those bounds, there might be insufficient memory allocated to rasterize the
/// painting commands and the resulting behavior is undefined.
/// When asked to paint, [CustomPaint] objects first ask their [painter] to
/// paint on the current canvas, then they paint their children, and then, after
/// painting their children, ask their [foregroundPainter] to paint. The
/// coodinate system of the canvas matches the coordinate system of the
/// [CustomPaint] object. The painters are expected to paint within a rectangle
/// starting at the origin and encompassing a region of the given size. (If the
/// painters paints outside those bounds, there might be insufficient memory
/// allocated to rasterize the painting commands and the resulting behavior is
/// undefined.)
///
/// Because custom paint calls its painters during paint, you cannot dirty
/// layout or paint information during the callback.
/// Painters are implemented by subclassing [CustomPainter].
///
/// Because custom paint calls its painters during paint, you cannot mark the
/// tree as needing a new layout during the callback (the layout for this frame
/// has already happened).
///
/// See: [CustomPainter], [Canvas].
class
CustomPaint
extends
SingleChildRenderObjectWidget
{
CustomPaint
({
Key
key
,
this
.
painter
,
this
.
foregroundPainter
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
...
...
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