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
c27b03b8
Commit
c27b03b8
authored
Sep 24, 2016
by
Adam Barth
Committed by
GitHub
Sep 24, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add FittedBox (#6029)
This widget lets you apply an ImageFit to a child widget. Fixes #5830
parent
12054e33
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
332 additions
and
32 deletions
+332
-32
image_fit.dart
packages/flutter/lib/src/painting/image_fit.dart
+1
-1
box.dart
packages/flutter/lib/src/rendering/box.dart
+40
-0
image.dart
packages/flutter/lib/src/rendering/image.dart
+6
-29
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+133
-0
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+37
-1
image.dart
packages/flutter/lib/src/widgets/image.dart
+1
-1
fitted_box_test.dart
packages/flutter/test/widget/fitted_box_test.dart
+114
-0
No files found.
packages/flutter/lib/src/painting/image_fit.dart
View file @
c27b03b8
packages/flutter/lib/src/rendering/box.dart
View file @
c27b03b8
...
...
@@ -209,6 +209,46 @@ class BoxConstraints extends Constraints {
return
result
;
}
/// Returns a size that attempts to meet the following conditions, in order:
///
/// - The size must satisfy these constraints.
/// - The aspect ratio of the returned size matches the aspect ratio of the
/// given size.
/// - The returned size as big as possible while still being equal to or
/// smaller than the given size.
Size
constrainSizeAndAttemptToPreserveAspectRatio
(
Size
size
)
{
if
(
isTight
)
return
smallest
;
double
width
=
size
.
width
;
double
height
=
size
.
height
;
assert
(
width
>
0.0
);
assert
(
height
>
0.0
);
double
aspectRatio
=
width
/
height
;
if
(
width
>
maxWidth
)
{
width
=
maxWidth
;
height
=
width
/
aspectRatio
;
}
if
(
height
>
maxHeight
)
{
height
=
maxHeight
;
width
=
height
*
aspectRatio
;
}
if
(
width
<
minWidth
)
{
width
=
minWidth
;
height
=
width
/
aspectRatio
;
}
if
(
height
<
minHeight
)
{
height
=
minHeight
;
width
=
height
*
aspectRatio
;
}
return
new
Size
(
constrainWidth
(
width
),
constrainHeight
(
height
));
}
/// The biggest size that satisifes the constraints.
Size
get
biggest
=>
new
Size
(
constrainWidth
(),
constrainHeight
());
...
...
packages/flutter/lib/src/rendering/image.dart
View file @
c27b03b8
...
...
@@ -114,7 +114,7 @@ class RenderImage extends RenderBox {
markNeedsPaint
();
}
/// How to inscribe the image into the
pl
ace allocated during layout.
/// How to inscribe the image into the
sp
ace allocated during layout.
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
...
...
@@ -178,36 +178,13 @@ class RenderImage extends RenderBox {
height:
_height
).
enforce
(
constraints
);
if
(
constraints
.
isTight
||
_image
==
null
)
if
(
_image
==
null
)
return
constraints
.
smallest
;
double
width
=
_image
.
width
.
toDouble
()
/
_scale
;
double
height
=
_image
.
height
.
toDouble
()
/
_scale
;
assert
(
width
>
0.0
);
assert
(
height
>
0.0
);
double
aspectRatio
=
width
/
height
;
if
(
width
>
constraints
.
maxWidth
)
{
width
=
constraints
.
maxWidth
;
height
=
width
/
aspectRatio
;
}
if
(
height
>
constraints
.
maxHeight
)
{
height
=
constraints
.
maxHeight
;
width
=
height
*
aspectRatio
;
}
if
(
width
<
constraints
.
minWidth
)
{
width
=
constraints
.
minWidth
;
height
=
width
/
aspectRatio
;
}
if
(
height
<
constraints
.
minHeight
)
{
height
=
constraints
.
minHeight
;
width
=
height
*
aspectRatio
;
}
return
constraints
.
constrain
(
new
Size
(
width
,
height
));
return
constraints
.
constrainSizeAndAttemptToPreserveAspectRatio
(
new
Size
(
_image
.
width
.
toDouble
()
/
_scale
,
_image
.
height
.
toDouble
()
/
_scale
));
}
@override
...
...
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
c27b03b8
...
...
@@ -1400,6 +1400,139 @@ class RenderTransform extends RenderProxyBox {
}
}
/// Scales and positions its child within itself according to [fit].
class
RenderFittedBox
extends
RenderProxyBox
{
/// Scales and positions its child within itself.
///
/// The [fit] and [alignment] arguments must not be null.
RenderFittedBox
({
RenderBox
child
,
ImageFit
fit:
ImageFit
.
contain
,
FractionalOffset
alignment:
FractionalOffset
.
center
})
:
_fit
=
fit
,
_alignment
=
alignment
,
super
(
child
)
{
assert
(
fit
!=
null
);
assert
(
alignment
!=
null
&&
alignment
.
dx
!=
null
&&
alignment
.
dy
!=
null
);
}
/// How to inscribe the child into the space allocated during layout.
ImageFit
get
fit
=>
_fit
;
ImageFit
_fit
;
set
fit
(
ImageFit
newFit
)
{
assert
(
newFit
!=
null
);
if
(
_fit
==
newFit
)
return
;
_fit
=
newFit
;
_clearPaintData
();
markNeedsPaint
();
}
/// How to align the child within its parent's bounds.
///
/// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its
/// parent's bounds. An alignment of (1.0, 0.5) aligns the child to the middle
/// of the right edge of its parent's bounds.
FractionalOffset
get
alignment
=>
_alignment
;
FractionalOffset
_alignment
;
set
alignment
(
FractionalOffset
newAlignment
)
{
assert
(
newAlignment
!=
null
&&
newAlignment
.
dx
!=
null
&&
newAlignment
.
dy
!=
null
);
if
(
_alignment
==
newAlignment
)
return
;
_alignment
=
newAlignment
;
_clearPaintData
();
markNeedsPaint
();
}
@override
void
performLayout
()
{
if
(
child
!=
null
)
{
child
.
layout
(
const
BoxConstraints
(),
parentUsesSize:
true
);
size
=
constraints
.
constrainSizeAndAttemptToPreserveAspectRatio
(
child
.
size
);
_clearPaintData
();
}
else
{
size
=
constraints
.
smallest
;
}
}
bool
_hasVisualOverflow
;
Matrix4
_transform
;
void
_clearPaintData
()
{
_hasVisualOverflow
=
null
;
_transform
=
null
;
}
void
_updatePaintData
()
{
if
(
_transform
!=
null
)
return
;
if
(
child
==
null
)
{
_hasVisualOverflow
=
false
;
_transform
=
new
Matrix4
.
identity
();
}
else
{
final
Size
childSize
=
child
.
size
;
final
FittedSizes
sizes
=
applyImageFit
(
_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
);
final
Rect
destinationRect
=
_alignment
.
inscribe
(
sizes
.
destination
,
Point
.
origin
&
size
);
_hasVisualOverflow
=
sourceRect
.
width
<
childSize
.
width
||
sourceRect
.
height
<
childSize
.
width
;
_transform
=
new
Matrix4
.
translationValues
(
destinationRect
.
left
,
destinationRect
.
top
,
0.0
)
..
scale
(
scaleX
,
scaleY
)
..
translate
(-
sourceRect
.
left
,
-
sourceRect
.
top
);
}
}
void
_paintChildWithTransform
(
PaintingContext
context
,
Offset
offset
)
{
Offset
childOffset
=
MatrixUtils
.
getAsTranslation
(
_transform
);
if
(
childOffset
==
null
)
context
.
pushTransform
(
needsCompositing
,
offset
,
_transform
,
super
.
paint
);
else
super
.
paint
(
context
,
offset
+
childOffset
);
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
_updatePaintData
();
if
(
child
!=
null
)
{
if
(
_hasVisualOverflow
)
context
.
pushClipRect
(
needsCompositing
,
offset
,
Point
.
origin
&
size
,
_paintChildWithTransform
);
else
_paintChildWithTransform
(
context
,
offset
);
}
}
@override
bool
hitTest
(
HitTestResult
result
,
{
Point
position
})
{
_updatePaintData
();
Matrix4
inverse
;
try
{
inverse
=
new
Matrix4
.
inverted
(
_transform
);
}
catch
(
e
)
{
// We cannot invert the effective transform. That means the child
// doesn't appear on screen and cannot be hit.
return
false
;
}
Vector3
position3
=
new
Vector3
(
position
.
x
,
position
.
y
,
0.0
);
Vector3
transformed3
=
inverse
.
transform3
(
position3
);
position
=
new
Point
(
transformed3
.
x
,
transformed3
.
y
);
return
super
.
hitTest
(
result
,
position:
position
);
}
@override
void
applyPaintTransform
(
RenderBox
child
,
Matrix4
transform
)
{
_updatePaintData
();
transform
.
multiply
(
_transform
);
super
.
applyPaintTransform
(
child
,
transform
);
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'fit:
$fit
'
);
description
.
add
(
'alignment:
$alignment
'
);
}
}
/// Applies a translation transformation before painting its child.
///
/// The translation is expressed as a [FractionalOffset] relative to the
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
c27b03b8
...
...
@@ -432,6 +432,42 @@ class Transform extends SingleChildRenderObjectWidget {
}
}
/// Scales and positions its child within itself according to [fit].
class
FittedBox
extends
SingleChildRenderObjectWidget
{
/// Creates a widget that scales and positions its child within itself according to [fit].
///
/// The [fit] and [alignment] arguments must not be null.
FittedBox
({
Key
key
,
this
.
fit
:
ImageFit
.
contain
,
this
.
alignment
:
FractionalOffset
.
center
,
Widget
child
})
:
super
(
key:
key
,
child:
child
)
{
assert
(
fit
!=
null
);
assert
(
alignment
!=
null
&&
alignment
.
dx
!=
null
&&
alignment
.
dy
!=
null
);
}
/// How to inscribe the child into the space allocated during layout.
final
ImageFit
fit
;
/// How to align the child within its parent's bounds.
///
/// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its
/// parent's bounds. An alignment of (1.0, 0.5) aligns the child to the middle
/// of the right edge of its parent's bounds.
final
FractionalOffset
alignment
;
@override
RenderFittedBox
createRenderObject
(
BuildContext
context
)
=>
new
RenderFittedBox
(
fit:
fit
,
alignment:
alignment
);
@override
void
updateRenderObject
(
BuildContext
context
,
RenderFittedBox
renderObject
)
{
renderObject
..
fit
=
fit
..
alignment
=
alignment
;
}
}
/// A widget that applies a translation expressed as a fraction of the box's
/// size before painting its child.
class
FractionalTranslation
extends
SingleChildRenderObjectWidget
{
...
...
@@ -2227,7 +2263,7 @@ class RawImage extends LeafRenderObjectWidget {
/// If non-null, apply this color filter to the image before painting.
final
Color
color
;
/// How to inscribe the image into the
pl
ace allocated during layout.
/// How to inscribe the image into the
sp
ace allocated during layout.
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
...
...
packages/flutter/lib/src/widgets/image.dart
View file @
c27b03b8
...
...
@@ -129,7 +129,7 @@ class Image extends StatefulWidget {
/// If non-null, apply this color filter to the image before painting.
final
Color
color
;
/// How to inscribe the image into the
pl
ace allocated during layout.
/// How to inscribe the image into the
sp
ace allocated during layout.
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
...
...
packages/flutter/test/widget/fitted_box_test.dart
0 → 100644
View file @
c27b03b8
// 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
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
void
main
(
)
{
testWidgets
(
'Can size according to aspect ratio'
,
(
WidgetTester
tester
)
async
{
Key
outside
=
new
UniqueKey
();
Key
inside
=
new
UniqueKey
();
await
tester
.
pumpWidget
(
new
Center
(
child:
new
Container
(
width:
200.0
,
child:
new
FittedBox
(
key:
outside
,
child:
new
Container
(
key:
inside
,
width:
100.0
,
height:
50.0
,
)
)
)
)
);
RenderBox
outsideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
outside
));
expect
(
outsideBox
.
size
.
width
,
200.0
);
expect
(
outsideBox
.
size
.
height
,
100.0
);
RenderBox
insideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
inside
));
expect
(
insideBox
.
size
.
width
,
100.0
);
expect
(
insideBox
.
size
.
height
,
50.0
);
Point
insidePoint
=
insideBox
.
localToGlobal
(
new
Point
(
100.0
,
50.0
));
Point
outsidePoint
=
outsideBox
.
localToGlobal
(
new
Point
(
200.0
,
100.0
));
expect
(
insidePoint
,
equals
(
outsidePoint
));
});
testWidgets
(
'Can contain child'
,
(
WidgetTester
tester
)
async
{
Key
outside
=
new
UniqueKey
();
Key
inside
=
new
UniqueKey
();
await
tester
.
pumpWidget
(
new
Center
(
child:
new
Container
(
width:
200.0
,
height:
200.0
,
child:
new
FittedBox
(
key:
outside
,
child:
new
Container
(
key:
inside
,
width:
100.0
,
height:
50.0
,
)
)
)
)
);
RenderBox
outsideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
outside
));
expect
(
outsideBox
.
size
.
width
,
200.0
);
expect
(
outsideBox
.
size
.
height
,
200.0
);
RenderBox
insideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
inside
));
expect
(
insideBox
.
size
.
width
,
100.0
);
expect
(
insideBox
.
size
.
height
,
50.0
);
Point
insidePoint
=
insideBox
.
localToGlobal
(
new
Point
(
100.0
,
0.0
));
Point
outsidePoint
=
outsideBox
.
localToGlobal
(
new
Point
(
200.0
,
50.0
));
expect
(
insidePoint
,
equals
(
outsidePoint
));
});
testWidgets
(
'Child can conver'
,
(
WidgetTester
tester
)
async
{
Key
outside
=
new
UniqueKey
();
Key
inside
=
new
UniqueKey
();
await
tester
.
pumpWidget
(
new
Center
(
child:
new
Container
(
width:
200.0
,
height:
200.0
,
child:
new
FittedBox
(
key:
outside
,
fit:
ImageFit
.
cover
,
child:
new
Container
(
key:
inside
,
width:
100.0
,
height:
50.0
,
)
)
)
)
);
RenderBox
outsideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
outside
));
expect
(
outsideBox
.
size
.
width
,
200.0
);
expect
(
outsideBox
.
size
.
height
,
200.0
);
RenderBox
insideBox
=
tester
.
firstRenderObject
(
find
.
byKey
(
inside
));
expect
(
insideBox
.
size
.
width
,
100.0
);
expect
(
insideBox
.
size
.
height
,
50.0
);
Point
insidePoint
=
insideBox
.
localToGlobal
(
new
Point
(
50.0
,
25.0
));
Point
outsidePoint
=
outsideBox
.
localToGlobal
(
new
Point
(
100.0
,
100.0
));
expect
(
insidePoint
,
equals
(
outsidePoint
));
});
}
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