1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:ui' as ui show Image, ImageFilter; 6 7import 'package:flutter/foundation.dart'; 8import 'package:flutter/gestures.dart'; 9import 'package:flutter/rendering.dart'; 10import 'package:flutter/services.dart'; 11 12import 'debug.dart'; 13import 'framework.dart'; 14import 'localizations.dart'; 15import 'widget_span.dart'; 16 17export 'package:flutter/animation.dart'; 18export 'package:flutter/foundation.dart' show 19 ChangeNotifier, 20 FlutterErrorDetails, 21 Listenable, 22 TargetPlatform, 23 ValueNotifier; 24export 'package:flutter/painting.dart'; 25export 'package:flutter/rendering.dart' show 26 AlignmentTween, 27 AlignmentGeometryTween, 28 Axis, 29 BoxConstraints, 30 CrossAxisAlignment, 31 CustomClipper, 32 CustomPainter, 33 CustomPainterSemantics, 34 DecorationPosition, 35 FlexFit, 36 FlowDelegate, 37 FlowPaintingContext, 38 FractionalOffsetTween, 39 HitTestBehavior, 40 LayerLink, 41 MainAxisAlignment, 42 MainAxisSize, 43 MultiChildLayoutDelegate, 44 Overflow, 45 PaintingContext, 46 PointerCancelEvent, 47 PointerCancelEventListener, 48 PointerDownEvent, 49 PointerDownEventListener, 50 PointerEvent, 51 PointerMoveEvent, 52 PointerMoveEventListener, 53 PointerUpEvent, 54 PointerUpEventListener, 55 RelativeRect, 56 SemanticsBuilderCallback, 57 ShaderCallback, 58 ShapeBorderClipper, 59 SingleChildLayoutDelegate, 60 StackFit, 61 TextOverflow, 62 ValueChanged, 63 ValueGetter, 64 WrapAlignment, 65 WrapCrossAlignment; 66 67// Examples can assume: 68// class TestWidget extends StatelessWidget { @override Widget build(BuildContext context) => const Placeholder(); } 69// WidgetTester tester; 70// bool _visible; 71// class Sky extends CustomPainter { @override void paint(Canvas c, Size s) => null; @override bool shouldRepaint(Sky s) => false; } 72// BuildContext context; 73// dynamic userAvatarUrl; 74 75// BIDIRECTIONAL TEXT SUPPORT 76 77/// A widget that determines the ambient directionality of text and 78/// text-direction-sensitive render objects. 79/// 80/// For example, [Padding] depends on the [Directionality] to resolve 81/// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects. 82class Directionality extends InheritedWidget { 83 /// Creates a widget that determines the directionality of text and 84 /// text-direction-sensitive render objects. 85 /// 86 /// The [textDirection] and [child] arguments must not be null. 87 const Directionality({ 88 Key key, 89 @required this.textDirection, 90 @required Widget child, 91 }) : assert(textDirection != null), 92 assert(child != null), 93 super(key: key, child: child); 94 95 /// The text direction for this subtree. 96 final TextDirection textDirection; 97 98 /// The text direction from the closest instance of this class that encloses 99 /// the given context. 100 /// 101 /// If there is no [Directionality] ancestor widget in the tree at the given 102 /// context, then this will return null. 103 /// 104 /// Typical usage is as follows: 105 /// 106 /// ```dart 107 /// TextDirection textDirection = Directionality.of(context); 108 /// ``` 109 static TextDirection of(BuildContext context) { 110 final Directionality widget = context.inheritFromWidgetOfExactType(Directionality); 111 return widget?.textDirection; 112 } 113 114 @override 115 bool updateShouldNotify(Directionality oldWidget) => textDirection != oldWidget.textDirection; 116 117 @override 118 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 119 super.debugFillProperties(properties); 120 properties.add(EnumProperty<TextDirection>('textDirection', textDirection)); 121 } 122} 123 124 125// PAINTING NODES 126 127/// A widget that makes its child partially transparent. 128/// 129/// This class paints its child into an intermediate buffer and then blends the 130/// child back into the scene partially transparent. 131/// 132/// For values of opacity other than 0.0 and 1.0, this class is relatively 133/// expensive because it requires painting the child into an intermediate 134/// buffer. For the value 0.0, the child is simply not painted at all. For the 135/// value 1.0, the child is painted immediately without an intermediate buffer. 136/// 137/// {@youtube 560 315 https://www.youtube.com/watch?v=9hltevOHQBw} 138/// 139/// {@tool sample} 140/// 141/// This example shows some [Text] when the `_visible` member field is true, and 142/// hides it when it is false: 143/// 144/// ```dart 145/// Opacity( 146/// opacity: _visible ? 1.0 : 0.0, 147/// child: const Text('Now you see me, now you don\'t!'), 148/// ) 149/// ``` 150/// {@end-tool} 151/// 152/// This is more efficient than adding and removing the child widget from the 153/// tree on demand. 154/// 155/// ## Performance considerations for opacity animation 156/// 157/// Animating an [Opacity] widget directly causes the widget (and possibly its 158/// subtree) to rebuild each frame, which is not very efficient. Consider using 159/// an [AnimatedOpacity] instead. 160/// 161/// ## Transparent image 162/// 163/// If only a single [Image] or [Color] needs to be composited with an opacity 164/// between 0.0 and 1.0, it's much faster to directly use them without [Opacity] 165/// widgets. 166/// 167/// For example, `Container(color: Color.fromRGBO(255, 0, 0, 0.5))` is much 168/// faster than `Opacity(opacity: 0.5, child: Container(color: Colors.red))`. 169/// 170/// {@tool sample} 171/// 172/// The following example draws an [Image] with 0.5 opacity without using 173/// [Opacity]: 174/// 175/// ```dart 176/// Image.network( 177/// 'https://raw.githubusercontent.com/flutter/assets-for-api-docs/master/packages/diagrams/assets/blend_mode_destination.jpeg', 178/// color: Color.fromRGBO(255, 255, 255, 0.5), 179/// colorBlendMode: BlendMode.modulate 180/// ) 181/// ``` 182/// 183/// {@end-tool} 184/// 185/// Directly drawing an [Image] or [Color] with opacity is faster than using 186/// [Opacity] on top of them because [Opacity] could apply the opacity to a 187/// group of widgets and therefore a costly offscreen buffer will be used. 188/// Drawing content into the offscreen buffer may also trigger render target 189/// switches and such switching is particularly slow in older GPUs. 190/// 191/// See also: 192/// 193/// * [Visibility], which can hide a child more efficiently (albeit less 194/// subtly, because it is either visible or hidden, rather than allowing 195/// fractional opacity values). 196/// * [ShaderMask], which can apply more elaborate effects to its child. 197/// * [Transform], which applies an arbitrary transform to its child widget at 198/// paint time. 199/// * [AnimatedOpacity], which uses an animation internally to efficiently 200/// animate opacity. 201/// * [FadeTransition], which uses a provided animation to efficiently animate 202/// opacity. 203/// * [Image], which can directly provide a partially transparent image with 204/// much less performance hit. 205class Opacity extends SingleChildRenderObjectWidget { 206 /// Creates a widget that makes its child partially transparent. 207 /// 208 /// The [opacity] argument must not be null and must be between 0.0 and 1.0 209 /// (inclusive). 210 const Opacity({ 211 Key key, 212 @required this.opacity, 213 this.alwaysIncludeSemantics = false, 214 Widget child, 215 }) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0), 216 assert(alwaysIncludeSemantics != null), 217 super(key: key, child: child); 218 219 /// The fraction to scale the child's alpha value. 220 /// 221 /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent 222 /// (i.e., invisible). 223 /// 224 /// The opacity must not be null. 225 /// 226 /// Values 1.0 and 0.0 are painted with a fast path. Other values 227 /// require painting the child into an intermediate buffer, which is 228 /// expensive. 229 final double opacity; 230 231 /// Whether the semantic information of the children is always included. 232 /// 233 /// Defaults to false. 234 /// 235 /// When true, regardless of the opacity settings the child semantic 236 /// information is exposed as if the widget were fully visible. This is 237 /// useful in cases where labels may be hidden during animations that 238 /// would otherwise contribute relevant semantics. 239 final bool alwaysIncludeSemantics; 240 241 @override 242 RenderOpacity createRenderObject(BuildContext context) { 243 return RenderOpacity( 244 opacity: opacity, 245 alwaysIncludeSemantics: alwaysIncludeSemantics, 246 ); 247 } 248 249 @override 250 void updateRenderObject(BuildContext context, RenderOpacity renderObject) { 251 renderObject 252 ..opacity = opacity 253 ..alwaysIncludeSemantics = alwaysIncludeSemantics; 254 } 255 256 @override 257 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 258 super.debugFillProperties(properties); 259 properties.add(DoubleProperty('opacity', opacity)); 260 properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); 261 } 262} 263 264/// A widget that applies a mask generated by a [Shader] to its child. 265/// 266/// For example, [ShaderMask] can be used to gradually fade out the edge 267/// of a child by using a [new ui.Gradient.linear] mask. 268/// 269/// {@tool sample} 270/// 271/// This example makes the text look like it is on fire: 272/// 273/// ```dart 274/// ShaderMask( 275/// shaderCallback: (Rect bounds) { 276/// return RadialGradient( 277/// center: Alignment.topLeft, 278/// radius: 1.0, 279/// colors: <Color>[Colors.yellow, Colors.deepOrange.shade900], 280/// tileMode: TileMode.mirror, 281/// ).createShader(bounds); 282/// }, 283/// child: const Text('I’m burning the memories'), 284/// ) 285/// ``` 286/// {@end-tool} 287/// 288/// See also: 289/// 290/// * [Opacity], which can apply a uniform alpha effect to its child. 291/// * [CustomPaint], which lets you draw directly on the canvas. 292/// * [DecoratedBox], for another approach at decorating child widgets. 293/// * [BackdropFilter], which applies an image filter to the background. 294class ShaderMask extends SingleChildRenderObjectWidget { 295 /// Creates a widget that applies a mask generated by a [Shader] to its child. 296 /// 297 /// The [shaderCallback] and [blendMode] arguments must not be null. 298 const ShaderMask({ 299 Key key, 300 @required this.shaderCallback, 301 this.blendMode = BlendMode.modulate, 302 Widget child, 303 }) : assert(shaderCallback != null), 304 assert(blendMode != null), 305 super(key: key, child: child); 306 307 /// Called to create the [dart:ui.Shader] that generates the mask. 308 /// 309 /// The shader callback is called with the current size of the child so that 310 /// it can customize the shader to the size and location of the child. 311 /// 312 /// Typically this will use a [LinearGradient], [RadialGradient], or 313 /// [SweepGradient] to create the [dart:ui.Shader], though the 314 /// [dart:ui.ImageShader] class could also be used. 315 final ShaderCallback shaderCallback; 316 317 /// The [BlendMode] to use when applying the shader to the child. 318 /// 319 /// The default, [BlendMode.modulate], is useful for applying an alpha blend 320 /// to the child. Other blend modes can be used to create other effects. 321 final BlendMode blendMode; 322 323 @override 324 RenderShaderMask createRenderObject(BuildContext context) { 325 return RenderShaderMask( 326 shaderCallback: shaderCallback, 327 blendMode: blendMode, 328 ); 329 } 330 331 @override 332 void updateRenderObject(BuildContext context, RenderShaderMask renderObject) { 333 renderObject 334 ..shaderCallback = shaderCallback 335 ..blendMode = blendMode; 336 } 337} 338 339/// A widget that applies a filter to the existing painted content and then 340/// paints [child]. 341/// 342/// The filter will be applied to all the area within its parent or ancestor 343/// widget's clip. If there's no clip, the filter will be applied to the full 344/// screen. 345/// 346/// {@youtube 560 315 https://www.youtube.com/watch?v=dYRs7Q1vfYI} 347/// 348/// {@tool sample} 349/// If the [BackdropFilter] needs to be applied to an area that exactly matches 350/// its child, wraps the [BackdropFilter] with a clip widget that clips exactly 351/// to that child. 352/// 353/// ```dart 354/// Stack( 355/// fit: StackFit.expand, 356/// children: <Widget>[ 357/// Text('0' * 10000), 358/// Center( 359/// child: ClipRect( // <-- clips to the 200x200 [Container] below 360/// child: BackdropFilter( 361/// filter: ui.ImageFilter.blur( 362/// sigmaX: 5.0, 363/// sigmaY: 5.0, 364/// ), 365/// child: Container( 366/// alignment: Alignment.center, 367/// width: 200.0, 368/// height: 200.0, 369/// child: Text('Hello World'), 370/// ), 371/// ), 372/// ), 373/// ), 374/// ], 375/// ) 376/// ``` 377/// {@end-tool} 378/// 379/// This effect is relatively expensive, especially if the filter is non-local, 380/// such as a blur. 381/// 382/// See also: 383/// 384/// * [DecoratedBox], which draws a background under (or over) a widget. 385/// * [Opacity], which changes the opacity of the widget itself. 386class BackdropFilter extends SingleChildRenderObjectWidget { 387 /// Creates a backdrop filter. 388 /// 389 /// The [filter] argument must not be null. 390 const BackdropFilter({ 391 Key key, 392 @required this.filter, 393 Widget child, 394 }) : assert(filter != null), 395 super(key: key, child: child); 396 397 /// The image filter to apply to the existing painted content before painting the child. 398 /// 399 /// For example, consider using [ImageFilter.blur] to create a backdrop 400 /// blur effect 401 final ui.ImageFilter filter; 402 403 @override 404 RenderBackdropFilter createRenderObject(BuildContext context) { 405 return RenderBackdropFilter(filter: filter); 406 } 407 408 @override 409 void updateRenderObject(BuildContext context, RenderBackdropFilter renderObject) { 410 renderObject.filter = filter; 411 } 412} 413 414/// A widget that provides a canvas on which to draw during the paint phase. 415/// 416/// When asked to paint, [CustomPaint] first asks its [painter] to paint on the 417/// current canvas, then it paints its child, and then, after painting its 418/// child, it asks its [foregroundPainter] to paint. The coordinate system of the 419/// canvas matches the coordinate system of the [CustomPaint] object. The 420/// painters are expected to paint within a rectangle starting at the origin and 421/// encompassing a region of the given size. (If the painters paint outside 422/// those bounds, there might be insufficient memory allocated to rasterize the 423/// painting commands and the resulting behavior is undefined.) To enforce 424/// painting within those bounds, consider wrapping this [CustomPaint] with a 425/// [ClipRect] widget. 426/// 427/// Painters are implemented by subclassing [CustomPainter]. 428/// 429/// {@youtube 560 315 https://www.youtube.com/watch?v=kp14Y4uHpHs} 430/// 431/// Because custom paint calls its painters during paint, you cannot call 432/// `setState` or `markNeedsLayout` during the callback (the layout for this 433/// frame has already happened). 434/// 435/// Custom painters normally size themselves to their child. If they do not have 436/// a child, they attempt to size themselves to the [size], which defaults to 437/// [Size.zero]. [size] must not be null. 438/// 439/// [isComplex] and [willChange] are hints to the compositor's raster cache 440/// and must not be null. 441/// 442/// {@tool sample} 443/// 444/// This example shows how the sample custom painter shown at [CustomPainter] 445/// could be used in a [CustomPaint] widget to display a background to some 446/// text. 447/// 448/// ```dart 449/// CustomPaint( 450/// painter: Sky(), 451/// child: Center( 452/// child: Text( 453/// 'Once upon a time...', 454/// style: const TextStyle( 455/// fontSize: 40.0, 456/// fontWeight: FontWeight.w900, 457/// color: Color(0xFFFFFFFF), 458/// ), 459/// ), 460/// ), 461/// ) 462/// ``` 463/// {@end-tool} 464/// 465/// See also: 466/// 467/// * [CustomPainter], the class to extend when creating custom painters. 468/// * [Canvas], the class that a custom painter uses to paint. 469class CustomPaint extends SingleChildRenderObjectWidget { 470 /// Creates a widget that delegates its painting. 471 const CustomPaint({ 472 Key key, 473 this.painter, 474 this.foregroundPainter, 475 this.size = Size.zero, 476 this.isComplex = false, 477 this.willChange = false, 478 Widget child, 479 }) : assert(size != null), 480 assert(isComplex != null), 481 assert(willChange != null), 482 super(key: key, child: child); 483 484 /// The painter that paints before the children. 485 final CustomPainter painter; 486 487 /// The painter that paints after the children. 488 final CustomPainter foregroundPainter; 489 490 /// The size that this [CustomPaint] should aim for, given the layout 491 /// constraints, if there is no child. 492 /// 493 /// Defaults to [Size.zero]. 494 /// 495 /// If there's a child, this is ignored, and the size of the child is used 496 /// instead. 497 final Size size; 498 499 /// Whether the painting is complex enough to benefit from caching. 500 /// 501 /// The compositor contains a raster cache that holds bitmaps of layers in 502 /// order to avoid the cost of repeatedly rendering those layers on each 503 /// frame. If this flag is not set, then the compositor will apply its own 504 /// heuristics to decide whether the this layer is complex enough to benefit 505 /// from caching. 506 final bool isComplex; 507 508 /// Whether the raster cache should be told that this painting is likely 509 /// to change in the next frame. 510 final bool willChange; 511 512 @override 513 RenderCustomPaint createRenderObject(BuildContext context) { 514 return RenderCustomPaint( 515 painter: painter, 516 foregroundPainter: foregroundPainter, 517 preferredSize: size, 518 isComplex: isComplex, 519 willChange: willChange, 520 ); 521 } 522 523 @override 524 void updateRenderObject(BuildContext context, RenderCustomPaint renderObject) { 525 renderObject 526 ..painter = painter 527 ..foregroundPainter = foregroundPainter 528 ..preferredSize = size 529 ..isComplex = isComplex 530 ..willChange = willChange; 531 } 532 533 @override 534 void didUnmountRenderObject(RenderCustomPaint renderObject) { 535 renderObject 536 ..painter = null 537 ..foregroundPainter = null; 538 } 539} 540 541/// A widget that clips its child using a rectangle. 542/// 543/// By default, [ClipRect] prevents its child from painting outside its 544/// bounds, but the size and location of the clip rect can be customized using a 545/// custom [clipper]. 546/// 547/// [ClipRect] is commonly used with these widgets, which commonly paint outside 548/// their bounds: 549/// 550/// * [CustomPaint] 551/// * [CustomSingleChildLayout] 552/// * [CustomMultiChildLayout] 553/// * [Align] and [Center] (e.g., if [Align.widthFactor] or 554/// [Align.heightFactor] is less than 1.0). 555/// * [OverflowBox] 556/// * [SizedOverflowBox] 557/// 558/// {@tool sample} 559/// 560/// For example, by combining a [ClipRect] with an [Align], one can show just 561/// the top half of an [Image]: 562/// 563/// ```dart 564/// ClipRect( 565/// child: Align( 566/// alignment: Alignment.topCenter, 567/// heightFactor: 0.5, 568/// child: Image.network(userAvatarUrl), 569/// ), 570/// ) 571/// ``` 572/// {@end-tool} 573/// 574/// See also: 575/// 576/// * [CustomClipper], for information about creating custom clips. 577/// * [ClipRRect], for a clip with rounded corners. 578/// * [ClipOval], for an elliptical clip. 579/// * [ClipPath], for an arbitrarily shaped clip. 580class ClipRect extends SingleChildRenderObjectWidget { 581 /// Creates a rectangular clip. 582 /// 583 /// If [clipper] is null, the clip will match the layout size and position of 584 /// the child. 585 const ClipRect({ Key key, this.clipper, this.clipBehavior = Clip.hardEdge, Widget child }) : super(key: key, child: child); 586 587 /// If non-null, determines which clip to use. 588 final CustomClipper<Rect> clipper; 589 590 /// {@macro flutter.clipper.clipBehavior} 591 final Clip clipBehavior; 592 593 @override 594 RenderClipRect createRenderObject(BuildContext context) => RenderClipRect(clipper: clipper, clipBehavior: clipBehavior); 595 596 @override 597 void updateRenderObject(BuildContext context, RenderClipRect renderObject) { 598 renderObject 599 ..clipper = clipper 600 ..clipBehavior = clipBehavior; 601 } 602 603 @override 604 void didUnmountRenderObject(RenderClipRect renderObject) { 605 renderObject.clipper = null; 606 } 607 608 @override 609 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 610 super.debugFillProperties(properties); 611 properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null)); 612 } 613} 614 615/// A widget that clips its child using a rounded rectangle. 616/// 617/// By default, [ClipRRect] uses its own bounds as the base rectangle for the 618/// clip, but the size and location of the clip can be customized using a custom 619/// [clipper]. 620/// 621/// {@youtube 560 315 https://www.youtube.com/watch?v=eI43jkQkrvs} 622/// 623/// See also: 624/// 625/// * [CustomClipper], for information about creating custom clips. 626/// * [ClipRect], for more efficient clips without rounded corners. 627/// * [ClipOval], for an elliptical clip. 628/// * [ClipPath], for an arbitrarily shaped clip. 629class ClipRRect extends SingleChildRenderObjectWidget { 630 /// Creates a rounded-rectangular clip. 631 /// 632 /// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with 633 /// right-angled corners. 634 /// 635 /// If [clipper] is non-null, then [borderRadius] is ignored. 636 const ClipRRect({ 637 Key key, 638 this.borderRadius, 639 this.clipper, 640 this.clipBehavior = Clip.antiAlias, 641 Widget child, 642 }) : assert(borderRadius != null || clipper != null), 643 assert(clipBehavior != null), 644 super(key: key, child: child); 645 646 /// The border radius of the rounded corners. 647 /// 648 /// Values are clamped so that horizontal and vertical radii sums do not 649 /// exceed width/height. 650 /// 651 /// This value is ignored if [clipper] is non-null. 652 final BorderRadius borderRadius; 653 654 /// If non-null, determines which clip to use. 655 final CustomClipper<RRect> clipper; 656 657 /// {@macro flutter.clipper.clipBehavior} 658 final Clip clipBehavior; 659 660 @override 661 RenderClipRRect createRenderObject(BuildContext context) => RenderClipRRect(borderRadius: borderRadius, clipper: clipper, clipBehavior: clipBehavior); 662 663 @override 664 void updateRenderObject(BuildContext context, RenderClipRRect renderObject) { 665 renderObject 666 ..borderRadius = borderRadius 667 ..clipBehavior = clipBehavior 668 ..clipper = clipper; 669 } 670 671 @override 672 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 673 super.debugFillProperties(properties); 674 properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, showName: false, defaultValue: null)); 675 properties.add(DiagnosticsProperty<CustomClipper<RRect>>('clipper', clipper, defaultValue: null)); 676 } 677} 678 679/// A widget that clips its child using an oval. 680/// 681/// By default, inscribes an axis-aligned oval into its layout dimensions and 682/// prevents its child from painting outside that oval, but the size and 683/// location of the clip oval can be customized using a custom [clipper]. 684/// 685/// See also: 686/// 687/// * [CustomClipper], for information about creating custom clips. 688/// * [ClipRect], for more efficient clips without rounded corners. 689/// * [ClipRRect], for a clip with rounded corners. 690/// * [ClipPath], for an arbitrarily shaped clip. 691class ClipOval extends SingleChildRenderObjectWidget { 692 /// Creates an oval-shaped clip. 693 /// 694 /// If [clipper] is null, the oval will be inscribed into the layout size and 695 /// position of the child. 696 const ClipOval({ Key key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget child }) : super(key: key, child: child); 697 698 /// If non-null, determines which clip to use. 699 /// 700 /// The delegate returns a rectangle that describes the axis-aligned 701 /// bounding box of the oval. The oval's axes will themselves also 702 /// be axis-aligned. 703 /// 704 /// If the [clipper] delegate is null, then the oval uses the 705 /// widget's bounding box (the layout dimensions of the render 706 /// object) instead. 707 final CustomClipper<Rect> clipper; 708 709 /// {@macro flutter.clipper.clipBehavior} 710 final Clip clipBehavior; 711 712 @override 713 RenderClipOval createRenderObject(BuildContext context) => RenderClipOval(clipper: clipper, clipBehavior: clipBehavior); 714 715 @override 716 void updateRenderObject(BuildContext context, RenderClipOval renderObject) { 717 renderObject 718 ..clipper = clipper 719 ..clipBehavior = clipBehavior; 720 } 721 722 @override 723 void didUnmountRenderObject(RenderClipOval renderObject) { 724 renderObject.clipper = null; 725 } 726 727 @override 728 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 729 super.debugFillProperties(properties); 730 properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null)); 731 } 732} 733 734/// A widget that clips its child using a path. 735/// 736/// Calls a callback on a delegate whenever the widget is to be 737/// painted. The callback returns a path and the widget prevents the 738/// child from painting outside the path. 739/// 740/// Clipping to a path is expensive. Certain shapes have more 741/// optimized widgets: 742/// 743/// * To clip to a rectangle, consider [ClipRect]. 744/// * To clip to an oval or circle, consider [ClipOval]. 745/// * To clip to a rounded rectangle, consider [ClipRRect]. 746/// 747/// To clip to a particular [ShapeBorder], consider using either the 748/// [ClipPath.shape] static method or the [ShapeBorderClipper] custom clipper 749/// class. 750class ClipPath extends SingleChildRenderObjectWidget { 751 /// Creates a path clip. 752 /// 753 /// If [clipper] is null, the clip will be a rectangle that matches the layout 754 /// size and location of the child. However, rather than use this default, 755 /// consider using a [ClipRect], which can achieve the same effect more 756 /// efficiently. 757 const ClipPath({ 758 Key key, 759 this.clipper, 760 this.clipBehavior = Clip.antiAlias, 761 Widget child, 762 }) : super(key: key, child: child); 763 764 /// Creates a shape clip. 765 /// 766 /// Uses a [ShapeBorderClipper] to configure the [ClipPath] to clip to the 767 /// given [ShapeBorder]. 768 static Widget shape({ 769 Key key, 770 @required ShapeBorder shape, 771 Clip clipBehavior = Clip.antiAlias, 772 Widget child, 773 }) { 774 assert(shape != null); 775 return Builder( 776 key: key, 777 builder: (BuildContext context) { 778 return ClipPath( 779 clipper: ShapeBorderClipper( 780 shape: shape, 781 textDirection: Directionality.of(context), 782 ), 783 clipBehavior: clipBehavior, 784 child: child, 785 ); 786 }, 787 ); 788 } 789 790 /// If non-null, determines which clip to use. 791 /// 792 /// The default clip, which is used if this property is null, is the 793 /// bounding box rectangle of the widget. [ClipRect] is a more 794 /// efficient way of obtaining that effect. 795 final CustomClipper<Path> clipper; 796 797 /// {@macro flutter.clipper.clipBehavior} 798 final Clip clipBehavior; 799 800 @override 801 RenderClipPath createRenderObject(BuildContext context) => RenderClipPath(clipper: clipper, clipBehavior: clipBehavior); 802 803 @override 804 void updateRenderObject(BuildContext context, RenderClipPath renderObject) { 805 renderObject 806 ..clipper = clipper 807 ..clipBehavior = clipBehavior; 808 } 809 810 @override 811 void didUnmountRenderObject(RenderClipPath renderObject) { 812 renderObject.clipper = null; 813 } 814 815 @override 816 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 817 super.debugFillProperties(properties); 818 properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper, defaultValue: null)); 819 } 820} 821 822/// A widget representing a physical layer that clips its children to a shape. 823/// 824/// Physical layers cast shadows based on an [elevation] which is nominally in 825/// logical pixels, coming vertically out of the rendering surface. 826/// 827/// For shapes that cannot be expressed as a rectangle with rounded corners use 828/// [PhysicalShape]. 829/// 830/// See also: 831/// 832/// * [AnimatedPhysicalModel], which animates property changes smoothly over 833/// a given duration. 834/// * [DecoratedBox], which can apply more arbitrary shadow effects. 835/// * [ClipRect], which applies a clip to its child. 836class PhysicalModel extends SingleChildRenderObjectWidget { 837 /// Creates a physical model with a rounded-rectangular clip. 838 /// 839 /// The [color] is required; physical things have a color. 840 /// 841 /// The [shape], [elevation], [color], and [shadowColor] must not be null. 842 /// Additionally, the [elevation] must be non-negative. 843 const PhysicalModel({ 844 Key key, 845 this.shape = BoxShape.rectangle, 846 this.clipBehavior = Clip.none, 847 this.borderRadius, 848 this.elevation = 0.0, 849 @required this.color, 850 this.shadowColor = const Color(0xFF000000), 851 Widget child, 852 }) : assert(shape != null), 853 assert(elevation != null && elevation >= 0.0), 854 assert(color != null), 855 assert(shadowColor != null), 856 super(key: key, child: child); 857 858 /// The type of shape. 859 final BoxShape shape; 860 861 /// {@macro flutter.widgets.Clip} 862 final Clip clipBehavior; 863 864 /// The border radius of the rounded corners. 865 /// 866 /// Values are clamped so that horizontal and vertical radii sums do not 867 /// exceed width/height. 868 /// 869 /// This is ignored if the [shape] is not [BoxShape.rectangle]. 870 final BorderRadius borderRadius; 871 872 /// The z-coordinate relative to the parent at which to place this physical 873 /// object. 874 /// 875 /// The value is non-negative. 876 final double elevation; 877 878 /// The background color. 879 final Color color; 880 881 /// The shadow color. 882 final Color shadowColor; 883 884 @override 885 RenderPhysicalModel createRenderObject(BuildContext context) { 886 return RenderPhysicalModel( 887 shape: shape, 888 clipBehavior: clipBehavior, 889 borderRadius: borderRadius, 890 elevation: elevation, color: color, 891 shadowColor: shadowColor, 892 ); 893 } 894 895 @override 896 void updateRenderObject(BuildContext context, RenderPhysicalModel renderObject) { 897 renderObject 898 ..shape = shape 899 ..clipBehavior = clipBehavior 900 ..borderRadius = borderRadius 901 ..elevation = elevation 902 ..color = color 903 ..shadowColor = shadowColor; 904 } 905 906 @override 907 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 908 super.debugFillProperties(properties); 909 properties.add(EnumProperty<BoxShape>('shape', shape)); 910 properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius)); 911 properties.add(DoubleProperty('elevation', elevation)); 912 properties.add(ColorProperty('color', color)); 913 properties.add(ColorProperty('shadowColor', shadowColor)); 914 } 915} 916 917/// A widget representing a physical layer that clips its children to a path. 918/// 919/// Physical layers cast shadows based on an [elevation] which is nominally in 920/// logical pixels, coming vertically out of the rendering surface. 921/// 922/// [PhysicalModel] does the same but only supports shapes that can be expressed 923/// as rectangles with rounded corners. 924/// 925/// See also: 926/// 927/// * [ShapeBorderClipper], which converts a [ShapeBorder] to a [CustomerClipper], as 928/// needed by this widget. 929class PhysicalShape extends SingleChildRenderObjectWidget { 930 /// Creates a physical model with an arbitrary shape clip. 931 /// 932 /// The [color] is required; physical things have a color. 933 /// 934 /// The [clipper], [elevation], [color], and [shadowColor] must not be null. 935 /// Additionally, the [elevation] must be non-negative. 936 const PhysicalShape({ 937 Key key, 938 @required this.clipper, 939 this.clipBehavior = Clip.none, 940 this.elevation = 0.0, 941 @required this.color, 942 this.shadowColor = const Color(0xFF000000), 943 Widget child, 944 }) : assert(clipper != null), 945 assert(clipBehavior != null), 946 assert(elevation != null && elevation >= 0.0), 947 assert(color != null), 948 assert(shadowColor != null), 949 super(key: key, child: child); 950 951 /// Determines which clip to use. 952 /// 953 /// If the path in question is expressed as a [ShapeBorder] subclass, 954 /// consider using the [ShapeBorderClipper] delegate class to adapt the 955 /// shape for use with this widget. 956 final CustomClipper<Path> clipper; 957 958 /// {@macro flutter.widgets.Clip} 959 final Clip clipBehavior; 960 961 /// The z-coordinate relative to the parent at which to place this physical 962 /// object. 963 /// 964 /// The value is non-negative. 965 final double elevation; 966 967 /// The background color. 968 final Color color; 969 970 /// When elevation is non zero the color to use for the shadow color. 971 final Color shadowColor; 972 973 @override 974 RenderPhysicalShape createRenderObject(BuildContext context) { 975 return RenderPhysicalShape( 976 clipper: clipper, 977 clipBehavior: clipBehavior, 978 elevation: elevation, 979 color: color, 980 shadowColor: shadowColor, 981 ); 982 } 983 984 @override 985 void updateRenderObject(BuildContext context, RenderPhysicalShape renderObject) { 986 renderObject 987 ..clipper = clipper 988 ..clipBehavior = clipBehavior 989 ..elevation = elevation 990 ..color = color 991 ..shadowColor = shadowColor; 992 } 993 994 @override 995 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 996 super.debugFillProperties(properties); 997 properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper)); 998 properties.add(DoubleProperty('elevation', elevation)); 999 properties.add(ColorProperty('color', color)); 1000 properties.add(ColorProperty('shadowColor', shadowColor)); 1001 } 1002} 1003 1004// POSITIONING AND SIZING NODES 1005 1006/// A widget that applies a transformation before painting its child. 1007/// 1008/// Unlike [RotatedBox], which applies a rotation prior to layout, this object 1009/// applies its transformation just prior to painting, which means the 1010/// transformation is not taken into account when calculating how much space 1011/// this widget's child (and thus this widget) consumes. 1012/// 1013/// {@youtube 560 315 https://www.youtube.com/watch?v=9z_YNlRlWfA} 1014/// 1015/// {@tool sample} 1016/// 1017/// This example rotates and skews an orange box containing text, keeping the 1018/// top right corner pinned to its original position. 1019/// 1020/// ```dart 1021/// Container( 1022/// color: Colors.black, 1023/// child: Transform( 1024/// alignment: Alignment.topRight, 1025/// transform: Matrix4.skewY(0.3)..rotateZ(-math.pi / 12.0), 1026/// child: Container( 1027/// padding: const EdgeInsets.all(8.0), 1028/// color: const Color(0xFFE8581C), 1029/// child: const Text('Apartment for rent!'), 1030/// ), 1031/// ), 1032/// ) 1033/// ``` 1034/// {@end-tool} 1035/// 1036/// See also: 1037/// 1038/// * [RotatedBox], which rotates the child widget during layout, not just 1039/// during painting. 1040/// * [FractionalTranslation], which applies a translation to the child 1041/// that is relative to the child's size. 1042/// * [FittedBox], which sizes and positions its child widget to fit the parent 1043/// according to a given [BoxFit] discipline. 1044class Transform extends SingleChildRenderObjectWidget { 1045 /// Creates a widget that transforms its child. 1046 /// 1047 /// The [transform] argument must not be null. 1048 const Transform({ 1049 Key key, 1050 @required this.transform, 1051 this.origin, 1052 this.alignment, 1053 this.transformHitTests = true, 1054 Widget child, 1055 }) : assert(transform != null), 1056 super(key: key, child: child); 1057 1058 /// Creates a widget that transforms its child using a rotation around the 1059 /// center. 1060 /// 1061 /// The `angle` argument must not be null. It gives the rotation in clockwise 1062 /// radians. 1063 /// 1064 /// {@tool sample} 1065 /// 1066 /// This example rotates an orange box containing text around its center by 1067 /// fifteen degrees. 1068 /// 1069 /// ```dart 1070 /// Transform.rotate( 1071 /// angle: -math.pi / 12.0, 1072 /// child: Container( 1073 /// padding: const EdgeInsets.all(8.0), 1074 /// color: const Color(0xFFE8581C), 1075 /// child: const Text('Apartment for rent!'), 1076 /// ), 1077 /// ) 1078 /// ``` 1079 /// {@end-tool} 1080 /// 1081 /// See also: 1082 /// 1083 /// * [RotationTransition], which animates changes in rotation smoothly 1084 /// over a given duration. 1085 Transform.rotate({ 1086 Key key, 1087 @required double angle, 1088 this.origin, 1089 this.alignment = Alignment.center, 1090 this.transformHitTests = true, 1091 Widget child, 1092 }) : transform = Matrix4.rotationZ(angle), 1093 super(key: key, child: child); 1094 1095 /// Creates a widget that transforms its child using a translation. 1096 /// 1097 /// The `offset` argument must not be null. It specifies the translation. 1098 /// 1099 /// {@tool sample} 1100 /// 1101 /// This example shifts the silver-colored child down by fifteen pixels. 1102 /// 1103 /// ```dart 1104 /// Transform.translate( 1105 /// offset: const Offset(0.0, 15.0), 1106 /// child: Container( 1107 /// padding: const EdgeInsets.all(8.0), 1108 /// color: const Color(0xFF7F7F7F), 1109 /// child: const Text('Quarter'), 1110 /// ), 1111 /// ) 1112 /// ``` 1113 /// {@end-tool} 1114 Transform.translate({ 1115 Key key, 1116 @required Offset offset, 1117 this.transformHitTests = true, 1118 Widget child, 1119 }) : transform = Matrix4.translationValues(offset.dx, offset.dy, 0.0), 1120 origin = null, 1121 alignment = null, 1122 super(key: key, child: child); 1123 1124 /// Creates a widget that scales its child uniformly. 1125 /// 1126 /// The `scale` argument must not be null. It gives the scalar by which 1127 /// to multiply the `x` and `y` axes. 1128 /// 1129 /// The [alignment] controls the origin of the scale; by default, this is 1130 /// the center of the box. 1131 /// 1132 /// {@tool sample} 1133 /// 1134 /// This example shrinks an orange box containing text such that each dimension 1135 /// is half the size it would otherwise be. 1136 /// 1137 /// ```dart 1138 /// Transform.scale( 1139 /// scale: 0.5, 1140 /// child: Container( 1141 /// padding: const EdgeInsets.all(8.0), 1142 /// color: const Color(0xFFE8581C), 1143 /// child: const Text('Bad Ideas'), 1144 /// ), 1145 /// ) 1146 /// ``` 1147 /// {@end-tool} 1148 /// 1149 /// See also: 1150 /// 1151 /// * [ScaleTransition], which animates changes in scale smoothly 1152 /// over a given duration. 1153 Transform.scale({ 1154 Key key, 1155 @required double scale, 1156 this.origin, 1157 this.alignment = Alignment.center, 1158 this.transformHitTests = true, 1159 Widget child, 1160 }) : transform = Matrix4.diagonal3Values(scale, scale, 1.0), 1161 super(key: key, child: child); 1162 1163 /// The matrix to transform the child by during painting. 1164 final Matrix4 transform; 1165 1166 /// The origin of the coordinate system (relative to the upper left corder of 1167 /// this render object) in which to apply the matrix. 1168 /// 1169 /// Setting an origin is equivalent to conjugating the transform matrix by a 1170 /// translation. This property is provided just for convenience. 1171 final Offset origin; 1172 1173 /// The alignment of the origin, relative to the size of the box. 1174 /// 1175 /// This is equivalent to setting an origin based on the size of the box. 1176 /// If it is specified at the same time as the [origin], both are applied. 1177 /// 1178 /// An [AlignmentDirectional.start] value is the same as an [Alignment] 1179 /// whose [Alignment.x] value is `-1.0` if [textDirection] is 1180 /// [TextDirection.ltr], and `1.0` if [textDirection] is [TextDirection.rtl]. 1181 /// Similarly [AlignmentDirectional.end] is the same as an [Alignment] 1182 /// whose [Alignment.x] value is `1.0` if [textDirection] is 1183 /// [TextDirection.ltr], and `-1.0` if [textDirection] is [TextDirection.rtl]. 1184 final AlignmentGeometry alignment; 1185 1186 /// Whether to apply the transformation when performing hit tests. 1187 final bool transformHitTests; 1188 1189 @override 1190 RenderTransform createRenderObject(BuildContext context) { 1191 return RenderTransform( 1192 transform: transform, 1193 origin: origin, 1194 alignment: alignment, 1195 textDirection: Directionality.of(context), 1196 transformHitTests: transformHitTests, 1197 ); 1198 } 1199 1200 @override 1201 void updateRenderObject(BuildContext context, RenderTransform renderObject) { 1202 renderObject 1203 ..transform = transform 1204 ..origin = origin 1205 ..alignment = alignment 1206 ..textDirection = Directionality.of(context) 1207 ..transformHitTests = transformHitTests; 1208 } 1209} 1210 1211/// A widget that can be targeted by a [CompositedTransformFollower]. 1212/// 1213/// When this widget is composited during the compositing phase (which comes 1214/// after the paint phase, as described in [WidgetsBinding.drawFrame]), it 1215/// updates the [link] object so that any [CompositedTransformFollower] widgets 1216/// that are subsequently composited in the same frame and were given the same 1217/// [LayerLink] can position themselves at the same screen location. 1218/// 1219/// A single [CompositedTransformTarget] can be followed by multiple 1220/// [CompositedTransformFollower] widgets. 1221/// 1222/// The [CompositedTransformTarget] must come earlier in the paint order than 1223/// any linked [CompositedTransformFollower]s. 1224/// 1225/// See also: 1226/// 1227/// * [CompositedTransformFollower], the widget that can target this one. 1228/// * [LeaderLayer], the layer that implements this widget's logic. 1229class CompositedTransformTarget extends SingleChildRenderObjectWidget { 1230 /// Creates a composited transform target widget. 1231 /// 1232 /// The [link] property must not be null, and must not be currently being used 1233 /// by any other [CompositedTransformTarget] object that is in the tree. 1234 const CompositedTransformTarget({ 1235 Key key, 1236 @required this.link, 1237 Widget child, 1238 }) : assert(link != null), 1239 super(key: key, child: child); 1240 1241 /// The link object that connects this [CompositedTransformTarget] with one or 1242 /// more [CompositedTransformFollower]s. 1243 /// 1244 /// This property must not be null. The object must not be associated with 1245 /// another [CompositedTransformTarget] that is also being painted. 1246 final LayerLink link; 1247 1248 @override 1249 RenderLeaderLayer createRenderObject(BuildContext context) { 1250 return RenderLeaderLayer( 1251 link: link, 1252 ); 1253 } 1254 1255 @override 1256 void updateRenderObject(BuildContext context, RenderLeaderLayer renderObject) { 1257 renderObject 1258 ..link = link; 1259 } 1260} 1261 1262/// A widget that follows a [CompositedTransformTarget]. 1263/// 1264/// When this widget is composited during the compositing phase (which comes 1265/// after the paint phase, as described in [WidgetsBinding.drawFrame]), it 1266/// applies a transformation that causes it to provide its child with a 1267/// coordinate space that matches that of the linked [CompositedTransformTarget] 1268/// widget, offset by [offset]. 1269/// 1270/// The [LayerLink] object used as the [link] must be the same object as that 1271/// provided to the matching [CompositedTransformTarget]. 1272/// 1273/// The [CompositedTransformTarget] must come earlier in the paint order than 1274/// this [CompositedTransformFollower]. 1275/// 1276/// Hit testing on descendants of this widget will only work if the target 1277/// position is within the box that this widget's parent considers to be 1278/// hittable. If the parent covers the screen, this is trivially achievable, so 1279/// this widget is usually used as the root of an [OverlayEntry] in an app-wide 1280/// [Overlay] (e.g. as created by the [MaterialApp] widget's [Navigator]). 1281/// 1282/// See also: 1283/// 1284/// * [CompositedTransformTarget], the widget that this widget can target. 1285/// * [FollowerLayer], the layer that implements this widget's logic. 1286/// * [Transform], which applies an arbitrary transform to a child. 1287class CompositedTransformFollower extends SingleChildRenderObjectWidget { 1288 /// Creates a composited transform target widget. 1289 /// 1290 /// The [link] property must not be null. If it was also provided to a 1291 /// [CompositedTransformTarget], that widget must come earlier in the paint 1292 /// order. 1293 /// 1294 /// The [showWhenUnlinked] and [offset] properties must also not be null. 1295 const CompositedTransformFollower({ 1296 Key key, 1297 @required this.link, 1298 this.showWhenUnlinked = true, 1299 this.offset = Offset.zero, 1300 Widget child, 1301 }) : assert(link != null), 1302 assert(showWhenUnlinked != null), 1303 assert(offset != null), 1304 super(key: key, child: child); 1305 1306 /// The link object that connects this [CompositedTransformFollower] with a 1307 /// [CompositedTransformTarget]. 1308 /// 1309 /// This property must not be null. 1310 final LayerLink link; 1311 1312 /// Whether to show the widget's contents when there is no corresponding 1313 /// [CompositedTransformTarget] with the same [link]. 1314 /// 1315 /// When the widget is linked, the child is positioned such that it has the 1316 /// same global position as the linked [CompositedTransformTarget]. 1317 /// 1318 /// When the widget is not linked, then: if [showWhenUnlinked] is true, the 1319 /// child is visible and not repositioned; if it is false, then child is 1320 /// hidden. 1321 final bool showWhenUnlinked; 1322 1323 /// The offset to apply to the origin of the linked 1324 /// [CompositedTransformTarget] to obtain this widget's origin. 1325 final Offset offset; 1326 1327 @override 1328 RenderFollowerLayer createRenderObject(BuildContext context) { 1329 return RenderFollowerLayer( 1330 link: link, 1331 showWhenUnlinked: showWhenUnlinked, 1332 offset: offset, 1333 ); 1334 } 1335 1336 @override 1337 void updateRenderObject(BuildContext context, RenderFollowerLayer renderObject) { 1338 renderObject 1339 ..link = link 1340 ..showWhenUnlinked = showWhenUnlinked 1341 ..offset = offset; 1342 } 1343} 1344 1345/// Scales and positions its child within itself according to [fit]. 1346/// 1347/// {@youtube 560 315 https://www.youtube.com/watch?v=T4Uehk3_wlY} 1348/// 1349/// See also: 1350/// 1351/// * [Transform], which applies an arbitrary transform to its child widget at 1352/// paint time. 1353/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1354class FittedBox extends SingleChildRenderObjectWidget { 1355 /// Creates a widget that scales and positions its child within itself according to [fit]. 1356 /// 1357 /// The [fit] and [alignment] arguments must not be null. 1358 const FittedBox({ 1359 Key key, 1360 this.fit = BoxFit.contain, 1361 this.alignment = Alignment.center, 1362 Widget child, 1363 }) : assert(fit != null), 1364 assert(alignment != null), 1365 super(key: key, child: child); 1366 1367 /// How to inscribe the child into the space allocated during layout. 1368 final BoxFit fit; 1369 1370 /// How to align the child within its parent's bounds. 1371 /// 1372 /// An alignment of (-1.0, -1.0) aligns the child to the top-left corner of its 1373 /// parent's bounds. An alignment of (1.0, 0.0) aligns the child to the middle 1374 /// of the right edge of its parent's bounds. 1375 /// 1376 /// Defaults to [Alignment.center]. 1377 /// 1378 /// See also: 1379 /// 1380 /// * [Alignment], a class with convenient constants typically used to 1381 /// specify an [AlignmentGeometry]. 1382 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 1383 /// relative to text direction. 1384 final AlignmentGeometry alignment; 1385 1386 @override 1387 RenderFittedBox createRenderObject(BuildContext context) { 1388 return RenderFittedBox( 1389 fit: fit, 1390 alignment: alignment, 1391 textDirection: Directionality.of(context), 1392 ); 1393 } 1394 1395 @override 1396 void updateRenderObject(BuildContext context, RenderFittedBox renderObject) { 1397 renderObject 1398 ..fit = fit 1399 ..alignment = alignment 1400 ..textDirection = Directionality.of(context); 1401 } 1402 1403 @override 1404 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 1405 super.debugFillProperties(properties); 1406 properties.add(EnumProperty<BoxFit>('fit', fit)); 1407 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 1408 } 1409} 1410 1411/// Applies a translation transformation before painting its child. 1412/// 1413/// The translation is expressed as a [Offset] scaled to the child's size. For 1414/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal 1415/// translation of one quarter the width of the child. 1416/// 1417/// Hit tests will only be detected inside the bounds of the 1418/// [FractionalTranslation], even if the contents are offset such that 1419/// they overflow. 1420/// 1421/// See also: 1422/// 1423/// * [Transform], which applies an arbitrary transform to its child widget at 1424/// paint time. 1425/// * [new Transform.translate], which applies an absolute offset translation 1426/// transformation instead of an offset scaled to the child. 1427/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1428class FractionalTranslation extends SingleChildRenderObjectWidget { 1429 /// Creates a widget that translates its child's painting. 1430 /// 1431 /// The [translation] argument must not be null. 1432 const FractionalTranslation({ 1433 Key key, 1434 @required this.translation, 1435 this.transformHitTests = true, 1436 Widget child, 1437 }) : assert(translation != null), 1438 super(key: key, child: child); 1439 1440 /// The translation to apply to the child, scaled to the child's size. 1441 /// 1442 /// For example, an [Offset] with a `dx` of 0.25 will result in a horizontal 1443 /// translation of one quarter the width of the child. 1444 final Offset translation; 1445 1446 /// Whether to apply the translation when performing hit tests. 1447 final bool transformHitTests; 1448 1449 @override 1450 RenderFractionalTranslation createRenderObject(BuildContext context) { 1451 return RenderFractionalTranslation( 1452 translation: translation, 1453 transformHitTests: transformHitTests, 1454 ); 1455 } 1456 1457 @override 1458 void updateRenderObject(BuildContext context, RenderFractionalTranslation renderObject) { 1459 renderObject 1460 ..translation = translation 1461 ..transformHitTests = transformHitTests; 1462 } 1463} 1464 1465/// A widget that rotates its child by a integral number of quarter turns. 1466/// 1467/// Unlike [Transform], which applies a transform just prior to painting, 1468/// this object applies its rotation prior to layout, which means the entire 1469/// rotated box consumes only as much space as required by the rotated child. 1470/// 1471/// {@tool sample} 1472/// 1473/// This snippet rotates the child (some [Text]) so that it renders from bottom 1474/// to top, like an axis label on a graph: 1475/// 1476/// ```dart 1477/// RotatedBox( 1478/// quarterTurns: 3, 1479/// child: const Text('Hello World!'), 1480/// ) 1481/// ``` 1482/// {@end-tool} 1483/// 1484/// See also: 1485/// 1486/// * [Transform], which is a paint effect that allows you to apply an 1487/// arbitrary transform to a child. 1488/// * [new Transform.rotate], which applies a rotation paint effect. 1489/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1490class RotatedBox extends SingleChildRenderObjectWidget { 1491 /// A widget that rotates its child. 1492 /// 1493 /// The [quarterTurns] argument must not be null. 1494 const RotatedBox({ 1495 Key key, 1496 @required this.quarterTurns, 1497 Widget child, 1498 }) : assert(quarterTurns != null), 1499 super(key: key, child: child); 1500 1501 /// The number of clockwise quarter turns the child should be rotated. 1502 final int quarterTurns; 1503 1504 @override 1505 RenderRotatedBox createRenderObject(BuildContext context) => RenderRotatedBox(quarterTurns: quarterTurns); 1506 1507 @override 1508 void updateRenderObject(BuildContext context, RenderRotatedBox renderObject) { 1509 renderObject.quarterTurns = quarterTurns; 1510 } 1511} 1512 1513/// A widget that insets its child by the given padding. 1514/// 1515/// When passing layout constraints to its child, padding shrinks the 1516/// constraints by the given padding, causing the child to layout at a smaller 1517/// size. Padding then sizes itself to its child's size, inflated by the 1518/// padding, effectively creating empty space around the child. 1519/// 1520/// {@tool sample} 1521/// 1522/// This snippet indents the child (a [Card] with some [Text]) by eight pixels 1523/// in each direction: 1524/// 1525/// ```dart 1526/// Padding( 1527/// padding: EdgeInsets.all(8.0), 1528/// child: const Card(child: Text('Hello World!')), 1529/// ) 1530/// ``` 1531/// {@end-tool} 1532/// 1533/// ## Design discussion 1534/// 1535/// ### Why use a [Padding] widget rather than a [Container] with a [Container.padding] property? 1536/// 1537/// There isn't really any difference between the two. If you supply a 1538/// [Container.padding] argument, [Container] simply builds a [Padding] widget 1539/// for you. 1540/// 1541/// [Container] doesn't implement its properties directly. Instead, [Container] 1542/// combines a number of simpler widgets together into a convenient package. For 1543/// example, the [Container.padding] property causes the container to build a 1544/// [Padding] widget and the [Container.decoration] property causes the 1545/// container to build a [DecoratedBox] widget. If you find [Container] 1546/// convenient, feel free to use it. If not, feel free to build these simpler 1547/// widgets in whatever combination meets your needs. 1548/// 1549/// In fact, the majority of widgets in Flutter are simply combinations of other 1550/// simpler widgets. Composition, rather than inheritance, is the primary 1551/// mechanism for building up widgets. 1552/// 1553/// See also: 1554/// 1555/// * [AnimatedPadding], which animates changes in [padding] over a given 1556/// duration. 1557/// * [EdgeInsets], the class that is used to describe the padding dimensions. 1558/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1559class Padding extends SingleChildRenderObjectWidget { 1560 /// Creates a widget that insets its child. 1561 /// 1562 /// The [padding] argument must not be null. 1563 const Padding({ 1564 Key key, 1565 @required this.padding, 1566 Widget child, 1567 }) : assert(padding != null), 1568 super(key: key, child: child); 1569 1570 /// The amount of space by which to inset the child. 1571 final EdgeInsetsGeometry padding; 1572 1573 @override 1574 RenderPadding createRenderObject(BuildContext context) { 1575 return RenderPadding( 1576 padding: padding, 1577 textDirection: Directionality.of(context), 1578 ); 1579 } 1580 1581 @override 1582 void updateRenderObject(BuildContext context, RenderPadding renderObject) { 1583 renderObject 1584 ..padding = padding 1585 ..textDirection = Directionality.of(context); 1586 } 1587 1588 @override 1589 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 1590 super.debugFillProperties(properties); 1591 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding)); 1592 } 1593} 1594 1595/// A widget that aligns its child within itself and optionally sizes itself 1596/// based on the child's size. 1597/// 1598/// For example, to align a box at the bottom right, you would pass this box a 1599/// tight constraint that is bigger than the child's natural size, 1600/// with an alignment of [Alignment.bottomRight]. 1601/// 1602/// {@youtube 560 315 https://www.youtube.com/watch?v=g2E7yl3MwMk} 1603/// 1604/// This widget will be as big as possible if its dimensions are constrained and 1605/// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained 1606/// and the corresponding size factor is null then the widget will match its 1607/// child's size in that dimension. If a size factor is non-null then the 1608/// corresponding dimension of this widget will be the product of the child's 1609/// dimension and the size factor. For example if widthFactor is 2.0 then 1610/// the width of this widget will always be twice its child's width. 1611/// 1612/// ## How it works 1613/// 1614/// The [alignment] property describes a point in the `child`'s coordinate system 1615/// and a different point in the coordinate system of this widget. The [Align] 1616/// widget positions the `child` such that both points are lined up on top of 1617/// each other. 1618/// 1619/// {@tool sample} 1620/// The [Align] widget in this example uses one of the defined constants from 1621/// [Alignment], [topRight]. This places the [FlutterLogo] in the top right corner 1622/// of the parent blue [Container]. 1623/// 1624///  1625/// 1626/// ```dart 1627/// Center( 1628/// child: Container( 1629/// height: 120.0, 1630/// width: 120.0, 1631/// color: Colors.blue[50], 1632/// child: Align( 1633/// alignment: Alignment.topRight, 1634/// child: FlutterLogo( 1635/// size: 60, 1636/// ), 1637/// ), 1638/// ), 1639/// ) 1640/// ``` 1641/// {@end-tool} 1642/// 1643/// {@tool sample} 1644/// The [Alignment] used in the following example defines a single point: 1645/// 1646/// * (0.2 * width of [FlutterLogo]/2 + width of [FlutterLogo]/2, 0.6 * height 1647/// of [FlutterLogo]/2 + height of [FlutterLogo]/2) = (36.0, 48.0). 1648/// 1649/// The [Alignment] class uses a coordinate system with an origin in the center 1650/// of the [Container], as shown with the [Icon] above. [Align] will place the 1651/// [FlutterLogo] at (36.0, 48.0) according to this coordinate system. 1652/// 1653///  1656/// 1657/// ```dart 1658/// Center( 1659/// child: Container( 1660/// height: 120.0, 1661/// width: 120.0, 1662/// color: Colors.blue[50], 1663/// child: Align( 1664/// alignment: Alignment(0.2, 0.6), 1665/// child: FlutterLogo( 1666/// size: 60, 1667/// ), 1668/// ), 1669/// ), 1670/// ) 1671/// ``` 1672/// {@end-tool} 1673/// 1674/// {@tool sample} 1675/// The [FractionalOffset] used in the following example defines two points: 1676/// 1677/// * (0.2 * width of [FlutterLogo], 0.6 * height of [FlutterLogo]) = (12.0, 36.0) 1678/// in the coordinate system of the blue container. 1679/// * (0.2 * width of [Align], 0.6 * height of [Align]) = (24.0, 72.0) in the 1680/// coordinate system of the [Align] widget. 1681/// 1682/// The [Align] widget positions the [FlutterLogo] such that the two points are on 1683/// top of each other. In this example, the top left of the [FlutterLogo] will 1684/// be placed at (24.0, 72.0) - (12.0, 36.0) = (12.0, 36.0) from the top left of 1685/// the [Align] widget. 1686/// 1687/// The [FractionalOffset] class uses a coordinate system with an origin in the top-left 1688/// corner of the [Container] in difference to the center-oriented system used in 1689/// the example above with [Alignment]. 1690/// 1691///  1694/// 1695/// ```dart 1696/// Center( 1697/// child: Container( 1698/// height: 120.0, 1699/// width: 120.0, 1700/// color: Colors.blue[50], 1701/// child: Align( 1702/// alignment: FractionalOffset(0.2, 0.6), 1703/// child: FlutterLogo( 1704/// size: 60, 1705/// ), 1706/// ), 1707/// ), 1708/// ) 1709/// ``` 1710/// {@end-tool} 1711/// 1712/// See also: 1713/// 1714/// * [AnimatedAlign], which animates changes in [alignment] smoothly over a 1715/// given duration. 1716/// * [CustomSingleChildLayout], which uses a delegate to control the layout of 1717/// a single child. 1718/// * [Center], which is the same as [Align] but with the [alignment] always 1719/// set to [Alignment.center]. 1720/// * [FractionallySizedBox], which sizes its child based on a fraction of its 1721/// own size and positions the child according to an [Alignment] value. 1722/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1723class Align extends SingleChildRenderObjectWidget { 1724 /// Creates an alignment widget. 1725 /// 1726 /// The alignment defaults to [Alignment.center]. 1727 const Align({ 1728 Key key, 1729 this.alignment = Alignment.center, 1730 this.widthFactor, 1731 this.heightFactor, 1732 Widget child, 1733 }) : assert(alignment != null), 1734 assert(widthFactor == null || widthFactor >= 0.0), 1735 assert(heightFactor == null || heightFactor >= 0.0), 1736 super(key: key, child: child); 1737 1738 /// How to align the child. 1739 /// 1740 /// The x and y values of the [Alignment] control the horizontal and vertical 1741 /// alignment, respectively. An x value of -1.0 means that the left edge of 1742 /// the child is aligned with the left edge of the parent whereas an x value 1743 /// of 1.0 means that the right edge of the child is aligned with the right 1744 /// edge of the parent. Other values interpolate (and extrapolate) linearly. 1745 /// For example, a value of 0.0 means that the center of the child is aligned 1746 /// with the center of the parent. 1747 /// 1748 /// See also: 1749 /// 1750 /// * [Alignment], which has more details and some convenience constants for 1751 /// common positions. 1752 /// * [AlignmentDirectional], which has a horizontal coordinate orientation 1753 /// that depends on the [TextDirection]. 1754 final AlignmentGeometry alignment; 1755 1756 /// If non-null, sets its width to the child's width multiplied by this factor. 1757 /// 1758 /// Can be both greater and less than 1.0 but must be positive. 1759 final double widthFactor; 1760 1761 /// If non-null, sets its height to the child's height multiplied by this factor. 1762 /// 1763 /// Can be both greater and less than 1.0 but must be positive. 1764 final double heightFactor; 1765 1766 @override 1767 RenderPositionedBox createRenderObject(BuildContext context) { 1768 return RenderPositionedBox( 1769 alignment: alignment, 1770 widthFactor: widthFactor, 1771 heightFactor: heightFactor, 1772 textDirection: Directionality.of(context), 1773 ); 1774 } 1775 1776 @override 1777 void updateRenderObject(BuildContext context, RenderPositionedBox renderObject) { 1778 renderObject 1779 ..alignment = alignment 1780 ..widthFactor = widthFactor 1781 ..heightFactor = heightFactor 1782 ..textDirection = Directionality.of(context); 1783 } 1784 1785 @override 1786 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 1787 super.debugFillProperties(properties); 1788 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 1789 properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null)); 1790 properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null)); 1791 } 1792} 1793 1794/// A widget that centers its child within itself. 1795/// 1796/// This widget will be as big as possible if its dimensions are constrained and 1797/// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained 1798/// and the corresponding size factor is null then the widget will match its 1799/// child's size in that dimension. If a size factor is non-null then the 1800/// corresponding dimension of this widget will be the product of the child's 1801/// dimension and the size factor. For example if widthFactor is 2.0 then 1802/// the width of this widget will always be twice its child's width. 1803/// 1804/// See also: 1805/// 1806/// * [Align], which lets you arbitrarily position a child within itself, 1807/// rather than just centering it. 1808/// * [Row], a widget that displays its children in a horizontal array. 1809/// * [Column], a widget that displays its children in a vertical array. 1810/// * [Container], a convenience widget that combines common painting, 1811/// positioning, and sizing widgets. 1812/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1813class Center extends Align { 1814 /// Creates a widget that centers its child. 1815 const Center({ Key key, double widthFactor, double heightFactor, Widget child }) 1816 : super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child); 1817} 1818 1819/// A widget that defers the layout of its single child to a delegate. 1820/// 1821/// The delegate can determine the layout constraints for the child and can 1822/// decide where to position the child. The delegate can also determine the size 1823/// of the parent, but the size of the parent cannot depend on the size of the 1824/// child. 1825/// 1826/// See also: 1827/// 1828/// * [SingleChildLayoutDelegate], which controls the layout of the child. 1829/// * [Align], which sizes itself based on its child's size and positions 1830/// the child according to an [Alignment] value. 1831/// * [FractionallySizedBox], which sizes its child based on a fraction of its own 1832/// size and positions the child according to an [Alignment] value. 1833/// * [CustomMultiChildLayout], which uses a delegate to position multiple 1834/// children. 1835class CustomSingleChildLayout extends SingleChildRenderObjectWidget { 1836 /// Creates a custom single child layout. 1837 /// 1838 /// The [delegate] argument must not be null. 1839 const CustomSingleChildLayout({ 1840 Key key, 1841 @required this.delegate, 1842 Widget child, 1843 }) : assert(delegate != null), 1844 super(key: key, child: child); 1845 1846 /// The delegate that controls the layout of the child. 1847 final SingleChildLayoutDelegate delegate; 1848 1849 @override 1850 RenderCustomSingleChildLayoutBox createRenderObject(BuildContext context) { 1851 return RenderCustomSingleChildLayoutBox(delegate: delegate); 1852 } 1853 1854 @override 1855 void updateRenderObject(BuildContext context, RenderCustomSingleChildLayoutBox renderObject) { 1856 renderObject.delegate = delegate; 1857 } 1858} 1859 1860/// Metadata for identifying children in a [CustomMultiChildLayout]. 1861/// 1862/// The [MultiChildLayoutDelegate.hasChild], 1863/// [MultiChildLayoutDelegate.layoutChild], and 1864/// [MultiChildLayoutDelegate.positionChild] methods use these identifiers. 1865class LayoutId extends ParentDataWidget<CustomMultiChildLayout> { 1866 /// Marks a child with a layout identifier. 1867 /// 1868 /// Both the child and the id arguments must not be null. 1869 LayoutId({ 1870 Key key, 1871 @required this.id, 1872 @required Widget child, 1873 }) : assert(child != null), 1874 assert(id != null), 1875 super(key: key ?? ValueKey<Object>(id), child: child); 1876 1877 /// An object representing the identity of this child. 1878 /// 1879 /// The [id] needs to be unique among the children that the 1880 /// [CustomMultiChildLayout] manages. 1881 final Object id; 1882 1883 @override 1884 void applyParentData(RenderObject renderObject) { 1885 assert(renderObject.parentData is MultiChildLayoutParentData); 1886 final MultiChildLayoutParentData parentData = renderObject.parentData; 1887 if (parentData.id != id) { 1888 parentData.id = id; 1889 final AbstractNode targetParent = renderObject.parent; 1890 if (targetParent is RenderObject) 1891 targetParent.markNeedsLayout(); 1892 } 1893 } 1894 1895 @override 1896 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 1897 super.debugFillProperties(properties); 1898 properties.add(DiagnosticsProperty<Object>('id', id)); 1899 } 1900} 1901 1902/// A widget that uses a delegate to size and position multiple children. 1903/// 1904/// The delegate can determine the layout constraints for each child and can 1905/// decide where to position each child. The delegate can also determine the 1906/// size of the parent, but the size of the parent cannot depend on the sizes of 1907/// the children. 1908/// 1909/// [CustomMultiChildLayout] is appropriate when there are complex relationships 1910/// between the size and positioning of a multiple widgets. To control the 1911/// layout of a single child, [CustomSingleChildLayout] is more appropriate. For 1912/// simple cases, such as aligning a widget to one or another edge, the [Stack] 1913/// widget is more appropriate. 1914/// 1915/// Each child must be wrapped in a [LayoutId] widget to identify the widget for 1916/// the delegate. 1917/// 1918/// See also: 1919/// 1920/// * [MultiChildLayoutDelegate], for details about how to control the layout of 1921/// the children. 1922/// * [CustomSingleChildLayout], which uses a delegate to control the layout of 1923/// a single child. 1924/// * [Stack], which arranges children relative to the edges of the container. 1925/// * [Flow], which provides paint-time control of its children using transform 1926/// matrices. 1927class CustomMultiChildLayout extends MultiChildRenderObjectWidget { 1928 /// Creates a custom multi-child layout. 1929 /// 1930 /// The [delegate] argument must not be null. 1931 CustomMultiChildLayout({ 1932 Key key, 1933 @required this.delegate, 1934 List<Widget> children = const <Widget>[], 1935 }) : assert(delegate != null), 1936 super(key: key, children: children); 1937 1938 /// The delegate that controls the layout of the children. 1939 final MultiChildLayoutDelegate delegate; 1940 1941 @override 1942 RenderCustomMultiChildLayoutBox createRenderObject(BuildContext context) { 1943 return RenderCustomMultiChildLayoutBox(delegate: delegate); 1944 } 1945 1946 @override 1947 void updateRenderObject(BuildContext context, RenderCustomMultiChildLayoutBox renderObject) { 1948 renderObject.delegate = delegate; 1949 } 1950} 1951 1952/// A box with a specified size. 1953/// 1954/// If given a child, this widget forces its child to have a specific width 1955/// and/or height (assuming values are permitted by this widget's parent). If 1956/// either the width or height is null, this widget will size itself to match 1957/// the child's size in that dimension. 1958/// 1959/// If not given a child, [SizedBox] will try to size itself as close to the 1960/// specified height and width as possible given the parent's constraints. If 1961/// [height] or [width] is null or unspecified, it will be treated as zero. 1962/// 1963/// The [new SizedBox.expand] constructor can be used to make a [SizedBox] that 1964/// sizes itself to fit the parent. It is equivalent to setting [width] and 1965/// [height] to [double.infinity]. 1966/// 1967/// {@youtube 560 315 https://www.youtube.com/watch?v=EHPu_DzRfqA} 1968/// 1969/// {@tool sample} 1970/// 1971/// This snippet makes the child widget (a [Card] with some [Text]) have the 1972/// exact size 200x300, parental constraints permitting: 1973/// 1974/// ```dart 1975/// SizedBox( 1976/// width: 200.0, 1977/// height: 300.0, 1978/// child: const Card(child: Text('Hello World!')), 1979/// ) 1980/// ``` 1981/// {@end-tool} 1982/// 1983/// See also: 1984/// 1985/// * [ConstrainedBox], a more generic version of this class that takes 1986/// arbitrary [BoxConstraints] instead of an explicit width and height. 1987/// * [UnconstrainedBox], a container that tries to let its child draw without 1988/// constraints. 1989/// * [FractionallySizedBox], a widget that sizes its child to a fraction of 1990/// the total available space. 1991/// * [AspectRatio], a widget that attempts to fit within the parent's 1992/// constraints while also sizing its child to match a given aspect ratio. 1993/// * [FittedBox], which sizes and positions its child widget to fit the parent 1994/// according to a given [BoxFit] discipline. 1995/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 1996class SizedBox extends SingleChildRenderObjectWidget { 1997 /// Creates a fixed size box. The [width] and [height] parameters can be null 1998 /// to indicate that the size of the box should not be constrained in 1999 /// the corresponding dimension. 2000 const SizedBox({ Key key, this.width, this.height, Widget child }) 2001 : super(key: key, child: child); 2002 2003 /// Creates a box that will become as large as its parent allows. 2004 const SizedBox.expand({ Key key, Widget child }) 2005 : width = double.infinity, 2006 height = double.infinity, 2007 super(key: key, child: child); 2008 2009 /// Creates a box that will become as small as its parent allows. 2010 const SizedBox.shrink({ Key key, Widget child }) 2011 : width = 0.0, 2012 height = 0.0, 2013 super(key: key, child: child); 2014 2015 /// Creates a box with the specified size. 2016 SizedBox.fromSize({ Key key, Widget child, Size size }) 2017 : width = size?.width, 2018 height = size?.height, 2019 super(key: key, child: child); 2020 2021 /// If non-null, requires the child to have exactly this width. 2022 final double width; 2023 2024 /// If non-null, requires the child to have exactly this height. 2025 final double height; 2026 2027 @override 2028 RenderConstrainedBox createRenderObject(BuildContext context) { 2029 return RenderConstrainedBox( 2030 additionalConstraints: _additionalConstraints, 2031 ); 2032 } 2033 2034 BoxConstraints get _additionalConstraints { 2035 return BoxConstraints.tightFor(width: width, height: height); 2036 } 2037 2038 @override 2039 void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) { 2040 renderObject.additionalConstraints = _additionalConstraints; 2041 } 2042 2043 @override 2044 String toStringShort() { 2045 String type; 2046 if (width == double.infinity && height == double.infinity) { 2047 type = '$runtimeType.expand'; 2048 } else if (width == 0.0 && height == 0.0) { 2049 type = '$runtimeType.shrink'; 2050 } else { 2051 type = '$runtimeType'; 2052 } 2053 return key == null ? '$type' : '$type-$key'; 2054 } 2055 2056 @override 2057 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2058 super.debugFillProperties(properties); 2059 DiagnosticLevel level; 2060 if ((width == double.infinity && height == double.infinity) || 2061 (width == 0.0 && height == 0.0)) { 2062 level = DiagnosticLevel.hidden; 2063 } else { 2064 level = DiagnosticLevel.info; 2065 } 2066 properties.add(DoubleProperty('width', width, defaultValue: null, level: level)); 2067 properties.add(DoubleProperty('height', height, defaultValue: null, level: level)); 2068 } 2069} 2070 2071/// A widget that imposes additional constraints on its child. 2072/// 2073/// For example, if you wanted [child] to have a minimum height of 50.0 logical 2074/// pixels, you could use `const BoxConstraints(minHeight: 50.0)` as the 2075/// [constraints]. 2076/// 2077/// {@tool sample} 2078/// 2079/// This snippet makes the child widget (a [Card] with some [Text]) fill the 2080/// parent, by applying [BoxConstraints.expand] constraints: 2081/// 2082/// ```dart 2083/// ConstrainedBox( 2084/// constraints: const BoxConstraints.expand(), 2085/// child: const Card(child: Text('Hello World!')), 2086/// ) 2087/// ``` 2088/// {@end-tool} 2089/// 2090/// The same behavior can be obtained using the [new SizedBox.expand] widget. 2091/// 2092/// See also: 2093/// 2094/// * [BoxConstraints], the class that describes constraints. 2095/// * [UnconstrainedBox], a container that tries to let its child draw without 2096/// constraints. 2097/// * [SizedBox], which lets you specify tight constraints by explicitly 2098/// specifying the height or width. 2099/// * [FractionallySizedBox], which sizes its child based on a fraction of its 2100/// own size and positions the child according to an [Alignment] value. 2101/// * [AspectRatio], a widget that attempts to fit within the parent's 2102/// constraints while also sizing its child to match a given aspect ratio. 2103/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2104class ConstrainedBox extends SingleChildRenderObjectWidget { 2105 /// Creates a widget that imposes additional constraints on its child. 2106 /// 2107 /// The [constraints] argument must not be null. 2108 ConstrainedBox({ 2109 Key key, 2110 @required this.constraints, 2111 Widget child, 2112 }) : assert(constraints != null), 2113 assert(constraints.debugAssertIsValid()), 2114 super(key: key, child: child); 2115 2116 /// The additional constraints to impose on the child. 2117 final BoxConstraints constraints; 2118 2119 @override 2120 RenderConstrainedBox createRenderObject(BuildContext context) { 2121 return RenderConstrainedBox(additionalConstraints: constraints); 2122 } 2123 2124 @override 2125 void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) { 2126 renderObject.additionalConstraints = constraints; 2127 } 2128 2129 @override 2130 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2131 super.debugFillProperties(properties); 2132 properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, showName: false)); 2133 } 2134} 2135 2136/// A widget that imposes no constraints on its child, allowing it to render 2137/// at its "natural" size. 2138/// 2139/// This allows a child to render at the size it would render if it were alone 2140/// on an infinite canvas with no constraints. This container will then attempt 2141/// to adopt the same size, within the limits of its own constraints. If it ends 2142/// up with a different size, it will align the child based on [alignment]. 2143/// If the box cannot expand enough to accommodate the entire child, the 2144/// child will be clipped. 2145/// 2146/// In debug mode, if the child overflows the container, a warning will be 2147/// printed on the console, and black and yellow striped areas will appear where 2148/// the overflow occurs. 2149/// 2150/// See also: 2151/// 2152/// * [ConstrainedBox], for a box which imposes constraints on its child. 2153/// * [Align], which loosens the constraints given to the child rather than 2154/// removing them entirely. 2155/// * [Container], a convenience widget that combines common painting, 2156/// positioning, and sizing widgets. 2157/// * [OverflowBox], a widget that imposes different constraints on its child 2158/// than it gets from its parent, possibly allowing the child to overflow 2159/// the parent. 2160class UnconstrainedBox extends SingleChildRenderObjectWidget { 2161 /// Creates a widget that imposes no constraints on its child, allowing it to 2162 /// render at its "natural" size. If the child overflows the parents 2163 /// constraints, a warning will be given in debug mode. 2164 const UnconstrainedBox({ 2165 Key key, 2166 Widget child, 2167 this.textDirection, 2168 this.alignment = Alignment.center, 2169 this.constrainedAxis, 2170 }) : assert(alignment != null), 2171 super(key: key, child: child); 2172 2173 /// The text direction to use when interpreting the [alignment] if it is an 2174 /// [AlignmentDirectional]. 2175 final TextDirection textDirection; 2176 2177 /// The alignment to use when laying out the child. 2178 /// 2179 /// If this is an [AlignmentDirectional], then [textDirection] must not be 2180 /// null. 2181 /// 2182 /// See also: 2183 /// 2184 /// * [Alignment] for non-[Directionality]-aware alignments. 2185 /// * [AlignmentDirectional] for [Directionality]-aware alignments. 2186 final AlignmentGeometry alignment; 2187 2188 /// The axis to retain constraints on, if any. 2189 /// 2190 /// If not set, or set to null (the default), neither axis will retain its 2191 /// constraints. If set to [Axis.vertical], then vertical constraints will 2192 /// be retained, and if set to [Axis.horizontal], then horizontal constraints 2193 /// will be retained. 2194 final Axis constrainedAxis; 2195 2196 @override 2197 void updateRenderObject(BuildContext context, covariant RenderUnconstrainedBox renderObject) { 2198 renderObject 2199 ..textDirection = textDirection ?? Directionality.of(context) 2200 ..alignment = alignment 2201 ..constrainedAxis = constrainedAxis; 2202 } 2203 2204 @override 2205 RenderUnconstrainedBox createRenderObject(BuildContext context) => RenderUnconstrainedBox( 2206 textDirection: textDirection ?? Directionality.of(context), 2207 alignment: alignment, 2208 constrainedAxis: constrainedAxis, 2209 ); 2210 2211 @override 2212 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2213 super.debugFillProperties(properties); 2214 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 2215 properties.add(EnumProperty<Axis>('constrainedAxis', constrainedAxis, defaultValue: null)); 2216 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); 2217 } 2218} 2219 2220/// A widget that sizes its child to a fraction of the total available space. 2221/// For more details about the layout algorithm, see 2222/// [RenderFractionallySizedOverflowBox]. 2223/// 2224/// See also: 2225/// 2226/// * [Align], which sizes itself based on its child's size and positions 2227/// the child according to an [Alignment] value. 2228/// * [OverflowBox], a widget that imposes different constraints on its child 2229/// than it gets from its parent, possibly allowing the child to overflow the 2230/// parent. 2231/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2232class FractionallySizedBox extends SingleChildRenderObjectWidget { 2233 /// Creates a widget that sizes its child to a fraction of the total available space. 2234 /// 2235 /// If non-null, the [widthFactor] and [heightFactor] arguments must be 2236 /// non-negative. 2237 const FractionallySizedBox({ 2238 Key key, 2239 this.alignment = Alignment.center, 2240 this.widthFactor, 2241 this.heightFactor, 2242 Widget child, 2243 }) : assert(alignment != null), 2244 assert(widthFactor == null || widthFactor >= 0.0), 2245 assert(heightFactor == null || heightFactor >= 0.0), 2246 super(key: key, child: child); 2247 2248 /// If non-null, the fraction of the incoming width given to the child. 2249 /// 2250 /// If non-null, the child is given a tight width constraint that is the max 2251 /// incoming width constraint multiplied by this factor. 2252 /// 2253 /// If null, the incoming width constraints are passed to the child 2254 /// unmodified. 2255 final double widthFactor; 2256 2257 /// If non-null, the fraction of the incoming height given to the child. 2258 /// 2259 /// If non-null, the child is given a tight height constraint that is the max 2260 /// incoming height constraint multiplied by this factor. 2261 /// 2262 /// If null, the incoming height constraints are passed to the child 2263 /// unmodified. 2264 final double heightFactor; 2265 2266 /// How to align the child. 2267 /// 2268 /// The x and y values of the alignment control the horizontal and vertical 2269 /// alignment, respectively. An x value of -1.0 means that the left edge of 2270 /// the child is aligned with the left edge of the parent whereas an x value 2271 /// of 1.0 means that the right edge of the child is aligned with the right 2272 /// edge of the parent. Other values interpolate (and extrapolate) linearly. 2273 /// For example, a value of 0.0 means that the center of the child is aligned 2274 /// with the center of the parent. 2275 /// 2276 /// Defaults to [Alignment.center]. 2277 /// 2278 /// See also: 2279 /// 2280 /// * [Alignment], a class with convenient constants typically used to 2281 /// specify an [AlignmentGeometry]. 2282 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 2283 /// relative to text direction. 2284 final AlignmentGeometry alignment; 2285 2286 @override 2287 RenderFractionallySizedOverflowBox createRenderObject(BuildContext context) { 2288 return RenderFractionallySizedOverflowBox( 2289 alignment: alignment, 2290 widthFactor: widthFactor, 2291 heightFactor: heightFactor, 2292 textDirection: Directionality.of(context), 2293 ); 2294 } 2295 2296 @override 2297 void updateRenderObject(BuildContext context, RenderFractionallySizedOverflowBox renderObject) { 2298 renderObject 2299 ..alignment = alignment 2300 ..widthFactor = widthFactor 2301 ..heightFactor = heightFactor 2302 ..textDirection = Directionality.of(context); 2303 } 2304 2305 @override 2306 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2307 super.debugFillProperties(properties); 2308 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 2309 properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null)); 2310 properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null)); 2311 } 2312} 2313 2314/// A box that limits its size only when it's unconstrained. 2315/// 2316/// If this widget's maximum width is unconstrained then its child's width is 2317/// limited to [maxWidth]. Similarly, if this widget's maximum height is 2318/// unconstrained then its child's height is limited to [maxHeight]. 2319/// 2320/// This has the effect of giving the child a natural dimension in unbounded 2321/// environments. For example, by providing a [maxHeight] to a widget that 2322/// normally tries to be as big as possible, the widget will normally size 2323/// itself to fit its parent, but when placed in a vertical list, it will take 2324/// on the given height. 2325/// 2326/// This is useful when composing widgets that normally try to match their 2327/// parents' size, so that they behave reasonably in lists (which are 2328/// unbounded). 2329/// 2330/// See also: 2331/// 2332/// * [ConstrainedBox], which applies its constraints in all cases, not just 2333/// when the incoming constraints are unbounded. 2334/// * [SizedBox], which lets you specify tight constraints by explicitly 2335/// specifying the height or width. 2336/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2337class LimitedBox extends SingleChildRenderObjectWidget { 2338 /// Creates a box that limits its size only when it's unconstrained. 2339 /// 2340 /// The [maxWidth] and [maxHeight] arguments must not be null and must not be 2341 /// negative. 2342 const LimitedBox({ 2343 Key key, 2344 this.maxWidth = double.infinity, 2345 this.maxHeight = double.infinity, 2346 Widget child, 2347 }) : assert(maxWidth != null && maxWidth >= 0.0), 2348 assert(maxHeight != null && maxHeight >= 0.0), 2349 super(key: key, child: child); 2350 2351 /// The maximum width limit to apply in the absence of a 2352 /// [BoxConstraints.maxWidth] constraint. 2353 final double maxWidth; 2354 2355 /// The maximum height limit to apply in the absence of a 2356 /// [BoxConstraints.maxHeight] constraint. 2357 final double maxHeight; 2358 2359 @override 2360 RenderLimitedBox createRenderObject(BuildContext context) { 2361 return RenderLimitedBox( 2362 maxWidth: maxWidth, 2363 maxHeight: maxHeight, 2364 ); 2365 } 2366 2367 @override 2368 void updateRenderObject(BuildContext context, RenderLimitedBox renderObject) { 2369 renderObject 2370 ..maxWidth = maxWidth 2371 ..maxHeight = maxHeight; 2372 } 2373 2374 @override 2375 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2376 super.debugFillProperties(properties); 2377 properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: double.infinity)); 2378 properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: double.infinity)); 2379 } 2380} 2381 2382/// A widget that imposes different constraints on its child than it gets 2383/// from its parent, possibly allowing the child to overflow the parent. 2384/// 2385/// See also: 2386/// 2387/// * [RenderConstrainedOverflowBox] for details about how [OverflowBox] is 2388/// rendered. 2389/// * [SizedOverflowBox], a widget that is a specific size but passes its 2390/// original constraints through to its child, which may then overflow. 2391/// * [ConstrainedBox], a widget that imposes additional constraints on its 2392/// child. 2393/// * [UnconstrainedBox], a container that tries to let its child draw without 2394/// constraints. 2395/// * [SizedBox], a box with a specified size. 2396/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2397class OverflowBox extends SingleChildRenderObjectWidget { 2398 /// Creates a widget that lets its child overflow itself. 2399 const OverflowBox({ 2400 Key key, 2401 this.alignment = Alignment.center, 2402 this.minWidth, 2403 this.maxWidth, 2404 this.minHeight, 2405 this.maxHeight, 2406 Widget child, 2407 }) : super(key: key, child: child); 2408 2409 /// How to align the child. 2410 /// 2411 /// The x and y values of the alignment control the horizontal and vertical 2412 /// alignment, respectively. An x value of -1.0 means that the left edge of 2413 /// the child is aligned with the left edge of the parent whereas an x value 2414 /// of 1.0 means that the right edge of the child is aligned with the right 2415 /// edge of the parent. Other values interpolate (and extrapolate) linearly. 2416 /// For example, a value of 0.0 means that the center of the child is aligned 2417 /// with the center of the parent. 2418 /// 2419 /// Defaults to [Alignment.center]. 2420 /// 2421 /// See also: 2422 /// 2423 /// * [Alignment], a class with convenient constants typically used to 2424 /// specify an [AlignmentGeometry]. 2425 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 2426 /// relative to text direction. 2427 final AlignmentGeometry alignment; 2428 2429 /// The minimum width constraint to give the child. Set this to null (the 2430 /// default) to use the constraint from the parent instead. 2431 final double minWidth; 2432 2433 /// The maximum width constraint to give the child. Set this to null (the 2434 /// default) to use the constraint from the parent instead. 2435 final double maxWidth; 2436 2437 /// The minimum height constraint to give the child. Set this to null (the 2438 /// default) to use the constraint from the parent instead. 2439 final double minHeight; 2440 2441 /// The maximum height constraint to give the child. Set this to null (the 2442 /// default) to use the constraint from the parent instead. 2443 final double maxHeight; 2444 2445 @override 2446 RenderConstrainedOverflowBox createRenderObject(BuildContext context) { 2447 return RenderConstrainedOverflowBox( 2448 alignment: alignment, 2449 minWidth: minWidth, 2450 maxWidth: maxWidth, 2451 minHeight: minHeight, 2452 maxHeight: maxHeight, 2453 textDirection: Directionality.of(context), 2454 ); 2455 } 2456 2457 @override 2458 void updateRenderObject(BuildContext context, RenderConstrainedOverflowBox renderObject) { 2459 renderObject 2460 ..alignment = alignment 2461 ..minWidth = minWidth 2462 ..maxWidth = maxWidth 2463 ..minHeight = minHeight 2464 ..maxHeight = maxHeight 2465 ..textDirection = Directionality.of(context); 2466 } 2467 2468 @override 2469 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2470 super.debugFillProperties(properties); 2471 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 2472 properties.add(DoubleProperty('minWidth', minWidth, defaultValue: null)); 2473 properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: null)); 2474 properties.add(DoubleProperty('minHeight', minHeight, defaultValue: null)); 2475 properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: null)); 2476 } 2477} 2478 2479/// A widget that is a specific size but passes its original constraints 2480/// through to its child, which may then overflow. 2481/// 2482/// See also: 2483/// 2484/// * [OverflowBox], A widget that imposes different constraints on its child 2485/// than it gets from its parent, possibly allowing the child to overflow the 2486/// parent. 2487/// * [ConstrainedBox], a widget that imposes additional constraints on its 2488/// child. 2489/// * [UnconstrainedBox], a container that tries to let its child draw without 2490/// constraints. 2491/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2492class SizedOverflowBox extends SingleChildRenderObjectWidget { 2493 /// Creates a widget of a given size that lets its child overflow. 2494 /// 2495 /// The [size] argument must not be null. 2496 const SizedOverflowBox({ 2497 Key key, 2498 @required this.size, 2499 this.alignment = Alignment.center, 2500 Widget child, 2501 }) : assert(size != null), 2502 assert(alignment != null), 2503 super(key: key, child: child); 2504 2505 /// How to align the child. 2506 /// 2507 /// The x and y values of the alignment control the horizontal and vertical 2508 /// alignment, respectively. An x value of -1.0 means that the left edge of 2509 /// the child is aligned with the left edge of the parent whereas an x value 2510 /// of 1.0 means that the right edge of the child is aligned with the right 2511 /// edge of the parent. Other values interpolate (and extrapolate) linearly. 2512 /// For example, a value of 0.0 means that the center of the child is aligned 2513 /// with the center of the parent. 2514 /// 2515 /// Defaults to [Alignment.center]. 2516 /// 2517 /// See also: 2518 /// 2519 /// * [Alignment], a class with convenient constants typically used to 2520 /// specify an [AlignmentGeometry]. 2521 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 2522 /// relative to text direction. 2523 final AlignmentGeometry alignment; 2524 2525 /// The size this widget should attempt to be. 2526 final Size size; 2527 2528 @override 2529 RenderSizedOverflowBox createRenderObject(BuildContext context) { 2530 return RenderSizedOverflowBox( 2531 alignment: alignment, 2532 requestedSize: size, 2533 textDirection: Directionality.of(context), 2534 ); 2535 } 2536 2537 @override 2538 void updateRenderObject(BuildContext context, RenderSizedOverflowBox renderObject) { 2539 renderObject 2540 ..alignment = alignment 2541 ..requestedSize = size 2542 ..textDirection = Directionality.of(context); 2543 } 2544 2545 @override 2546 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2547 super.debugFillProperties(properties); 2548 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 2549 properties.add(DiagnosticsProperty<Size>('size', size, defaultValue: null)); 2550 } 2551} 2552 2553/// A widget that lays the child out as if it was in the tree, but without 2554/// painting anything, without making the child available for hit testing, and 2555/// without taking any room in the parent. 2556/// 2557/// Animations continue to run in offstage children, and therefore use battery 2558/// and CPU time, regardless of whether the animations end up being visible. 2559/// 2560/// [Offstage] can be used to measure the dimensions of a widget without 2561/// bringing it on screen (yet). To hide a widget from view while it is not 2562/// needed, prefer removing the widget from the tree entirely rather than 2563/// keeping it alive in an [Offstage] subtree. 2564/// 2565/// See also: 2566/// 2567/// * [Visibility], which can hide a child more efficiently (albeit less 2568/// subtly). 2569/// * [TickerMode], which can be used to disable animations in a subtree. 2570/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2571class Offstage extends SingleChildRenderObjectWidget { 2572 /// Creates a widget that visually hides its child. 2573 const Offstage({ Key key, this.offstage = true, Widget child }) 2574 : assert(offstage != null), 2575 super(key: key, child: child); 2576 2577 /// Whether the child is hidden from the rest of the tree. 2578 /// 2579 /// If true, the child is laid out as if it was in the tree, but without 2580 /// painting anything, without making the child available for hit testing, and 2581 /// without taking any room in the parent. 2582 /// 2583 /// If false, the child is included in the tree as normal. 2584 final bool offstage; 2585 2586 @override 2587 RenderOffstage createRenderObject(BuildContext context) => RenderOffstage(offstage: offstage); 2588 2589 @override 2590 void updateRenderObject(BuildContext context, RenderOffstage renderObject) { 2591 renderObject.offstage = offstage; 2592 } 2593 2594 @override 2595 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2596 super.debugFillProperties(properties); 2597 properties.add(DiagnosticsProperty<bool>('offstage', offstage)); 2598 } 2599 2600 @override 2601 _OffstageElement createElement() => _OffstageElement(this); 2602} 2603 2604class _OffstageElement extends SingleChildRenderObjectElement { 2605 _OffstageElement(Offstage widget) : super(widget); 2606 2607 @override 2608 Offstage get widget => super.widget; 2609 2610 @override 2611 void debugVisitOnstageChildren(ElementVisitor visitor) { 2612 if (!widget.offstage) 2613 super.debugVisitOnstageChildren(visitor); 2614 } 2615} 2616 2617/// A widget that attempts to size the child to a specific aspect ratio. 2618/// 2619/// The widget first tries the largest width permitted by the layout 2620/// constraints. The height of the widget is determined by applying the 2621/// given aspect ratio to the width, expressed as a ratio of width to height. 2622/// 2623/// {@youtube 560 315 https://www.youtube.com/watch?v=XcnP3_mO_Ms} 2624/// 2625/// For example, a 16:9 width:height aspect ratio would have a value of 2626/// 16.0/9.0. If the maximum width is infinite, the initial width is determined 2627/// by applying the aspect ratio to the maximum height. 2628/// 2629/// Now consider a second example, this time with an aspect ratio of 2.0 and 2630/// layout constraints that require the width to be between 0.0 and 100.0 and 2631/// the height to be between 0.0 and 100.0. We'll select a width of 100.0 (the 2632/// biggest allowed) and a height of 50.0 (to match the aspect ratio). 2633/// 2634/// In that same situation, if the aspect ratio is 0.5, we'll also select a 2635/// width of 100.0 (still the biggest allowed) and we'll attempt to use a height 2636/// of 200.0. Unfortunately, that violates the constraints because the child can 2637/// be at most 100.0 pixels tall. The widget will then take that value 2638/// and apply the aspect ratio again to obtain a width of 50.0. That width is 2639/// permitted by the constraints and the child receives a width of 50.0 and a 2640/// height of 100.0. If the width were not permitted, the widget would 2641/// continue iterating through the constraints. If the widget does not 2642/// find a feasible size after consulting each constraint, the widget 2643/// will eventually select a size for the child that meets the layout 2644/// constraints but fails to meet the aspect ratio constraints. 2645/// 2646/// See also: 2647/// 2648/// * [Align], a widget that aligns its child within itself and optionally 2649/// sizes itself based on the child's size. 2650/// * [ConstrainedBox], a widget that imposes additional constraints on its 2651/// child. 2652/// * [UnconstrainedBox], a container that tries to let its child draw without 2653/// constraints. 2654/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2655class AspectRatio extends SingleChildRenderObjectWidget { 2656 /// Creates a widget with a specific aspect ratio. 2657 /// 2658 /// The [aspectRatio] argument must not be null. 2659 const AspectRatio({ 2660 Key key, 2661 @required this.aspectRatio, 2662 Widget child, 2663 }) : assert(aspectRatio != null), 2664 super(key: key, child: child); 2665 2666 /// The aspect ratio to attempt to use. 2667 /// 2668 /// The aspect ratio is expressed as a ratio of width to height. For example, 2669 /// a 16:9 width:height aspect ratio would have a value of 16.0/9.0. 2670 final double aspectRatio; 2671 2672 @override 2673 RenderAspectRatio createRenderObject(BuildContext context) => RenderAspectRatio(aspectRatio: aspectRatio); 2674 2675 @override 2676 void updateRenderObject(BuildContext context, RenderAspectRatio renderObject) { 2677 renderObject.aspectRatio = aspectRatio; 2678 } 2679 2680 @override 2681 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2682 super.debugFillProperties(properties); 2683 properties.add(DoubleProperty('aspectRatio', aspectRatio)); 2684 } 2685} 2686 2687/// A widget that sizes its child to the child's intrinsic width. 2688/// 2689/// Sizes its child's width to the child's maximum intrinsic width. If 2690/// [stepWidth] is non-null, the child's width will be snapped to a multiple of 2691/// the [stepWidth]. Similarly, if [stepHeight] is non-null, the child's height 2692/// will be snapped to a multiple of the [stepHeight]. 2693/// 2694/// This class is useful, for example, when unlimited width is available and 2695/// you would like a child that would otherwise attempt to expand infinitely to 2696/// instead size itself to a more reasonable width. 2697/// 2698/// This class is relatively expensive, because it adds a speculative layout 2699/// pass before the final layout phase. Avoid using it where possible. In the 2700/// worst case, this widget can result in a layout that is O(N²) in the depth of 2701/// the tree. 2702/// 2703/// See also: 2704/// 2705/// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/). 2706class IntrinsicWidth extends SingleChildRenderObjectWidget { 2707 /// Creates a widget that sizes its child to the child's intrinsic width. 2708 /// 2709 /// This class is relatively expensive. Avoid using it where possible. 2710 const IntrinsicWidth({ Key key, this.stepWidth, this.stepHeight, Widget child }) 2711 : assert(stepWidth == null || stepWidth >= 0.0), 2712 assert(stepHeight == null || stepHeight >= 0.0), 2713 super(key: key, child: child); 2714 2715 /// If non-null, force the child's width to be a multiple of this value. 2716 /// 2717 /// If null or 0.0 the child's width will be the same as its maximum 2718 /// intrinsic width. 2719 /// 2720 /// This value must not be negative. 2721 /// 2722 /// See also: 2723 /// 2724 /// * [RenderBox.getMaxIntrinsicWidth], which defines a widget's max 2725 /// intrinsic width in general. 2726 final double stepWidth; 2727 2728 /// If non-null, force the child's height to be a multiple of this value. 2729 /// 2730 /// If null or 0.0 the child's height will not be constrained. 2731 /// 2732 /// This value must not be negative. 2733 final double stepHeight; 2734 2735 double get _stepWidth => stepWidth == 0.0 ? null : stepWidth; 2736 double get _stepHeight => stepHeight == 0.0 ? null : stepHeight; 2737 2738 @override 2739 RenderIntrinsicWidth createRenderObject(BuildContext context) { 2740 return RenderIntrinsicWidth(stepWidth: _stepWidth, stepHeight: _stepHeight); 2741 } 2742 2743 @override 2744 void updateRenderObject(BuildContext context, RenderIntrinsicWidth renderObject) { 2745 renderObject 2746 ..stepWidth = _stepWidth 2747 ..stepHeight = _stepHeight; 2748 } 2749} 2750 2751/// A widget that sizes its child to the child's intrinsic height. 2752/// 2753/// This class is useful, for example, when unlimited height is available and 2754/// you would like a child that would otherwise attempt to expand infinitely to 2755/// instead size itself to a more reasonable height. 2756/// 2757/// This class is relatively expensive, because it adds a speculative layout 2758/// pass before the final layout phase. Avoid using it where possible. In the 2759/// worst case, this widget can result in a layout that is O(N²) in the depth of 2760/// the tree. 2761/// 2762/// See also: 2763/// 2764/// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/). 2765class IntrinsicHeight extends SingleChildRenderObjectWidget { 2766 /// Creates a widget that sizes its child to the child's intrinsic height. 2767 /// 2768 /// This class is relatively expensive. Avoid using it where possible. 2769 const IntrinsicHeight({ Key key, Widget child }) : super(key: key, child: child); 2770 2771 @override 2772 RenderIntrinsicHeight createRenderObject(BuildContext context) => RenderIntrinsicHeight(); 2773} 2774 2775/// A widget that positions its child according to the child's baseline. 2776/// 2777/// This widget shifts the child down such that the child's baseline (or the 2778/// bottom of the child, if the child has no baseline) is [baseline] 2779/// logical pixels below the top of this box, then sizes this box to 2780/// contain the child. If [baseline] is less than the distance from 2781/// the top of the child to the baseline of the child, then the child 2782/// is top-aligned instead. 2783/// 2784/// See also: 2785/// 2786/// * [Align], a widget that aligns its child within itself and optionally 2787/// sizes itself based on the child's size. 2788/// * [Center], a widget that centers its child within itself. 2789/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 2790class Baseline extends SingleChildRenderObjectWidget { 2791 /// Creates a widget that positions its child according to the child's baseline. 2792 /// 2793 /// The [baseline] and [baselineType] arguments must not be null. 2794 const Baseline({ 2795 Key key, 2796 @required this.baseline, 2797 @required this.baselineType, 2798 Widget child, 2799 }) : assert(baseline != null), 2800 assert(baselineType != null), 2801 super(key: key, child: child); 2802 2803 /// The number of logical pixels from the top of this box at which to position 2804 /// the child's baseline. 2805 final double baseline; 2806 2807 /// The type of baseline to use for positioning the child. 2808 final TextBaseline baselineType; 2809 2810 @override 2811 RenderBaseline createRenderObject(BuildContext context) { 2812 return RenderBaseline(baseline: baseline, baselineType: baselineType); 2813 } 2814 2815 @override 2816 void updateRenderObject(BuildContext context, RenderBaseline renderObject) { 2817 renderObject 2818 ..baseline = baseline 2819 ..baselineType = baselineType; 2820 } 2821} 2822 2823 2824// SLIVERS 2825 2826/// A sliver that contains a single box widget. 2827/// 2828/// Slivers are special-purpose widgets that can be combined using a 2829/// [CustomScrollView] to create custom scroll effects. A [SliverToBoxAdapter] 2830/// is a basic sliver that creates a bridge back to one of the usual box-based 2831/// widgets. 2832/// 2833/// Rather than using multiple [SliverToBoxAdapter] widgets to display multiple 2834/// box widgets in a [CustomScrollView], consider using [SliverList], 2835/// [SliverFixedExtentList], [SliverPrototypeExtentList], or [SliverGrid], 2836/// which are more efficient because they instantiate only those children that 2837/// are actually visible through the scroll view's viewport. 2838/// 2839/// See also: 2840/// 2841/// * [CustomScrollView], which displays a scrollable list of slivers. 2842/// * [SliverList], which displays multiple box widgets in a linear array. 2843/// * [SliverFixedExtentList], which displays multiple box widgets with the 2844/// same main-axis extent in a linear array. 2845/// * [SliverPrototypeExtentList], which displays multiple box widgets with the 2846/// same main-axis extent as a prototype item, in a linear array. 2847/// * [SliverGrid], which displays multiple box widgets in arbitrary positions. 2848class SliverToBoxAdapter extends SingleChildRenderObjectWidget { 2849 /// Creates a sliver that contains a single box widget. 2850 const SliverToBoxAdapter({ 2851 Key key, 2852 Widget child, 2853 }) : super(key: key, child: child); 2854 2855 @override 2856 RenderSliverToBoxAdapter createRenderObject(BuildContext context) => RenderSliverToBoxAdapter(); 2857} 2858 2859/// A sliver that applies padding on each side of another sliver. 2860/// 2861/// Slivers are special-purpose widgets that can be combined using a 2862/// [CustomScrollView] to create custom scroll effects. A [SliverPadding] 2863/// is a basic sliver that insets another sliver by applying padding on each 2864/// side. 2865/// 2866/// Applying padding to anything but the most mundane sliver is likely to have 2867/// undesired effects. For example, wrapping a [SliverPersistentHeader] with 2868/// `pinned:true` will cause the app bar to overlap earlier slivers (contrary to 2869/// the normal behavior of pinned app bars), and while the app bar is pinned, 2870/// the padding will scroll away. 2871/// 2872/// See also: 2873/// 2874/// * [CustomScrollView], which displays a scrollable list of slivers. 2875class SliverPadding extends SingleChildRenderObjectWidget { 2876 /// Creates a sliver that applies padding on each side of another sliver. 2877 /// 2878 /// The [padding] argument must not be null. 2879 const SliverPadding({ 2880 Key key, 2881 @required this.padding, 2882 Widget sliver, 2883 }) : assert(padding != null), 2884 super(key: key, child: sliver); 2885 2886 /// The amount of space by which to inset the child sliver. 2887 final EdgeInsetsGeometry padding; 2888 2889 @override 2890 RenderSliverPadding createRenderObject(BuildContext context) { 2891 return RenderSliverPadding( 2892 padding: padding, 2893 textDirection: Directionality.of(context), 2894 ); 2895 } 2896 2897 @override 2898 void updateRenderObject(BuildContext context, RenderSliverPadding renderObject) { 2899 renderObject 2900 ..padding = padding 2901 ..textDirection = Directionality.of(context); 2902 } 2903 2904 @override 2905 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2906 super.debugFillProperties(properties); 2907 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding)); 2908 } 2909} 2910 2911 2912// LAYOUT NODES 2913 2914/// Returns the [AxisDirection] in the given [Axis] in the current 2915/// [Directionality] (or the reverse if `reverse` is true). 2916/// 2917/// If `axis` is [Axis.vertical], this function returns [AxisDirection.down] 2918/// unless `reverse` is true, in which case this function returns 2919/// [AxisDirection.up]. 2920/// 2921/// If `axis` is [Axis.horizontal], this function checks the current 2922/// [Directionality]. If the current [Directionality] is right-to-left, then 2923/// this function returns [AxisDirection.left] (unless `reverse` is true, in 2924/// which case it returns [AxisDirection.right]). Similarly, if the current 2925/// [Directionality] is left-to-right, then this function returns 2926/// [AxisDirection.right] (unless `reverse` is true, in which case it returns 2927/// [AxisDirection.left]). 2928/// 2929/// This function is used by a number of scrolling widgets (e.g., [ListView], 2930/// [GridView], [PageView], and [SingleChildScrollView]) as well as [ListBody] 2931/// to translate their [Axis] and `reverse` properties into a concrete 2932/// [AxisDirection]. 2933AxisDirection getAxisDirectionFromAxisReverseAndDirectionality( 2934 BuildContext context, 2935 Axis axis, 2936 bool reverse, 2937) { 2938 switch (axis) { 2939 case Axis.horizontal: 2940 assert(debugCheckHasDirectionality(context)); 2941 final TextDirection textDirection = Directionality.of(context); 2942 final AxisDirection axisDirection = textDirectionToAxisDirection(textDirection); 2943 return reverse ? flipAxisDirection(axisDirection) : axisDirection; 2944 case Axis.vertical: 2945 return reverse ? AxisDirection.up : AxisDirection.down; 2946 } 2947 return null; 2948} 2949 2950/// A widget that arranges its children sequentially along a given axis, forcing 2951/// them to the dimension of the parent in the other axis. 2952/// 2953/// This widget is rarely used directly. Instead, consider using [ListView], 2954/// which combines a similar layout algorithm with scrolling behavior, or 2955/// [Column], which gives you more flexible control over the layout of a 2956/// vertical set of boxes. 2957/// 2958/// See also: 2959/// 2960/// * [RenderListBody], which implements this layout algorithm and the 2961/// documentation for which describes some of its subtleties. 2962/// * [SingleChildScrollView], which is sometimes used with [ListBody] to 2963/// make the contents scrollable. 2964/// * [Column] and [Row], which implement a more elaborate version of 2965/// this layout algorithm (at the cost of being slightly less efficient). 2966/// * [ListView], which implements an efficient scrolling version of this 2967/// layout algorithm. 2968class ListBody extends MultiChildRenderObjectWidget { 2969 /// Creates a layout widget that arranges its children sequentially along a 2970 /// given axis. 2971 /// 2972 /// By default, the [mainAxis] is [Axis.vertical]. 2973 ListBody({ 2974 Key key, 2975 this.mainAxis = Axis.vertical, 2976 this.reverse = false, 2977 List<Widget> children = const <Widget>[], 2978 }) : assert(mainAxis != null), 2979 super(key: key, children: children); 2980 2981 /// The direction to use as the main axis. 2982 final Axis mainAxis; 2983 2984 /// Whether the list body positions children in the reading direction. 2985 /// 2986 /// For example, if the reading direction is left-to-right and 2987 /// [mainAxis] is [Axis.horizontal], then the list body positions children 2988 /// from left to right when [reverse] is false and from right to left when 2989 /// [reverse] is true. 2990 /// 2991 /// Similarly, if [mainAxis] is [Axis.vertical], then the list body positions 2992 /// from top to bottom when [reverse] is false and from bottom to top when 2993 /// [reverse] is true. 2994 /// 2995 /// Defaults to false. 2996 final bool reverse; 2997 2998 AxisDirection _getDirection(BuildContext context) { 2999 return getAxisDirectionFromAxisReverseAndDirectionality(context, mainAxis, reverse); 3000 } 3001 3002 @override 3003 RenderListBody createRenderObject(BuildContext context) { 3004 return RenderListBody(axisDirection: _getDirection(context)); 3005 } 3006 3007 @override 3008 void updateRenderObject(BuildContext context, RenderListBody renderObject) { 3009 renderObject.axisDirection = _getDirection(context); 3010 } 3011} 3012 3013/// A widget that positions its children relative to the edges of its box. 3014/// 3015/// This class is useful if you want to overlap several children in a simple 3016/// way, for example having some text and an image, overlaid with a gradient and 3017/// a button attached to the bottom. 3018/// 3019/// Each child of a [Stack] widget is either _positioned_ or _non-positioned_. 3020/// Positioned children are those wrapped in a [Positioned] widget that has at 3021/// least one non-null property. The stack sizes itself to contain all the 3022/// non-positioned children, which are positioned according to [alignment] 3023/// (which defaults to the top-left corner in left-to-right environments and the 3024/// top-right corner in right-to-left environments). The positioned children are 3025/// then placed relative to the stack according to their top, right, bottom, and 3026/// left properties. 3027/// 3028/// The stack paints its children in order with the first child being at the 3029/// bottom. If you want to change the order in which the children paint, you 3030/// can rebuild the stack with the children in the new order. If you reorder 3031/// the children in this way, consider giving the children non-null keys. 3032/// These keys will cause the framework to move the underlying objects for 3033/// the children to their new locations rather than recreate them at their 3034/// new location. 3035/// 3036/// For more details about the stack layout algorithm, see [RenderStack]. 3037/// 3038/// If you want to lay a number of children out in a particular pattern, or if 3039/// you want to make a custom layout manager, you probably want to use 3040/// [CustomMultiChildLayout] instead. In particular, when using a [Stack] you 3041/// can't position children relative to their size or the stack's own size. 3042/// 3043/// {@tool sample} 3044/// 3045/// Using a [Stack] you can position widgets over one another. 3046/// 3047///  3048/// 3049/// ```dart 3050/// Stack( 3051/// children: <Widget>[ 3052/// Container( 3053/// width: 100, 3054/// height: 100, 3055/// color: Colors.red, 3056/// ), 3057/// Container( 3058/// width: 90, 3059/// height: 90, 3060/// color: Colors.green, 3061/// ), 3062/// Container( 3063/// width: 80, 3064/// height: 80, 3065/// color: Colors.blue, 3066/// ), 3067/// ], 3068/// ) 3069/// ``` 3070/// {@end-tool} 3071/// 3072/// {@tool sample} 3073/// 3074/// This example shows how [Stack] can be used to enhance text visibility 3075/// by adding gradient backdrops. 3076/// 3077///  3078/// 3079/// ```dart 3080/// SizedBox( 3081/// width: 250, 3082/// height: 250, 3083/// child: Stack( 3084/// children: <Widget>[ 3085/// Container( 3086/// width: 250, 3087/// height: 250, 3088/// color: Colors.white, 3089/// ), 3090/// Container( 3091/// padding: EdgeInsets.all(5.0), 3092/// alignment: Alignment.bottomCenter, 3093/// decoration: BoxDecoration( 3094/// gradient: LinearGradient( 3095/// begin: Alignment.topCenter, 3096/// end: Alignment.bottomCenter, 3097/// colors: <Color>[ 3098/// Colors.black.withAlpha(0), 3099/// Colors.black12, 3100/// Colors.black45 3101/// ], 3102/// ), 3103/// ), 3104/// child: Text( 3105/// "Foreground Text", 3106/// style: TextStyle(color: Colors.white, fontSize: 20.0), 3107/// ), 3108/// ), 3109/// ], 3110/// ), 3111/// ) 3112/// ``` 3113/// {@end-tool} 3114/// 3115/// See also: 3116/// 3117/// * [Align], which sizes itself based on its child's size and positions 3118/// the child according to an [Alignment] value. 3119/// * [CustomSingleChildLayout], which uses a delegate to control the layout of 3120/// a single child. 3121/// * [CustomMultiChildLayout], which uses a delegate to position multiple 3122/// children. 3123/// * [Flow], which provides paint-time control of its children using transform 3124/// matrices. 3125/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 3126class Stack extends MultiChildRenderObjectWidget { 3127 /// Creates a stack layout widget. 3128 /// 3129 /// By default, the non-positioned children of the stack are aligned by their 3130 /// top left corners. 3131 Stack({ 3132 Key key, 3133 this.alignment = AlignmentDirectional.topStart, 3134 this.textDirection, 3135 this.fit = StackFit.loose, 3136 this.overflow = Overflow.clip, 3137 List<Widget> children = const <Widget>[], 3138 }) : super(key: key, children: children); 3139 3140 /// How to align the non-positioned and partially-positioned children in the 3141 /// stack. 3142 /// 3143 /// The non-positioned children are placed relative to each other such that 3144 /// the points determined by [alignment] are co-located. For example, if the 3145 /// [alignment] is [Alignment.topLeft], then the top left corner of 3146 /// each non-positioned child will be located at the same global coordinate. 3147 /// 3148 /// Partially-positioned children, those that do not specify an alignment in a 3149 /// particular axis (e.g. that have neither `top` nor `bottom` set), use the 3150 /// alignment to determine how they should be positioned in that 3151 /// under-specified axis. 3152 /// 3153 /// Defaults to [AlignmentDirectional.topStart]. 3154 /// 3155 /// See also: 3156 /// 3157 /// * [Alignment], a class with convenient constants typically used to 3158 /// specify an [AlignmentGeometry]. 3159 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 3160 /// relative to text direction. 3161 final AlignmentGeometry alignment; 3162 3163 /// The text direction with which to resolve [alignment]. 3164 /// 3165 /// Defaults to the ambient [Directionality]. 3166 final TextDirection textDirection; 3167 3168 /// How to size the non-positioned children in the stack. 3169 /// 3170 /// The constraints passed into the [Stack] from its parent are either 3171 /// loosened ([StackFit.loose]) or tightened to their biggest size 3172 /// ([StackFit.expand]). 3173 final StackFit fit; 3174 3175 /// Whether overflowing children should be clipped. See [Overflow]. 3176 /// 3177 /// Some children in a stack might overflow its box. When this flag is set to 3178 /// [Overflow.clip], children cannot paint outside of the stack's box. 3179 final Overflow overflow; 3180 3181 @override 3182 RenderStack createRenderObject(BuildContext context) { 3183 return RenderStack( 3184 alignment: alignment, 3185 textDirection: textDirection ?? Directionality.of(context), 3186 fit: fit, 3187 overflow: overflow, 3188 ); 3189 } 3190 3191 @override 3192 void updateRenderObject(BuildContext context, RenderStack renderObject) { 3193 renderObject 3194 ..alignment = alignment 3195 ..textDirection = textDirection ?? Directionality.of(context) 3196 ..fit = fit 3197 ..overflow = overflow; 3198 } 3199 3200 @override 3201 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 3202 super.debugFillProperties(properties); 3203 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); 3204 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); 3205 properties.add(EnumProperty<StackFit>('fit', fit)); 3206 properties.add(EnumProperty<Overflow>('overflow', overflow)); 3207 } 3208} 3209 3210/// A [Stack] that shows a single child from a list of children. 3211/// 3212/// The displayed child is the one with the given [index]. The stack is 3213/// always as big as the largest child. 3214/// 3215/// If value is null, then nothing is displayed. 3216/// 3217/// See also: 3218/// 3219/// * [Stack], for more details about stacks. 3220/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 3221class IndexedStack extends Stack { 3222 /// Creates a [Stack] widget that paints a single child. 3223 /// 3224 /// The [index] argument must not be null. 3225 IndexedStack({ 3226 Key key, 3227 AlignmentGeometry alignment = AlignmentDirectional.topStart, 3228 TextDirection textDirection, 3229 StackFit sizing = StackFit.loose, 3230 this.index = 0, 3231 List<Widget> children = const <Widget>[], 3232 }) : super(key: key, alignment: alignment, textDirection: textDirection, fit: sizing, children: children); 3233 3234 /// The index of the child to show. 3235 final int index; 3236 3237 @override 3238 RenderIndexedStack createRenderObject(BuildContext context) { 3239 return RenderIndexedStack( 3240 index: index, 3241 alignment: alignment, 3242 textDirection: textDirection ?? Directionality.of(context), 3243 ); 3244 } 3245 3246 @override 3247 void updateRenderObject(BuildContext context, RenderIndexedStack renderObject) { 3248 renderObject 3249 ..index = index 3250 ..alignment = alignment 3251 ..textDirection = textDirection ?? Directionality.of(context); 3252 } 3253} 3254 3255/// A widget that controls where a child of a [Stack] is positioned. 3256/// 3257/// A [Positioned] widget must be a descendant of a [Stack], and the path from 3258/// the [Positioned] widget to its enclosing [Stack] must contain only 3259/// [StatelessWidget]s or [StatefulWidget]s (not other kinds of widgets, like 3260/// [RenderObjectWidget]s). 3261/// 3262/// {@youtube 560 315 https://www.youtube.com/watch?v=EgtPleVwxBQ} 3263/// 3264/// If a widget is wrapped in a [Positioned], then it is a _positioned_ widget 3265/// in its [Stack]. If the [top] property is non-null, the top edge of this child 3266/// will be positioned [top] layout units from the top of the stack widget. The 3267/// [right], [bottom], and [left] properties work analogously. 3268/// 3269/// If both the [top] and [bottom] properties are non-null, then the child will 3270/// be forced to have exactly the height required to satisfy both constraints. 3271/// Similarly, setting the [right] and [left] properties to non-null values will 3272/// force the child to have a particular width. Alternatively the [width] and 3273/// [height] properties can be used to give the dimensions, with one 3274/// corresponding position property (e.g. [top] and [height]). 3275/// 3276/// If all three values on a particular axis are null, then the 3277/// [Stack.alignment] property is used to position the child. 3278/// 3279/// If all six values are null, the child is a non-positioned child. The [Stack] 3280/// uses only the non-positioned children to size itself. 3281/// 3282/// See also: 3283/// 3284/// * [AnimatedPositioned], which automatically transitions the child's 3285/// position over a given duration whenever the given position changes. 3286/// * [PositionedTransition], which takes a provided [Animation] to transition 3287/// changes in the child's position over a given duration. 3288/// * [PositionedDirectional], which adapts to the ambient [Directionality]. 3289class Positioned extends ParentDataWidget<Stack> { 3290 /// Creates a widget that controls where a child of a [Stack] is positioned. 3291 /// 3292 /// Only two out of the three horizontal values ([left], [right], 3293 /// [width]), and only two out of the three vertical values ([top], 3294 /// [bottom], [height]), can be set. In each case, at least one of 3295 /// the three must be null. 3296 /// 3297 /// See also: 3298 /// 3299 /// * [Positioned.directional], which specifies the widget's horizontal 3300 /// position using `start` and `end` rather than `left` and `right`. 3301 /// * [PositionedDirectional], which is similar to [Positioned.directional] 3302 /// but adapts to the ambient [Directionality]. 3303 const Positioned({ 3304 Key key, 3305 this.left, 3306 this.top, 3307 this.right, 3308 this.bottom, 3309 this.width, 3310 this.height, 3311 @required Widget child, 3312 }) : assert(left == null || right == null || width == null), 3313 assert(top == null || bottom == null || height == null), 3314 super(key: key, child: child); 3315 3316 /// Creates a Positioned object with the values from the given [Rect]. 3317 /// 3318 /// This sets the [left], [top], [width], and [height] properties 3319 /// from the given [Rect]. The [right] and [bottom] properties are 3320 /// set to null. 3321 Positioned.fromRect({ 3322 Key key, 3323 Rect rect, 3324 @required Widget child, 3325 }) : left = rect.left, 3326 top = rect.top, 3327 width = rect.width, 3328 height = rect.height, 3329 right = null, 3330 bottom = null, 3331 super(key: key, child: child); 3332 3333 /// Creates a Positioned object with the values from the given [RelativeRect]. 3334 /// 3335 /// This sets the [left], [top], [right], and [bottom] properties from the 3336 /// given [RelativeRect]. The [height] and [width] properties are set to null. 3337 Positioned.fromRelativeRect({ 3338 Key key, 3339 RelativeRect rect, 3340 @required Widget child, 3341 }) : left = rect.left, 3342 top = rect.top, 3343 right = rect.right, 3344 bottom = rect.bottom, 3345 width = null, 3346 height = null, 3347 super(key: key, child: child); 3348 3349 /// Creates a Positioned object with [left], [top], [right], and [bottom] set 3350 /// to 0.0 unless a value for them is passed. 3351 const Positioned.fill({ 3352 Key key, 3353 this.left = 0.0, 3354 this.top = 0.0, 3355 this.right = 0.0, 3356 this.bottom = 0.0, 3357 @required Widget child, 3358 }) : width = null, 3359 height = null, 3360 super(key: key, child: child); 3361 3362 /// Creates a widget that controls where a child of a [Stack] is positioned. 3363 /// 3364 /// Only two out of the three horizontal values (`start`, `end`, 3365 /// [width]), and only two out of the three vertical values ([top], 3366 /// [bottom], [height]), can be set. In each case, at least one of 3367 /// the three must be null. 3368 /// 3369 /// If `textDirection` is [TextDirection.rtl], then the `start` argument is 3370 /// used for the [right] property and the `end` argument is used for the 3371 /// [left] property. Otherwise, if `textDirection` is [TextDirection.ltr], 3372 /// then the `start` argument is used for the [left] property and the `end` 3373 /// argument is used for the [right] property. 3374 /// 3375 /// The `textDirection` argument must not be null. 3376 /// 3377 /// See also: 3378 /// 3379 /// * [PositionedDirectional], which adapts to the ambient [Directionality]. 3380 factory Positioned.directional({ 3381 Key key, 3382 @required TextDirection textDirection, 3383 double start, 3384 double top, 3385 double end, 3386 double bottom, 3387 double width, 3388 double height, 3389 @required Widget child, 3390 }) { 3391 assert(textDirection != null); 3392 double left; 3393 double right; 3394 switch (textDirection) { 3395 case TextDirection.rtl: 3396 left = end; 3397 right = start; 3398 break; 3399 case TextDirection.ltr: 3400 left = start; 3401 right = end; 3402 break; 3403 } 3404 return Positioned( 3405 key: key, 3406 left: left, 3407 top: top, 3408 right: right, 3409 bottom: bottom, 3410 width: width, 3411 height: height, 3412 child: child, 3413 ); 3414 } 3415 3416 /// The distance that the child's left edge is inset from the left of the stack. 3417 /// 3418 /// Only two out of the three horizontal values ([left], [right], [width]) can be 3419 /// set. The third must be null. 3420 /// 3421 /// If all three are null, the [Stack.alignment] is used to position the child 3422 /// horizontally. 3423 final double left; 3424 3425 /// The distance that the child's top edge is inset from the top of the stack. 3426 /// 3427 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3428 /// set. The third must be null. 3429 /// 3430 /// If all three are null, the [Stack.alignment] is used to position the child 3431 /// vertically. 3432 final double top; 3433 3434 /// The distance that the child's right edge is inset from the right of the stack. 3435 /// 3436 /// Only two out of the three horizontal values ([left], [right], [width]) can be 3437 /// set. The third must be null. 3438 /// 3439 /// If all three are null, the [Stack.alignment] is used to position the child 3440 /// horizontally. 3441 final double right; 3442 3443 /// The distance that the child's bottom edge is inset from the bottom of the stack. 3444 /// 3445 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3446 /// set. The third must be null. 3447 /// 3448 /// If all three are null, the [Stack.alignment] is used to position the child 3449 /// vertically. 3450 final double bottom; 3451 3452 /// The child's width. 3453 /// 3454 /// Only two out of the three horizontal values ([left], [right], [width]) can be 3455 /// set. The third must be null. 3456 /// 3457 /// If all three are null, the [Stack.alignment] is used to position the child 3458 /// horizontally. 3459 final double width; 3460 3461 /// The child's height. 3462 /// 3463 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3464 /// set. The third must be null. 3465 /// 3466 /// If all three are null, the [Stack.alignment] is used to position the child 3467 /// vertically. 3468 final double height; 3469 3470 @override 3471 void applyParentData(RenderObject renderObject) { 3472 assert(renderObject.parentData is StackParentData); 3473 final StackParentData parentData = renderObject.parentData; 3474 bool needsLayout = false; 3475 3476 if (parentData.left != left) { 3477 parentData.left = left; 3478 needsLayout = true; 3479 } 3480 3481 if (parentData.top != top) { 3482 parentData.top = top; 3483 needsLayout = true; 3484 } 3485 3486 if (parentData.right != right) { 3487 parentData.right = right; 3488 needsLayout = true; 3489 } 3490 3491 if (parentData.bottom != bottom) { 3492 parentData.bottom = bottom; 3493 needsLayout = true; 3494 } 3495 3496 if (parentData.width != width) { 3497 parentData.width = width; 3498 needsLayout = true; 3499 } 3500 3501 if (parentData.height != height) { 3502 parentData.height = height; 3503 needsLayout = true; 3504 } 3505 3506 if (needsLayout) { 3507 final AbstractNode targetParent = renderObject.parent; 3508 if (targetParent is RenderObject) 3509 targetParent.markNeedsLayout(); 3510 } 3511 } 3512 3513 @override 3514 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 3515 super.debugFillProperties(properties); 3516 properties.add(DoubleProperty('left', left, defaultValue: null)); 3517 properties.add(DoubleProperty('top', top, defaultValue: null)); 3518 properties.add(DoubleProperty('right', right, defaultValue: null)); 3519 properties.add(DoubleProperty('bottom', bottom, defaultValue: null)); 3520 properties.add(DoubleProperty('width', width, defaultValue: null)); 3521 properties.add(DoubleProperty('height', height, defaultValue: null)); 3522 } 3523} 3524 3525/// A widget that controls where a child of a [Stack] is positioned without 3526/// committing to a specific [TextDirection]. 3527/// 3528/// The ambient [Directionality] is used to determine whether [start] is to the 3529/// left or to the right. 3530/// 3531/// A [PositionedDirectional] widget must be a descendant of a [Stack], and the 3532/// path from the [PositionedDirectional] widget to its enclosing [Stack] must 3533/// contain only [StatelessWidget]s or [StatefulWidget]s (not other kinds of 3534/// widgets, like [RenderObjectWidget]s). 3535/// 3536/// If a widget is wrapped in a [PositionedDirectional], then it is a 3537/// _positioned_ widget in its [Stack]. If the [top] property is non-null, the 3538/// top edge of this child/ will be positioned [top] layout units from the top 3539/// of the stack widget. The [start], [bottom], and [end] properties work 3540/// analogously. 3541/// 3542/// If both the [top] and [bottom] properties are non-null, then the child will 3543/// be forced to have exactly the height required to satisfy both constraints. 3544/// Similarly, setting the [start] and [end] properties to non-null values will 3545/// force the child to have a particular width. Alternatively the [width] and 3546/// [height] properties can be used to give the dimensions, with one 3547/// corresponding position property (e.g. [top] and [height]). 3548/// 3549/// See also: 3550/// 3551/// * [Positioned], which specifies the widget's position visually. 3552/// * [Positioned.directional], which also specifies the widget's horizontal 3553/// position using [start] and [end] but has an explicit [TextDirection]. 3554/// * [AnimatedPositionedDirectional], which automatically transitions 3555/// the child's position over a given duration whenever the given position 3556/// changes. 3557class PositionedDirectional extends StatelessWidget { 3558 /// Creates a widget that controls where a child of a [Stack] is positioned. 3559 /// 3560 /// Only two out of the three horizontal values (`start`, `end`, 3561 /// [width]), and only two out of the three vertical values ([top], 3562 /// [bottom], [height]), can be set. In each case, at least one of 3563 /// the three must be null. 3564 /// 3565 /// See also: 3566 /// 3567 /// * [Positioned.directional], which also specifies the widget's horizontal 3568 /// position using [start] and [end] but has an explicit [TextDirection]. 3569 const PositionedDirectional({ 3570 Key key, 3571 this.start, 3572 this.top, 3573 this.end, 3574 this.bottom, 3575 this.width, 3576 this.height, 3577 @required this.child, 3578 }) : super(key: key); 3579 3580 /// The distance that the child's leading edge is inset from the leading edge 3581 /// of the stack. 3582 /// 3583 /// Only two out of the three horizontal values ([start], [end], [width]) can be 3584 /// set. The third must be null. 3585 final double start; 3586 3587 /// The distance that the child's top edge is inset from the top of the stack. 3588 /// 3589 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3590 /// set. The third must be null. 3591 final double top; 3592 3593 /// The distance that the child's trailing edge is inset from the trailing 3594 /// edge of the stack. 3595 /// 3596 /// Only two out of the three horizontal values ([start], [end], [width]) can be 3597 /// set. The third must be null. 3598 final double end; 3599 3600 /// The distance that the child's bottom edge is inset from the bottom of the stack. 3601 /// 3602 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3603 /// set. The third must be null. 3604 final double bottom; 3605 3606 /// The child's width. 3607 /// 3608 /// Only two out of the three horizontal values ([start], [end], [width]) can be 3609 /// set. The third must be null. 3610 final double width; 3611 3612 /// The child's height. 3613 /// 3614 /// Only two out of the three vertical values ([top], [bottom], [height]) can be 3615 /// set. The third must be null. 3616 final double height; 3617 3618 /// The widget below this widget in the tree. 3619 /// 3620 /// {@macro flutter.widgets.child} 3621 final Widget child; 3622 3623 @override 3624 Widget build(BuildContext context) { 3625 return Positioned.directional( 3626 textDirection: Directionality.of(context), 3627 start: start, 3628 top: top, 3629 end: end, 3630 bottom: bottom, 3631 width: width, 3632 height: height, 3633 child: child, 3634 ); 3635 } 3636} 3637 3638/// A widget that displays its children in a one-dimensional array. 3639/// 3640/// The [Flex] widget allows you to control the axis along which the children are 3641/// placed (horizontal or vertical). This is referred to as the _main axis_. If 3642/// you know the main axis in advance, then consider using a [Row] (if it's 3643/// horizontal) or [Column] (if it's vertical) instead, because that will be less 3644/// verbose. 3645/// 3646/// To cause a child to expand to fill the available space in the [direction] 3647/// of this widget's main axis, wrap the child in an [Expanded] widget. 3648/// 3649/// The [Flex] widget does not scroll (and in general it is considered an error 3650/// to have more children in a [Flex] than will fit in the available room). If 3651/// you have some widgets and want them to be able to scroll if there is 3652/// insufficient room, consider using a [ListView]. 3653/// 3654/// If you only have one child, then rather than using [Flex], [Row], or 3655/// [Column], consider using [Align] or [Center] to position the child. 3656/// 3657/// ## Layout algorithm 3658/// 3659/// _This section describes how a [Flex] is rendered by the framework._ 3660/// _See [BoxConstraints] for an introduction to box layout models._ 3661/// 3662/// Layout for a [Flex] proceeds in six steps: 3663/// 3664/// 1. Layout each child a null or zero flex factor (e.g., those that are not 3665/// [Expanded]) with unbounded main axis constraints and the incoming 3666/// cross axis constraints. If the [crossAxisAlignment] is 3667/// [CrossAxisAlignment.stretch], instead use tight cross axis constraints 3668/// that match the incoming max extent in the cross axis. 3669/// 2. Divide the remaining main axis space among the children with non-zero 3670/// flex factors (e.g., those that are [Expanded]) according to their flex 3671/// factor. For example, a child with a flex factor of 2.0 will receive twice 3672/// the amount of main axis space as a child with a flex factor of 1.0. 3673/// 3. Layout each of the remaining children with the same cross axis 3674/// constraints as in step 1, but instead of using unbounded main axis 3675/// constraints, use max axis constraints based on the amount of space 3676/// allocated in step 2. Children with [Flexible.fit] properties that are 3677/// [FlexFit.tight] are given tight constraints (i.e., forced to fill the 3678/// allocated space), and children with [Flexible.fit] properties that are 3679/// [FlexFit.loose] are given loose constraints (i.e., not forced to fill the 3680/// allocated space). 3681/// 4. The cross axis extent of the [Flex] is the maximum cross axis extent of 3682/// the children (which will always satisfy the incoming constraints). 3683/// 5. The main axis extent of the [Flex] is determined by the [mainAxisSize] 3684/// property. If the [mainAxisSize] property is [MainAxisSize.max], then the 3685/// main axis extent of the [Flex] is the max extent of the incoming main 3686/// axis constraints. If the [mainAxisSize] property is [MainAxisSize.min], 3687/// then the main axis extent of the [Flex] is the sum of the main axis 3688/// extents of the children (subject to the incoming constraints). 3689/// 6. Determine the position for each child according to the 3690/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the 3691/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any main axis 3692/// space that has not been allocated to children is divided evenly and 3693/// placed between the children. 3694/// 3695/// See also: 3696/// 3697/// * [Row], for a version of this widget that is always horizontal. 3698/// * [Column], for a version of this widget that is always vertical. 3699/// * [Expanded], to indicate children that should take all the remaining room. 3700/// * [Flexible], to indicate children that should share the remaining room. 3701/// * [Spacer], a widget that takes up space proportional to it's flex value. 3702/// that may be sized smaller (leaving some remaining room unused). 3703/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 3704class Flex extends MultiChildRenderObjectWidget { 3705 /// Creates a flex layout. 3706 /// 3707 /// The [direction] is required. 3708 /// 3709 /// The [direction], [mainAxisAlignment], [crossAxisAlignment], and 3710 /// [verticalDirection] arguments must not be null. If [crossAxisAlignment] is 3711 /// [CrossAxisAlignment.baseline], then [textBaseline] must not be null. 3712 /// 3713 /// The [textDirection] argument defaults to the ambient [Directionality], if 3714 /// any. If there is no ambient directionality, and a text direction is going 3715 /// to be necessary to decide which direction to lay the children in or to 3716 /// disambiguate `start` or `end` values for the main or cross axis 3717 /// directions, the [textDirection] must not be null. 3718 Flex({ 3719 Key key, 3720 @required this.direction, 3721 this.mainAxisAlignment = MainAxisAlignment.start, 3722 this.mainAxisSize = MainAxisSize.max, 3723 this.crossAxisAlignment = CrossAxisAlignment.center, 3724 this.textDirection, 3725 this.verticalDirection = VerticalDirection.down, 3726 this.textBaseline, 3727 List<Widget> children = const <Widget>[], 3728 }) : assert(direction != null), 3729 assert(mainAxisAlignment != null), 3730 assert(mainAxisSize != null), 3731 assert(crossAxisAlignment != null), 3732 assert(verticalDirection != null), 3733 assert(crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null), 3734 super(key: key, children: children); 3735 3736 /// The direction to use as the main axis. 3737 /// 3738 /// If you know the axis in advance, then consider using a [Row] (if it's 3739 /// horizontal) or [Column] (if it's vertical) instead of a [Flex], since that 3740 /// will be less verbose. (For [Row] and [Column] this property is fixed to 3741 /// the appropriate axis.) 3742 final Axis direction; 3743 3744 /// How the children should be placed along the main axis. 3745 /// 3746 /// For example, [MainAxisAlignment.start], the default, places the children 3747 /// at the start (i.e., the left for a [Row] or the top for a [Column]) of the 3748 /// main axis. 3749 final MainAxisAlignment mainAxisAlignment; 3750 3751 /// How much space should be occupied in the main axis. 3752 /// 3753 /// After allocating space to children, there might be some remaining free 3754 /// space. This value controls whether to maximize or minimize the amount of 3755 /// free space, subject to the incoming layout constraints. 3756 /// 3757 /// If some children have a non-zero flex factors (and none have a fit of 3758 /// [FlexFit.loose]), they will expand to consume all the available space and 3759 /// there will be no remaining free space to maximize or minimize, making this 3760 /// value irrelevant to the final layout. 3761 final MainAxisSize mainAxisSize; 3762 3763 /// How the children should be placed along the cross axis. 3764 /// 3765 /// For example, [CrossAxisAlignment.center], the default, centers the 3766 /// children in the cross axis (e.g., horizontally for a [Column]). 3767 final CrossAxisAlignment crossAxisAlignment; 3768 3769 /// Determines the order to lay children out horizontally and how to interpret 3770 /// `start` and `end` in the horizontal direction. 3771 /// 3772 /// Defaults to the ambient [Directionality]. 3773 /// 3774 /// If the [direction] is [Axis.horizontal], this controls the order in which 3775 /// the children are positioned (left-to-right or right-to-left), and the 3776 /// meaning of the [mainAxisAlignment] property's [MainAxisAlignment.start] and 3777 /// [MainAxisAlignment.end] values. 3778 /// 3779 /// If the [direction] is [Axis.horizontal], and either the 3780 /// [mainAxisAlignment] is either [MainAxisAlignment.start] or 3781 /// [MainAxisAlignment.end], or there's more than one child, then the 3782 /// [textDirection] (or the ambient [Directionality]) must not be null. 3783 /// 3784 /// If the [direction] is [Axis.vertical], this controls the meaning of the 3785 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and 3786 /// [CrossAxisAlignment.end] values. 3787 /// 3788 /// If the [direction] is [Axis.vertical], and the [crossAxisAlignment] is 3789 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the 3790 /// [textDirection] (or the ambient [Directionality]) must not be null. 3791 final TextDirection textDirection; 3792 3793 /// Determines the order to lay children out vertically and how to interpret 3794 /// `start` and `end` in the vertical direction. 3795 /// 3796 /// Defaults to [VerticalDirection.down]. 3797 /// 3798 /// If the [direction] is [Axis.vertical], this controls which order children 3799 /// are painted in (down or up), the meaning of the [mainAxisAlignment] 3800 /// property's [MainAxisAlignment.start] and [MainAxisAlignment.end] values. 3801 /// 3802 /// If the [direction] is [Axis.vertical], and either the [mainAxisAlignment] 3803 /// is either [MainAxisAlignment.start] or [MainAxisAlignment.end], or there's 3804 /// more than one child, then the [verticalDirection] must not be null. 3805 /// 3806 /// If the [direction] is [Axis.horizontal], this controls the meaning of the 3807 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and 3808 /// [CrossAxisAlignment.end] values. 3809 /// 3810 /// If the [direction] is [Axis.horizontal], and the [crossAxisAlignment] is 3811 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the 3812 /// [verticalDirection] must not be null. 3813 final VerticalDirection verticalDirection; 3814 3815 /// If aligning items according to their baseline, which baseline to use. 3816 final TextBaseline textBaseline; 3817 3818 bool get _needTextDirection { 3819 assert(direction != null); 3820 switch (direction) { 3821 case Axis.horizontal: 3822 return true; // because it affects the layout order. 3823 case Axis.vertical: 3824 assert(crossAxisAlignment != null); 3825 return crossAxisAlignment == CrossAxisAlignment.start 3826 || crossAxisAlignment == CrossAxisAlignment.end; 3827 } 3828 return null; 3829 } 3830 3831 /// The value to pass to [RenderFlex.textDirection]. 3832 /// 3833 /// This value is derived from the [textDirection] property and the ambient 3834 /// [Directionality]. The value is null if there is no need to specify the 3835 /// text direction. In practice there's always a need to specify the direction 3836 /// except for vertical flexes (e.g. [Column]s) whose [crossAxisAlignment] is 3837 /// not dependent on the text direction (not `start` or `end`). In particular, 3838 /// a [Row] always needs a text direction because the text direction controls 3839 /// its layout order. (For [Column]s, the layout order is controlled by 3840 /// [verticalDirection], which is always specified as it does not depend on an 3841 /// inherited widget and defaults to [VerticalDirection.down].) 3842 /// 3843 /// This method exists so that subclasses of [Flex] that create their own 3844 /// render objects that are derived from [RenderFlex] can do so and still use 3845 /// the logic for providing a text direction only when it is necessary. 3846 @protected 3847 TextDirection getEffectiveTextDirection(BuildContext context) { 3848 return textDirection ?? (_needTextDirection ? Directionality.of(context) : null); 3849 } 3850 3851 @override 3852 RenderFlex createRenderObject(BuildContext context) { 3853 return RenderFlex( 3854 direction: direction, 3855 mainAxisAlignment: mainAxisAlignment, 3856 mainAxisSize: mainAxisSize, 3857 crossAxisAlignment: crossAxisAlignment, 3858 textDirection: getEffectiveTextDirection(context), 3859 verticalDirection: verticalDirection, 3860 textBaseline: textBaseline, 3861 ); 3862 } 3863 3864 @override 3865 void updateRenderObject(BuildContext context, covariant RenderFlex renderObject) { 3866 renderObject 3867 ..direction = direction 3868 ..mainAxisAlignment = mainAxisAlignment 3869 ..mainAxisSize = mainAxisSize 3870 ..crossAxisAlignment = crossAxisAlignment 3871 ..textDirection = getEffectiveTextDirection(context) 3872 ..verticalDirection = verticalDirection 3873 ..textBaseline = textBaseline; 3874 } 3875 3876 @override 3877 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 3878 super.debugFillProperties(properties); 3879 properties.add(EnumProperty<Axis>('direction', direction)); 3880 properties.add(EnumProperty<MainAxisAlignment>('mainAxisAlignment', mainAxisAlignment)); 3881 properties.add(EnumProperty<MainAxisSize>('mainAxisSize', mainAxisSize, defaultValue: MainAxisSize.max)); 3882 properties.add(EnumProperty<CrossAxisAlignment>('crossAxisAlignment', crossAxisAlignment)); 3883 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); 3884 properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down)); 3885 properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null)); 3886 } 3887} 3888 3889/// A widget that displays its children in a horizontal array. 3890/// 3891/// To cause a child to expand to fill the available horizontal space, wrap the 3892/// child in an [Expanded] widget. 3893/// 3894/// The [Row] widget does not scroll (and in general it is considered an error 3895/// to have more children in a [Row] than will fit in the available room). If 3896/// you have a line of widgets and want them to be able to scroll if there is 3897/// insufficient room, consider using a [ListView]. 3898/// 3899/// For a vertical variant, see [Column]. 3900/// 3901/// If you only have one child, then consider using [Align] or [Center] to 3902/// position the child. 3903/// 3904/// {@tool sample} 3905/// 3906/// This example divides the available space into three (horizontally), and 3907/// places text centered in the first two cells and the Flutter logo centered in 3908/// the third: 3909/// 3910///  3911/// 3912/// ```dart 3913/// Row( 3914/// children: <Widget>[ 3915/// Expanded( 3916/// child: Text('Deliver features faster', textAlign: TextAlign.center), 3917/// ), 3918/// Expanded( 3919/// child: Text('Craft beautiful UIs', textAlign: TextAlign.center), 3920/// ), 3921/// Expanded( 3922/// child: FittedBox( 3923/// fit: BoxFit.contain, // otherwise the logo will be tiny 3924/// child: const FlutterLogo(), 3925/// ), 3926/// ), 3927/// ], 3928/// ) 3929/// ``` 3930/// {@end-tool} 3931/// 3932/// ## Troubleshooting 3933/// 3934/// ### Why does my row have a yellow and black warning stripe? 3935/// 3936/// If the non-flexible contents of the row (those that are not wrapped in 3937/// [Expanded] or [Flexible] widgets) are together wider than the row itself, 3938/// then the row is said to have overflowed. When a row overflows, the row does 3939/// not have any remaining space to share between its [Expanded] and [Flexible] 3940/// children. The row reports this by drawing a yellow and black striped 3941/// warning box on the edge that is overflowing. If there is room on the outside 3942/// of the row, the amount of overflow is printed in red lettering. 3943/// 3944/// #### Story time 3945/// 3946/// Suppose, for instance, that you had this code: 3947/// 3948/// ```dart 3949/// Row( 3950/// children: <Widget>[ 3951/// const FlutterLogo(), 3952/// const Text('Flutter\'s hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android.'), 3953/// const Icon(Icons.sentiment_very_satisfied), 3954/// ], 3955/// ) 3956/// ``` 3957/// 3958/// You will see this issue when you run the app: 3959/// 3960///  3961/// 3962/// The row first asks its first child, the [FlutterLogo], to lay out, at 3963/// whatever size the logo would like. The logo is friendly and happily decides 3964/// to be 24 pixels to a side. This leaves lots of room for the next child. The 3965/// row then asks that next child, the text, to lay out, at whatever size it 3966/// thinks is best. 3967/// 3968/// At this point, the text, not knowing how wide is too wide, says "Ok, I will 3969/// be thiiiiiiiiiiiiiiiiiiiis wide.", and goes well beyond the space that the 3970/// row has available, not wrapping. The row responds, "That's not fair, now I 3971/// have no more room available for my other children!", and gets angry and 3972/// sprouts a yellow and black strip. 3973/// 3974/// {@tool sample} 3975/// The fix is to wrap the second child in an [Expanded] widget, which tells the 3976/// row that the child should be given the remaining room: 3977/// 3978///  3979/// 3980/// ```dart 3981/// Row( 3982/// children: <Widget>[ 3983/// const FlutterLogo(), 3984/// const Expanded( 3985/// child: Text('Flutter\'s hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android.'), 3986/// ), 3987/// const Icon(Icons.sentiment_very_satisfied), 3988/// ], 3989/// ) 3990/// ``` 3991/// {@end-tool} 3992/// 3993/// Now, the row first asks the logo to lay out, and then asks the _icon_ to lay 3994/// out. The [Icon], like the logo, is happy to take on a reasonable size (also 3995/// 24 pixels, not coincidentally, since both [FlutterLogo] and [Icon] honor the 3996/// ambient [IconTheme]). This leaves some room left over, and now the row tells 3997/// the text exactly how wide to be: the exact width of the remaining space. The 3998/// text, now happy to comply to a reasonable request, wraps the text within 3999/// that width, and you end up with a paragraph split over several lines. 4000/// 4001/// ## Layout algorithm 4002/// 4003/// _This section describes how a [Row] is rendered by the framework._ 4004/// _See [BoxConstraints] for an introduction to box layout models._ 4005/// 4006/// Layout for a [Row] proceeds in six steps: 4007/// 4008/// 1. Layout each child a null or zero flex factor (e.g., those that are not 4009/// [Expanded]) with unbounded horizontal constraints and the incoming 4010/// vertical constraints. If the [crossAxisAlignment] is 4011/// [CrossAxisAlignment.stretch], instead use tight vertical constraints that 4012/// match the incoming max height. 4013/// 2. Divide the remaining horizontal space among the children with non-zero 4014/// flex factors (e.g., those that are [Expanded]) according to their flex 4015/// factor. For example, a child with a flex factor of 2.0 will receive twice 4016/// the amount of horizontal space as a child with a flex factor of 1.0. 4017/// 3. Layout each of the remaining children with the same vertical constraints 4018/// as in step 1, but instead of using unbounded horizontal constraints, use 4019/// horizontal constraints based on the amount of space allocated in step 2. 4020/// Children with [Flexible.fit] properties that are [FlexFit.tight] are 4021/// given tight constraints (i.e., forced to fill the allocated space), and 4022/// children with [Flexible.fit] properties that are [FlexFit.loose] are 4023/// given loose constraints (i.e., not forced to fill the allocated space). 4024/// 4. The height of the [Row] is the maximum height of the children (which will 4025/// always satisfy the incoming vertical constraints). 4026/// 5. The width of the [Row] is determined by the [mainAxisSize] property. If 4027/// the [mainAxisSize] property is [MainAxisSize.max], then the width of the 4028/// [Row] is the max width of the incoming constraints. If the [mainAxisSize] 4029/// property is [MainAxisSize.min], then the width of the [Row] is the sum 4030/// of widths of the children (subject to the incoming constraints). 4031/// 6. Determine the position for each child according to the 4032/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the 4033/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any horizontal 4034/// space that has not been allocated to children is divided evenly and 4035/// placed between the children. 4036/// 4037/// See also: 4038/// 4039/// * [Column], for a vertical equivalent. 4040/// * [Flex], if you don't know in advance if you want a horizontal or vertical 4041/// arrangement. 4042/// * [Expanded], to indicate children that should take all the remaining room. 4043/// * [Flexible], to indicate children that should share the remaining room but 4044/// that may by sized smaller (leaving some remaining room unused). 4045/// * [Spacer], a widget that takes up space proportional to it's flex value. 4046/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4047class Row extends Flex { 4048 /// Creates a horizontal array of children. 4049 /// 4050 /// The [direction], [mainAxisAlignment], [mainAxisSize], 4051 /// [crossAxisAlignment], and [verticalDirection] arguments must not be null. 4052 /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then 4053 /// [textBaseline] must not be null. 4054 /// 4055 /// The [textDirection] argument defaults to the ambient [Directionality], if 4056 /// any. If there is no ambient directionality, and a text direction is going 4057 /// to be necessary to determine the layout order (which is always the case 4058 /// unless the row has no children or only one child) or to disambiguate 4059 /// `start` or `end` values for the [mainAxisAlignment], the [textDirection] 4060 /// must not be null. 4061 Row({ 4062 Key key, 4063 MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, 4064 MainAxisSize mainAxisSize = MainAxisSize.max, 4065 CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, 4066 TextDirection textDirection, 4067 VerticalDirection verticalDirection = VerticalDirection.down, 4068 TextBaseline textBaseline, 4069 List<Widget> children = const <Widget>[], 4070 }) : super( 4071 children: children, 4072 key: key, 4073 direction: Axis.horizontal, 4074 mainAxisAlignment: mainAxisAlignment, 4075 mainAxisSize: mainAxisSize, 4076 crossAxisAlignment: crossAxisAlignment, 4077 textDirection: textDirection, 4078 verticalDirection: verticalDirection, 4079 textBaseline: textBaseline, 4080 ); 4081} 4082 4083/// A widget that displays its children in a vertical array. 4084/// 4085/// To cause a child to expand to fill the available vertical space, wrap the 4086/// child in an [Expanded] widget. 4087/// 4088/// The [Column] widget does not scroll (and in general it is considered an error 4089/// to have more children in a [Column] than will fit in the available room). If 4090/// you have a line of widgets and want them to be able to scroll if there is 4091/// insufficient room, consider using a [ListView]. 4092/// 4093/// For a horizontal variant, see [Row]. 4094/// 4095/// If you only have one child, then consider using [Align] or [Center] to 4096/// position the child. 4097/// 4098/// {@tool sample} 4099/// 4100/// This example uses a [Column] to arrange three widgets vertically, the last 4101/// being made to fill all the remaining space. 4102/// 4103///  4104/// 4105/// ```dart 4106/// Column( 4107/// children: <Widget>[ 4108/// Text('Deliver features faster'), 4109/// Text('Craft beautiful UIs'), 4110/// Expanded( 4111/// child: FittedBox( 4112/// fit: BoxFit.contain, // otherwise the logo will be tiny 4113/// child: const FlutterLogo(), 4114/// ), 4115/// ), 4116/// ], 4117/// ) 4118/// ``` 4119/// {@end-tool} 4120/// {@tool sample} 4121/// 4122/// In the sample above, the text and the logo are centered on each line. In the 4123/// following example, the [crossAxisAlignment] is set to 4124/// [CrossAxisAlignment.start], so that the children are left-aligned. The 4125/// [mainAxisSize] is set to [MainAxisSize.min], so that the column shrinks to 4126/// fit the children. 4127/// 4128///  4129/// 4130/// ```dart 4131/// Column( 4132/// crossAxisAlignment: CrossAxisAlignment.start, 4133/// mainAxisSize: MainAxisSize.min, 4134/// children: <Widget>[ 4135/// Text('We move under cover and we move as one'), 4136/// Text('Through the night, we have one shot to live another day'), 4137/// Text('We cannot let a stray gunshot give us away'), 4138/// Text('We will fight up close, seize the moment and stay in it'), 4139/// Text('It’s either that or meet the business end of a bayonet'), 4140/// Text('The code word is ‘Rochambeau,’ dig me?'), 4141/// Text('Rochambeau!', style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 2.0)), 4142/// ], 4143/// ) 4144/// ``` 4145/// {@end-tool} 4146/// 4147/// ## Troubleshooting 4148/// 4149/// ### When the incoming vertical constraints are unbounded 4150/// 4151/// When a [Column] has one or more [Expanded] or [Flexible] children, and is 4152/// placed in another [Column], or in a [ListView], or in some other context 4153/// that does not provide a maximum height constraint for the [Column], you will 4154/// get an exception at runtime saying that there are children with non-zero 4155/// flex but the vertical constraints are unbounded. 4156/// 4157/// The problem, as described in the details that accompany that exception, is 4158/// that using [Flexible] or [Expanded] means that the remaining space after 4159/// laying out all the other children must be shared equally, but if the 4160/// incoming vertical constraints are unbounded, there is infinite remaining 4161/// space. 4162/// 4163/// The key to solving this problem is usually to determine why the [Column] is 4164/// receiving unbounded vertical constraints. 4165/// 4166/// One common reason for this to happen is that the [Column] has been placed in 4167/// another [Column] (without using [Expanded] or [Flexible] around the inner 4168/// nested [Column]). When a [Column] lays out its non-flex children (those that 4169/// have neither [Expanded] or [Flexible] around them), it gives them unbounded 4170/// constraints so that they can determine their own dimensions (passing 4171/// unbounded constraints usually signals to the child that it should 4172/// shrink-wrap its contents). The solution in this case is typically to just 4173/// wrap the inner column in an [Expanded] to indicate that it should take the 4174/// remaining space of the outer column, rather than being allowed to take any 4175/// amount of room it desires. 4176/// 4177/// Another reason for this message to be displayed is nesting a [Column] inside 4178/// a [ListView] or other vertical scrollable. In that scenario, there really is 4179/// infinite vertical space (the whole point of a vertical scrolling list is to 4180/// allow infinite space vertically). In such scenarios, it is usually worth 4181/// examining why the inner [Column] should have an [Expanded] or [Flexible] 4182/// child: what size should the inner children really be? The solution in this 4183/// case is typically to remove the [Expanded] or [Flexible] widgets from around 4184/// the inner children. 4185/// 4186/// For more discussion about constraints, see [BoxConstraints]. 4187/// 4188/// ### The yellow and black striped banner 4189/// 4190/// When the contents of a [Column] exceed the amount of space available, the 4191/// [Column] overflows, and the contents are clipped. In debug mode, a yellow 4192/// and black striped bar is rendered at the overflowing edge to indicate the 4193/// problem, and a message is printed below the [Column] saying how much 4194/// overflow was detected. 4195/// 4196/// The usual solution is to use a [ListView] rather than a [Column], to enable 4197/// the contents to scroll when vertical space is limited. 4198/// 4199/// ## Layout algorithm 4200/// 4201/// _This section describes how a [Column] is rendered by the framework._ 4202/// _See [BoxConstraints] for an introduction to box layout models._ 4203/// 4204/// Layout for a [Column] proceeds in six steps: 4205/// 4206/// 1. Layout each child a null or zero flex factor (e.g., those that are not 4207/// [Expanded]) with unbounded vertical constraints and the incoming 4208/// horizontal constraints. If the [crossAxisAlignment] is 4209/// [CrossAxisAlignment.stretch], instead use tight horizontal constraints 4210/// that match the incoming max width. 4211/// 2. Divide the remaining vertical space among the children with non-zero 4212/// flex factors (e.g., those that are [Expanded]) according to their flex 4213/// factor. For example, a child with a flex factor of 2.0 will receive twice 4214/// the amount of vertical space as a child with a flex factor of 1.0. 4215/// 3. Layout each of the remaining children with the same horizontal 4216/// constraints as in step 1, but instead of using unbounded vertical 4217/// constraints, use vertical constraints based on the amount of space 4218/// allocated in step 2. Children with [Flexible.fit] properties that are 4219/// [FlexFit.tight] are given tight constraints (i.e., forced to fill the 4220/// allocated space), and children with [Flexible.fit] properties that are 4221/// [FlexFit.loose] are given loose constraints (i.e., not forced to fill the 4222/// allocated space). 4223/// 4. The width of the [Column] is the maximum width of the children (which 4224/// will always satisfy the incoming horizontal constraints). 4225/// 5. The height of the [Column] is determined by the [mainAxisSize] property. 4226/// If the [mainAxisSize] property is [MainAxisSize.max], then the height of 4227/// the [Column] is the max height of the incoming constraints. If the 4228/// [mainAxisSize] property is [MainAxisSize.min], then the height of the 4229/// [Column] is the sum of heights of the children (subject to the incoming 4230/// constraints). 4231/// 6. Determine the position for each child according to the 4232/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the 4233/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any vertical 4234/// space that has not been allocated to children is divided evenly and 4235/// placed between the children. 4236/// 4237/// See also: 4238/// 4239/// * [Row], for a horizontal equivalent. 4240/// * [Flex], if you don't know in advance if you want a horizontal or vertical 4241/// arrangement. 4242/// * [Expanded], to indicate children that should take all the remaining room. 4243/// * [Flexible], to indicate children that should share the remaining room but 4244/// that may size smaller (leaving some remaining room unused). 4245/// * [SingleChildScrollView], whose documentation discusses some ways to 4246/// use a [Column] inside a scrolling container. 4247/// * [Spacer], a widget that takes up space proportional to it's flex value. 4248/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4249class Column extends Flex { 4250 /// Creates a vertical array of children. 4251 /// 4252 /// The [direction], [mainAxisAlignment], [mainAxisSize], 4253 /// [crossAxisAlignment], and [verticalDirection] arguments must not be null. 4254 /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then 4255 /// [textBaseline] must not be null. 4256 /// 4257 /// The [textDirection] argument defaults to the ambient [Directionality], if 4258 /// any. If there is no ambient directionality, and a text direction is going 4259 /// to be necessary to disambiguate `start` or `end` values for the 4260 /// [crossAxisAlignment], the [textDirection] must not be null. 4261 Column({ 4262 Key key, 4263 MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, 4264 MainAxisSize mainAxisSize = MainAxisSize.max, 4265 CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, 4266 TextDirection textDirection, 4267 VerticalDirection verticalDirection = VerticalDirection.down, 4268 TextBaseline textBaseline, 4269 List<Widget> children = const <Widget>[], 4270 }) : super( 4271 children: children, 4272 key: key, 4273 direction: Axis.vertical, 4274 mainAxisAlignment: mainAxisAlignment, 4275 mainAxisSize: mainAxisSize, 4276 crossAxisAlignment: crossAxisAlignment, 4277 textDirection: textDirection, 4278 verticalDirection: verticalDirection, 4279 textBaseline: textBaseline, 4280 ); 4281} 4282 4283/// A widget that controls how a child of a [Row], [Column], or [Flex] flexes. 4284/// 4285/// Using a [Flexible] widget gives a child of a [Row], [Column], or [Flex] 4286/// the flexibility to expand to fill the available space in the main axis 4287/// (e.g., horizontally for a [Row] or vertically for a [Column]), but, unlike 4288/// [Expanded], [Flexible] does not require the child to fill the available 4289/// space. 4290/// 4291/// A [Flexible] widget must be a descendant of a [Row], [Column], or [Flex], 4292/// and the path from the [Flexible] widget to its enclosing [Row], [Column], or 4293/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other 4294/// kinds of widgets, like [RenderObjectWidget]s). 4295/// 4296/// {@youtube 560 315 https://www.youtube.com/watch?v=CI7x0mAZiY0} 4297/// 4298/// See also: 4299/// 4300/// * [Expanded], which forces the child to expand to fill the available space. 4301/// * [Spacer], a widget that takes up space proportional to it's flex value. 4302/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4303class Flexible extends ParentDataWidget<Flex> { 4304 /// Creates a widget that controls how a child of a [Row], [Column], or [Flex] 4305 /// flexes. 4306 const Flexible({ 4307 Key key, 4308 this.flex = 1, 4309 this.fit = FlexFit.loose, 4310 @required Widget child, 4311 }) : super(key: key, child: child); 4312 4313 /// The flex factor to use for this child 4314 /// 4315 /// If null or zero, the child is inflexible and determines its own size. If 4316 /// non-zero, the amount of space the child's can occupy in the main axis is 4317 /// determined by dividing the free space (after placing the inflexible 4318 /// children) according to the flex factors of the flexible children. 4319 final int flex; 4320 4321 /// How a flexible child is inscribed into the available space. 4322 /// 4323 /// If [flex] is non-zero, the [fit] determines whether the child fills the 4324 /// space the parent makes available during layout. If the fit is 4325 /// [FlexFit.tight], the child is required to fill the available space. If the 4326 /// fit is [FlexFit.loose], the child can be at most as large as the available 4327 /// space (but is allowed to be smaller). 4328 final FlexFit fit; 4329 4330 @override 4331 void applyParentData(RenderObject renderObject) { 4332 assert(renderObject.parentData is FlexParentData); 4333 final FlexParentData parentData = renderObject.parentData; 4334 bool needsLayout = false; 4335 4336 if (parentData.flex != flex) { 4337 parentData.flex = flex; 4338 needsLayout = true; 4339 } 4340 4341 if (parentData.fit != fit) { 4342 parentData.fit = fit; 4343 needsLayout = true; 4344 } 4345 4346 if (needsLayout) { 4347 final AbstractNode targetParent = renderObject.parent; 4348 if (targetParent is RenderObject) 4349 targetParent.markNeedsLayout(); 4350 } 4351 } 4352 4353 @override 4354 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 4355 super.debugFillProperties(properties); 4356 properties.add(IntProperty('flex', flex)); 4357 } 4358} 4359 4360/// A widget that expands a child of a [Row], [Column], or [Flex] 4361/// so that the child fills the available space. 4362/// 4363/// Using an [Expanded] widget makes a child of a [Row], [Column], or [Flex] 4364/// expand to fill the available space along the main axis (e.g., horizontally for 4365/// a [Row] or vertically for a [Column]). If multiple children are expanded, 4366/// the available space is divided among them according to the [flex] factor. 4367/// 4368/// An [Expanded] widget must be a descendant of a [Row], [Column], or [Flex], 4369/// and the path from the [Expanded] widget to its enclosing [Row], [Column], or 4370/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other 4371/// kinds of widgets, like [RenderObjectWidget]s). 4372/// 4373/// {@youtube 560 315 https://www.youtube.com/watch?v=_rnZaagadyo} 4374/// 4375/// {@tool snippet --template=stateless_widget_material} 4376/// This example shows how to use an [Expanded] widget in a [Column] so that 4377/// it's middle child, a [Container] here, expands to fill the space. 4378/// 4379///  4380/// 4381/// ```dart 4382/// Widget build(BuildContext context) { 4383/// return Scaffold( 4384/// appBar: AppBar( 4385/// title: Text('Expanded Column Sample'), 4386/// ), 4387/// body: Center( 4388/// child: Column( 4389/// children: <Widget>[ 4390/// Container( 4391/// color: Colors.blue, 4392/// height: 100, 4393/// width: 100, 4394/// ), 4395/// Expanded( 4396/// child: Container( 4397/// color: Colors.amber, 4398/// width: 100, 4399/// ), 4400/// ), 4401/// Container( 4402/// color: Colors.blue, 4403/// height: 100, 4404/// width: 100, 4405/// ), 4406/// ], 4407/// ), 4408/// ), 4409/// ); 4410/// } 4411/// ``` 4412/// {@end-tool} 4413/// 4414/// {@tool snippet --template=stateless_widget_material} 4415/// This example shows how to use an [Expanded] widget in a [Row] with multiple 4416/// children expanded, utilizing the [flex] factor to prioritize available space. 4417/// 4418///  4419/// 4420/// ```dart 4421/// Widget build(BuildContext context) { 4422/// return Scaffold( 4423/// appBar: AppBar( 4424/// title: Text('Expanded Row Sample'), 4425/// ), 4426/// body: Center( 4427/// child: Row( 4428/// children: <Widget>[ 4429/// Expanded( 4430/// flex: 2, 4431/// child: Container( 4432/// color: Colors.amber, 4433/// height: 100, 4434/// ), 4435/// ), 4436/// Container( 4437/// color: Colors.blue, 4438/// height: 100, 4439/// width: 50, 4440/// ), 4441/// Expanded( 4442/// flex: 1, 4443/// child: Container( 4444/// color: Colors.amber, 4445/// height: 100, 4446/// ), 4447/// ), 4448/// ], 4449/// ), 4450/// ), 4451/// ); 4452/// } 4453/// ``` 4454/// {@end-tool} 4455/// 4456/// See also: 4457/// 4458/// * [Flexible], which does not force the child to fill the available space. 4459/// * [Spacer], a widget that takes up space proportional to it's flex value. 4460/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4461class Expanded extends Flexible { 4462 /// Creates a widget that expands a child of a [Row], [Column], or [Flex] 4463 /// so that the child fills the available space along the flex widget's 4464 /// main axis. 4465 const Expanded({ 4466 Key key, 4467 int flex = 1, 4468 @required Widget child, 4469 }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child); 4470} 4471 4472/// A widget that displays its children in multiple horizontal or vertical runs. 4473/// 4474/// A [Wrap] lays out each child and attempts to place the child adjacent to the 4475/// previous child in the main axis, given by [direction], leaving [spacing] 4476/// space in between. If there is not enough space to fit the child, [Wrap] 4477/// creates a new _run_ adjacent to the existing children in the cross axis. 4478/// 4479/// After all the children have been allocated to runs, the children within the 4480/// runs are positioned according to the [alignment] in the main axis and 4481/// according to the [crossAxisAlignment] in the cross axis. 4482/// 4483/// The runs themselves are then positioned in the cross axis according to the 4484/// [runSpacing] and [runAlignment]. 4485/// 4486/// {@youtube 560 315 https://www.youtube.com/watch?v=z5iw2SeFx2M} 4487/// 4488/// {@tool sample} 4489/// 4490/// This example renders some [Chip]s representing four contacts in a [Wrap] so 4491/// that they flow across lines as necessary. 4492/// 4493/// ```dart 4494/// Wrap( 4495/// spacing: 8.0, // gap between adjacent chips 4496/// runSpacing: 4.0, // gap between lines 4497/// children: <Widget>[ 4498/// Chip( 4499/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('AH')), 4500/// label: Text('Hamilton'), 4501/// ), 4502/// Chip( 4503/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('ML')), 4504/// label: Text('Lafayette'), 4505/// ), 4506/// Chip( 4507/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('HM')), 4508/// label: Text('Mulligan'), 4509/// ), 4510/// Chip( 4511/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('JL')), 4512/// label: Text('Laurens'), 4513/// ), 4514/// ], 4515/// ) 4516/// ``` 4517/// {@end-tool} 4518/// 4519/// See also: 4520/// 4521/// * [Row], which places children in one line, and gives control over their 4522/// alignment and spacing. 4523/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4524class Wrap extends MultiChildRenderObjectWidget { 4525 /// Creates a wrap layout. 4526 /// 4527 /// By default, the wrap layout is horizontal and both the children and the 4528 /// runs are aligned to the start. 4529 /// 4530 /// The [textDirection] argument defaults to the ambient [Directionality], if 4531 /// any. If there is no ambient directionality, and a text direction is going 4532 /// to be necessary to decide which direction to lay the children in or to 4533 /// disambiguate `start` or `end` values for the main or cross axis 4534 /// directions, the [textDirection] must not be null. 4535 Wrap({ 4536 Key key, 4537 this.direction = Axis.horizontal, 4538 this.alignment = WrapAlignment.start, 4539 this.spacing = 0.0, 4540 this.runAlignment = WrapAlignment.start, 4541 this.runSpacing = 0.0, 4542 this.crossAxisAlignment = WrapCrossAlignment.start, 4543 this.textDirection, 4544 this.verticalDirection = VerticalDirection.down, 4545 List<Widget> children = const <Widget>[], 4546 }) : super(key: key, children: children); 4547 4548 /// The direction to use as the main axis. 4549 /// 4550 /// For example, if [direction] is [Axis.horizontal], the default, the 4551 /// children are placed adjacent to one another in a horizontal run until the 4552 /// available horizontal space is consumed, at which point a subsequent 4553 /// children are placed in a new run vertically adjacent to the previous run. 4554 final Axis direction; 4555 4556 /// How the children within a run should be placed in the main axis. 4557 /// 4558 /// For example, if [alignment] is [WrapAlignment.center], the children in 4559 /// each run are grouped together in the center of their run in the main axis. 4560 /// 4561 /// Defaults to [WrapAlignment.start]. 4562 /// 4563 /// See also: 4564 /// 4565 /// * [runAlignment], which controls how the runs are placed relative to each 4566 /// other in the cross axis. 4567 /// * [crossAxisAlignment], which controls how the children within each run 4568 /// are placed relative to each other in the cross axis. 4569 final WrapAlignment alignment; 4570 4571 /// How much space to place between children in a run in the main axis. 4572 /// 4573 /// For example, if [spacing] is 10.0, the children will be spaced at least 4574 /// 10.0 logical pixels apart in the main axis. 4575 /// 4576 /// If there is additional free space in a run (e.g., because the wrap has a 4577 /// minimum size that is not filled or because some runs are longer than 4578 /// others), the additional free space will be allocated according to the 4579 /// [alignment]. 4580 /// 4581 /// Defaults to 0.0. 4582 final double spacing; 4583 4584 /// How the runs themselves should be placed in the cross axis. 4585 /// 4586 /// For example, if [runAlignment] is [WrapAlignment.center], the runs are 4587 /// grouped together in the center of the overall [Wrap] in the cross axis. 4588 /// 4589 /// Defaults to [WrapAlignment.start]. 4590 /// 4591 /// See also: 4592 /// 4593 /// * [alignment], which controls how the children within each run are placed 4594 /// relative to each other in the main axis. 4595 /// * [crossAxisAlignment], which controls how the children within each run 4596 /// are placed relative to each other in the cross axis. 4597 final WrapAlignment runAlignment; 4598 4599 /// How much space to place between the runs themselves in the cross axis. 4600 /// 4601 /// For example, if [runSpacing] is 10.0, the runs will be spaced at least 4602 /// 10.0 logical pixels apart in the cross axis. 4603 /// 4604 /// If there is additional free space in the overall [Wrap] (e.g., because 4605 /// the wrap has a minimum size that is not filled), the additional free space 4606 /// will be allocated according to the [runAlignment]. 4607 /// 4608 /// Defaults to 0.0. 4609 final double runSpacing; 4610 4611 /// How the children within a run should be aligned relative to each other in 4612 /// the cross axis. 4613 /// 4614 /// For example, if this is set to [WrapCrossAlignment.end], and the 4615 /// [direction] is [Axis.horizontal], then the children within each 4616 /// run will have their bottom edges aligned to the bottom edge of the run. 4617 /// 4618 /// Defaults to [WrapCrossAlignment.start]. 4619 /// 4620 /// See also: 4621 /// 4622 /// * [alignment], which controls how the children within each run are placed 4623 /// relative to each other in the main axis. 4624 /// * [runAlignment], which controls how the runs are placed relative to each 4625 /// other in the cross axis. 4626 final WrapCrossAlignment crossAxisAlignment; 4627 4628 /// Determines the order to lay children out horizontally and how to interpret 4629 /// `start` and `end` in the horizontal direction. 4630 /// 4631 /// Defaults to the ambient [Directionality]. 4632 /// 4633 /// If the [direction] is [Axis.horizontal], this controls order in which the 4634 /// children are positioned (left-to-right or right-to-left), and the meaning 4635 /// of the [alignment] property's [WrapAlignment.start] and 4636 /// [WrapAlignment.end] values. 4637 /// 4638 /// If the [direction] is [Axis.horizontal], and either the 4639 /// [alignment] is either [WrapAlignment.start] or [WrapAlignment.end], or 4640 /// there's more than one child, then the [textDirection] (or the ambient 4641 /// [Directionality]) must not be null. 4642 /// 4643 /// If the [direction] is [Axis.vertical], this controls the order in which 4644 /// runs are positioned, the meaning of the [runAlignment] property's 4645 /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the 4646 /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and 4647 /// [WrapCrossAlignment.end] values. 4648 /// 4649 /// If the [direction] is [Axis.vertical], and either the 4650 /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the 4651 /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or 4652 /// [WrapCrossAlignment.end], or there's more than one child, then the 4653 /// [textDirection] (or the ambient [Directionality]) must not be null. 4654 final TextDirection textDirection; 4655 4656 /// Determines the order to lay children out vertically and how to interpret 4657 /// `start` and `end` in the vertical direction. 4658 /// 4659 /// If the [direction] is [Axis.vertical], this controls which order children 4660 /// are painted in (down or up), the meaning of the [alignment] property's 4661 /// [WrapAlignment.start] and [WrapAlignment.end] values. 4662 /// 4663 /// If the [direction] is [Axis.vertical], and either the [alignment] 4664 /// is either [WrapAlignment.start] or [WrapAlignment.end], or there's 4665 /// more than one child, then the [verticalDirection] must not be null. 4666 /// 4667 /// If the [direction] is [Axis.horizontal], this controls the order in which 4668 /// runs are positioned, the meaning of the [runAlignment] property's 4669 /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the 4670 /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and 4671 /// [WrapCrossAlignment.end] values. 4672 /// 4673 /// If the [direction] is [Axis.horizontal], and either the 4674 /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the 4675 /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or 4676 /// [WrapCrossAlignment.end], or there's more than one child, then the 4677 /// [verticalDirection] must not be null. 4678 final VerticalDirection verticalDirection; 4679 4680 @override 4681 RenderWrap createRenderObject(BuildContext context) { 4682 return RenderWrap( 4683 direction: direction, 4684 alignment: alignment, 4685 spacing: spacing, 4686 runAlignment: runAlignment, 4687 runSpacing: runSpacing, 4688 crossAxisAlignment: crossAxisAlignment, 4689 textDirection: textDirection ?? Directionality.of(context), 4690 verticalDirection: verticalDirection, 4691 ); 4692 } 4693 4694 @override 4695 void updateRenderObject(BuildContext context, RenderWrap renderObject) { 4696 renderObject 4697 ..direction = direction 4698 ..alignment = alignment 4699 ..spacing = spacing 4700 ..runAlignment = runAlignment 4701 ..runSpacing = runSpacing 4702 ..crossAxisAlignment = crossAxisAlignment 4703 ..textDirection = textDirection ?? Directionality.of(context) 4704 ..verticalDirection = verticalDirection; 4705 } 4706 4707 @override 4708 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 4709 super.debugFillProperties(properties); 4710 properties.add(EnumProperty<Axis>('direction', direction)); 4711 properties.add(EnumProperty<WrapAlignment>('alignment', alignment)); 4712 properties.add(DoubleProperty('spacing', spacing)); 4713 properties.add(EnumProperty<WrapAlignment>('runAlignment', runAlignment)); 4714 properties.add(DoubleProperty('runSpacing', runSpacing)); 4715 properties.add(DoubleProperty('crossAxisAlignment', runSpacing)); 4716 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); 4717 properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down)); 4718 } 4719} 4720 4721/// A widget that sizes and positions children efficiently, according to the 4722/// logic in a [FlowDelegate]. 4723/// 4724/// Flow layouts are optimized for repositioning children using transformation 4725/// matrices. 4726/// 4727/// The flow container is sized independently from the children by the 4728/// [FlowDelegate.getSize] function of the delegate. The children are then sized 4729/// independently given the constraints from the 4730/// [FlowDelegate.getConstraintsForChild] function. 4731/// 4732/// Rather than positioning the children during layout, the children are 4733/// positioned using transformation matrices during the paint phase using the 4734/// matrices from the [FlowDelegate.paintChildren] function. The children can be 4735/// repositioned efficiently by simply repainting the flow, which happens 4736/// without the children being laid out again (contrast this with a [Stack], 4737/// which does the sizing and positioning together during layout). 4738/// 4739/// The most efficient way to trigger a repaint of the flow is to supply an 4740/// animation to the constructor of the [FlowDelegate]. The flow will listen to 4741/// this animation and repaint whenever the animation ticks, avoiding both the 4742/// build and layout phases of the pipeline. 4743/// 4744/// See also: 4745/// 4746/// * [Wrap], which provides the layout model that some other frameworks call 4747/// "flow", and is otherwise unrelated to [Flow]. 4748/// * [FlowDelegate], which controls the visual presentation of the children. 4749/// * [Stack], which arranges children relative to the edges of the container. 4750/// * [CustomSingleChildLayout], which uses a delegate to control the layout of 4751/// a single child. 4752/// * [CustomMultiChildLayout], which uses a delegate to position multiple 4753/// children. 4754/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). 4755/// 4756/// 4757/// {@animation 450 100 https://flutter.github.io/assets-for-api-docs/assets/widgets/flow_menu.mp4} 4758/// 4759/// {@tool snippet --template=freeform} 4760/// 4761/// This example uses the [Flow] widget to create a menu that opens and closes 4762/// as it is interacted with, shown above. The color of the button in the menu 4763/// changes to indicate which one has been selected. 4764/// 4765/// ```dart main 4766/// import 'package:flutter/material.dart'; 4767/// 4768/// void main() => runApp(FlowApp()); 4769/// 4770/// class FlowApp extends StatelessWidget { 4771/// @override 4772/// Widget build(BuildContext context) { 4773/// return MaterialApp( 4774/// home: Scaffold( 4775/// appBar: AppBar( 4776/// title: const Text('Flow Example'), 4777/// ), 4778/// body: FlowMenu(), 4779/// ), 4780/// ); 4781/// } 4782/// } 4783/// 4784/// class FlowMenu extends StatefulWidget { 4785/// @override 4786/// _FlowMenuState createState() => _FlowMenuState(); 4787/// } 4788/// 4789/// class _FlowMenuState extends State<FlowMenu> with SingleTickerProviderStateMixin { 4790/// AnimationController menuAnimation; 4791/// IconData lastTapped = Icons.notifications; 4792/// final List<IconData> menuItems = <IconData>[ 4793/// Icons.home, 4794/// Icons.new_releases, 4795/// Icons.notifications, 4796/// Icons.settings, 4797/// Icons.menu, 4798/// ]; 4799/// 4800/// void _updateMenu(IconData icon) { 4801/// if (icon != Icons.menu) 4802/// setState(() => lastTapped = icon); 4803/// } 4804/// 4805/// @override 4806/// void initState() { 4807/// super.initState(); 4808/// menuAnimation = AnimationController( 4809/// duration: const Duration(milliseconds: 250), 4810/// vsync: this, 4811/// ); 4812/// } 4813/// 4814/// Widget flowMenuItem(IconData icon) { 4815/// final double buttonDiameter = MediaQuery.of(context).size.width / menuItems.length; 4816/// return Padding( 4817/// padding: const EdgeInsets.symmetric(vertical: 8.0), 4818/// child: RawMaterialButton( 4819/// fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue, 4820/// splashColor: Colors.amber[100], 4821/// shape: CircleBorder(), 4822/// constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)), 4823/// onPressed: () { 4824/// _updateMenu(icon); 4825/// menuAnimation.status == AnimationStatus.completed 4826/// ? menuAnimation.reverse() 4827/// : menuAnimation.forward(); 4828/// }, 4829/// child: Icon( 4830/// icon, 4831/// color: Colors.white, 4832/// size: 45.0, 4833/// ), 4834/// ), 4835/// ); 4836/// } 4837/// 4838/// @override 4839/// Widget build(BuildContext context) { 4840/// return Container( 4841/// child: Flow( 4842/// delegate: FlowMenuDelegate(menuAnimation: menuAnimation), 4843/// children: menuItems.map<Widget>((IconData icon) => flowMenuItem(icon)).toList(), 4844/// ), 4845/// ); 4846/// } 4847/// } 4848/// 4849/// class FlowMenuDelegate extends FlowDelegate { 4850/// FlowMenuDelegate({this.menuAnimation}) : super(repaint: menuAnimation); 4851/// 4852/// final Animation<double> menuAnimation; 4853/// 4854/// @override 4855/// bool shouldRepaint(FlowMenuDelegate oldDelegate) { 4856/// return menuAnimation != oldDelegate.menuAnimation; 4857/// } 4858/// 4859/// @override 4860/// void paintChildren(FlowPaintingContext context) { 4861/// double dx = 0.0; 4862/// for (int i = 0; i < context.childCount; ++i) { 4863/// dx = context.getChildSize(i).width * i; 4864/// context.paintChild( 4865/// i, 4866/// transform: Matrix4.translationValues( 4867/// dx * menuAnimation.value, 4868/// 0, 4869/// 0, 4870/// ), 4871/// ); 4872/// } 4873/// } 4874/// } 4875/// ``` 4876/// {@end-tool} 4877/// 4878class Flow extends MultiChildRenderObjectWidget { 4879 /// Creates a flow layout. 4880 /// 4881 /// Wraps each of the given children in a [RepaintBoundary] to avoid 4882 /// repainting the children when the flow repaints. 4883 /// 4884 /// The [delegate] argument must not be null. 4885 Flow({ 4886 Key key, 4887 @required this.delegate, 4888 List<Widget> children = const <Widget>[], 4889 }) : assert(delegate != null), 4890 super(key: key, children: RepaintBoundary.wrapAll(children)); 4891 // https://github.com/dart-lang/sdk/issues/29277 4892 4893 /// Creates a flow layout. 4894 /// 4895 /// Does not wrap the given children in repaint boundaries, unlike the default 4896 /// constructor. Useful when the child is trivial to paint or already contains 4897 /// a repaint boundary. 4898 /// 4899 /// The [delegate] argument must not be null. 4900 Flow.unwrapped({ 4901 Key key, 4902 @required this.delegate, 4903 List<Widget> children = const <Widget>[], 4904 }) : assert(delegate != null), 4905 super(key: key, children: children); 4906 4907 /// The delegate that controls the transformation matrices of the children. 4908 final FlowDelegate delegate; 4909 4910 @override 4911 RenderFlow createRenderObject(BuildContext context) => RenderFlow(delegate: delegate); 4912 4913 @override 4914 void updateRenderObject(BuildContext context, RenderFlow renderObject) { 4915 renderObject 4916 ..delegate = delegate; 4917 } 4918} 4919 4920/// A paragraph of rich text. 4921/// 4922/// The [RichText] widget displays text that uses multiple different styles. The 4923/// text to display is described using a tree of [TextSpan] objects, each of 4924/// which has an associated style that is used for that subtree. The text might 4925/// break across multiple lines or might all be displayed on the same line 4926/// depending on the layout constraints. 4927/// 4928/// Text displayed in a [RichText] widget must be explicitly styled. When 4929/// picking which style to use, consider using [DefaultTextStyle.of] the current 4930/// [BuildContext] to provide defaults. For more details on how to style text in 4931/// a [RichText] widget, see the documentation for [TextStyle]. 4932/// 4933/// Consider using the [Text] widget to integrate with the [DefaultTextStyle] 4934/// automatically. When all the text uses the same style, the default constructor 4935/// is less verbose. The [Text.rich] constructor allows you to style multiple 4936/// spans with the default text style while still allowing specified styles per 4937/// span. 4938/// 4939/// {@tool sample} 4940/// 4941/// ```dart 4942/// RichText( 4943/// text: TextSpan( 4944/// text: 'Hello ', 4945/// style: DefaultTextStyle.of(context).style, 4946/// children: <TextSpan>[ 4947/// TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)), 4948/// TextSpan(text: ' world!'), 4949/// ], 4950/// ), 4951/// ) 4952/// ``` 4953/// {@end-tool} 4954/// 4955/// See also: 4956/// 4957/// * [TextStyle], which discusses how to style text. 4958/// * [TextSpan], which is used to describe the text in a paragraph. 4959/// * [Text], which automatically applies the ambient styles described by a 4960/// [DefaultTextStyle] to a single string. 4961/// * [Text.rich], a const text widget that provides similar functionality 4962/// as [RichText]. [Text.rich] will inherit [TextStyle] from [DefaultTextStyle]. 4963class RichText extends MultiChildRenderObjectWidget { 4964 /// Creates a paragraph of rich text. 4965 /// 4966 /// The [text], [textAlign], [softWrap], [overflow], and [textScaleFactor] 4967 /// arguments must not be null. 4968 /// 4969 /// The [maxLines] property may be null (and indeed defaults to null), but if 4970 /// it is not null, it must be greater than zero. 4971 /// 4972 /// The [textDirection], if null, defaults to the ambient [Directionality], 4973 /// which in that case must not be null. 4974 RichText({ 4975 Key key, 4976 @required this.text, 4977 this.textAlign = TextAlign.start, 4978 this.textDirection, 4979 this.softWrap = true, 4980 this.overflow = TextOverflow.clip, 4981 this.textScaleFactor = 1.0, 4982 this.maxLines, 4983 this.locale, 4984 this.strutStyle, 4985 this.textWidthBasis = TextWidthBasis.parent, 4986 }) : assert(text != null), 4987 assert(textAlign != null), 4988 assert(softWrap != null), 4989 assert(overflow != null), 4990 assert(textScaleFactor != null), 4991 assert(maxLines == null || maxLines > 0), 4992 assert(textWidthBasis != null), 4993 super(key: key, children: _extractChildren(text)); 4994 4995 // Traverses the InlineSpan tree and depth-first collects the list of 4996 // child widgets that are created in WidgetSpans. 4997 static List<Widget> _extractChildren(InlineSpan span) { 4998 final List<Widget> result = <Widget>[]; 4999 span.visitChildren((InlineSpan span) { 5000 if (span is WidgetSpan) { 5001 result.add(span.child); 5002 } 5003 return true; 5004 }); 5005 return result; 5006 } 5007 5008 /// The text to display in this widget. 5009 final InlineSpan text; 5010 5011 /// How the text should be aligned horizontally. 5012 final TextAlign textAlign; 5013 5014 /// The directionality of the text. 5015 /// 5016 /// This decides how [textAlign] values like [TextAlign.start] and 5017 /// [TextAlign.end] are interpreted. 5018 /// 5019 /// This is also used to disambiguate how to render bidirectional text. For 5020 /// example, if the [text] is an English phrase followed by a Hebrew phrase, 5021 /// in a [TextDirection.ltr] context the English phrase will be on the left 5022 /// and the Hebrew phrase to its right, while in a [TextDirection.rtl] 5023 /// context, the English phrase will be on the right and the Hebrew phrase on 5024 /// its left. 5025 /// 5026 /// Defaults to the ambient [Directionality], if any. If there is no ambient 5027 /// [Directionality], then this must not be null. 5028 final TextDirection textDirection; 5029 5030 /// Whether the text should break at soft line breaks. 5031 /// 5032 /// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. 5033 final bool softWrap; 5034 5035 /// How visual overflow should be handled. 5036 final TextOverflow overflow; 5037 5038 /// The number of font pixels for each logical pixel. 5039 /// 5040 /// For example, if the text scale factor is 1.5, text will be 50% larger than 5041 /// the specified font size. 5042 final double textScaleFactor; 5043 5044 /// An optional maximum number of lines for the text to span, wrapping if necessary. 5045 /// If the text exceeds the given number of lines, it will be truncated according 5046 /// to [overflow]. 5047 /// 5048 /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the 5049 /// edge of the box. 5050 final int maxLines; 5051 5052 /// Used to select a font when the same Unicode character can 5053 /// be rendered differently, depending on the locale. 5054 /// 5055 /// It's rarely necessary to set this property. By default its value 5056 /// is inherited from the enclosing app with `Localizations.localeOf(context)`. 5057 /// 5058 /// See [RenderParagraph.locale] for more information. 5059 final Locale locale; 5060 5061 /// {@macro flutter.painting.textPainter.strutStyle} 5062 final StrutStyle strutStyle; 5063 5064 /// {@macro flutter.widgets.text.DefaultTextStyle.textWidthBasis} 5065 final TextWidthBasis textWidthBasis; 5066 5067 @override 5068 RenderParagraph createRenderObject(BuildContext context) { 5069 assert(textDirection != null || debugCheckHasDirectionality(context)); 5070 return RenderParagraph(text, 5071 textAlign: textAlign, 5072 textDirection: textDirection ?? Directionality.of(context), 5073 softWrap: softWrap, 5074 overflow: overflow, 5075 textScaleFactor: textScaleFactor, 5076 maxLines: maxLines, 5077 strutStyle: strutStyle, 5078 textWidthBasis: textWidthBasis, 5079 locale: locale ?? Localizations.localeOf(context, nullOk: true), 5080 ); 5081 } 5082 5083 @override 5084 void updateRenderObject(BuildContext context, RenderParagraph renderObject) { 5085 assert(textDirection != null || debugCheckHasDirectionality(context)); 5086 renderObject 5087 ..text = text 5088 ..textAlign = textAlign 5089 ..textDirection = textDirection ?? Directionality.of(context) 5090 ..softWrap = softWrap 5091 ..overflow = overflow 5092 ..textScaleFactor = textScaleFactor 5093 ..maxLines = maxLines 5094 ..strutStyle = strutStyle 5095 ..textWidthBasis = textWidthBasis 5096 ..locale = locale ?? Localizations.localeOf(context, nullOk: true); 5097 } 5098 5099 @override 5100 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 5101 super.debugFillProperties(properties); 5102 properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start)); 5103 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); 5104 properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true)); 5105 properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: TextOverflow.clip)); 5106 properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: 1.0)); 5107 properties.add(IntProperty('maxLines', maxLines, ifNull: 'unlimited')); 5108 properties.add(EnumProperty<TextWidthBasis>('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent)); 5109 properties.add(StringProperty('text', text.toPlainText())); 5110 } 5111} 5112 5113/// A widget that displays a [dart:ui.Image] directly. 5114/// 5115/// The image is painted using [paintImage], which describes the meanings of the 5116/// various fields on this class in more detail. 5117/// 5118/// This widget is rarely used directly. Instead, consider using [Image]. 5119class RawImage extends LeafRenderObjectWidget { 5120 /// Creates a widget that displays an image. 5121 /// 5122 /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments must 5123 /// not be null. 5124 const RawImage({ 5125 Key key, 5126 this.image, 5127 this.width, 5128 this.height, 5129 this.scale = 1.0, 5130 this.color, 5131 this.colorBlendMode, 5132 this.fit, 5133 this.alignment = Alignment.center, 5134 this.repeat = ImageRepeat.noRepeat, 5135 this.centerSlice, 5136 this.matchTextDirection = false, 5137 this.invertColors = false, 5138 this.filterQuality = FilterQuality.low, 5139 }) : assert(scale != null), 5140 assert(alignment != null), 5141 assert(repeat != null), 5142 assert(matchTextDirection != null), 5143 super(key: key); 5144 5145 /// The image to display. 5146 final ui.Image image; 5147 5148 /// If non-null, require the image to have this width. 5149 /// 5150 /// If null, the image will pick a size that best preserves its intrinsic 5151 /// aspect ratio. 5152 final double width; 5153 5154 /// If non-null, require the image to have this height. 5155 /// 5156 /// If null, the image will pick a size that best preserves its intrinsic 5157 /// aspect ratio. 5158 final double height; 5159 5160 /// Specifies the image's scale. 5161 /// 5162 /// Used when determining the best display size for the image. 5163 final double scale; 5164 5165 /// If non-null, this color is blended with each image pixel using [colorBlendMode]. 5166 final Color color; 5167 5168 /// Used to set the filterQuality of the image 5169 /// Use the "low" quality setting to scale the image, which corresponds to 5170 /// bilinear interpolation, rather than the default "none" which corresponds 5171 /// to nearest-neighbor. 5172 final FilterQuality filterQuality; 5173 5174 /// Used to combine [color] with this image. 5175 /// 5176 /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is 5177 /// the source and this image is the destination. 5178 /// 5179 /// See also: 5180 /// 5181 /// * [BlendMode], which includes an illustration of the effect of each blend mode. 5182 final BlendMode colorBlendMode; 5183 5184 /// How to inscribe the image into the space allocated during layout. 5185 /// 5186 /// The default varies based on the other fields. See the discussion at 5187 /// [paintImage]. 5188 final BoxFit fit; 5189 5190 /// How to align the image within its bounds. 5191 /// 5192 /// The alignment aligns the given position in the image to the given position 5193 /// in the layout bounds. For example, an [Alignment] alignment of (-1.0, 5194 /// -1.0) aligns the image to the top-left corner of its layout bounds, while a 5195 /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the 5196 /// image with the bottom right corner of its layout bounds. Similarly, an 5197 /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the 5198 /// middle of the bottom edge of its layout bounds. 5199 /// 5200 /// To display a subpart of an image, consider using a [CustomPainter] and 5201 /// [Canvas.drawImageRect]. 5202 /// 5203 /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a 5204 /// [AlignmentDirectional]), then an ambient [Directionality] widget 5205 /// must be in scope. 5206 /// 5207 /// Defaults to [Alignment.center]. 5208 /// 5209 /// See also: 5210 /// 5211 /// * [Alignment], a class with convenient constants typically used to 5212 /// specify an [AlignmentGeometry]. 5213 /// * [AlignmentDirectional], like [Alignment] for specifying alignments 5214 /// relative to text direction. 5215 final AlignmentGeometry alignment; 5216 5217 /// How to paint any portions of the layout bounds not covered by the image. 5218 final ImageRepeat repeat; 5219 5220 /// The center slice for a nine-patch image. 5221 /// 5222 /// The region of the image inside the center slice will be stretched both 5223 /// horizontally and vertically to fit the image into its destination. The 5224 /// region of the image above and below the center slice will be stretched 5225 /// only horizontally and the region of the image to the left and right of 5226 /// the center slice will be stretched only vertically. 5227 final Rect centerSlice; 5228 5229 /// Whether to paint the image in the direction of the [TextDirection]. 5230 /// 5231 /// If this is true, then in [TextDirection.ltr] contexts, the image will be 5232 /// drawn with its origin in the top left (the "normal" painting direction for 5233 /// images); and in [TextDirection.rtl] contexts, the image will be drawn with 5234 /// a scaling factor of -1 in the horizontal direction so that the origin is 5235 /// in the top right. 5236 /// 5237 /// This is occasionally used with images in right-to-left environments, for 5238 /// images that were designed for left-to-right locales. Be careful, when 5239 /// using this, to not flip images with integral shadows, text, or other 5240 /// effects that will look incorrect when flipped. 5241 /// 5242 /// If this is true, there must be an ambient [Directionality] widget in 5243 /// scope. 5244 final bool matchTextDirection; 5245 5246 /// Whether the colors of the image are inverted when drawn. 5247 /// 5248 /// inverting the colors of an image applies a new color filter to the paint. 5249 /// If there is another specified color filter, the invert will be applied 5250 /// after it. This is primarily used for implementing smart invert on iOS. 5251 /// 5252 /// See also: 5253 /// 5254 /// * [Paint.invertColors], for the dart:ui implementation. 5255 final bool invertColors; 5256 5257 @override 5258 RenderImage createRenderObject(BuildContext context) { 5259 assert((!matchTextDirection && alignment is Alignment) || debugCheckHasDirectionality(context)); 5260 return RenderImage( 5261 image: image, 5262 width: width, 5263 height: height, 5264 scale: scale, 5265 color: color, 5266 colorBlendMode: colorBlendMode, 5267 fit: fit, 5268 alignment: alignment, 5269 repeat: repeat, 5270 centerSlice: centerSlice, 5271 matchTextDirection: matchTextDirection, 5272 textDirection: matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null, 5273 invertColors: invertColors, 5274 filterQuality: filterQuality, 5275 ); 5276 } 5277 5278 @override 5279 void updateRenderObject(BuildContext context, RenderImage renderObject) { 5280 renderObject 5281 ..image = image 5282 ..width = width 5283 ..height = height 5284 ..scale = scale 5285 ..color = color 5286 ..colorBlendMode = colorBlendMode 5287 ..alignment = alignment 5288 ..fit = fit 5289 ..repeat = repeat 5290 ..centerSlice = centerSlice 5291 ..matchTextDirection = matchTextDirection 5292 ..textDirection = matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null 5293 ..invertColors = invertColors 5294 ..filterQuality = filterQuality; 5295 } 5296 5297 @override 5298 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 5299 super.debugFillProperties(properties); 5300 properties.add(DiagnosticsProperty<ui.Image>('image', image)); 5301 properties.add(DoubleProperty('width', width, defaultValue: null)); 5302 properties.add(DoubleProperty('height', height, defaultValue: null)); 5303 properties.add(DoubleProperty('scale', scale, defaultValue: 1.0)); 5304 properties.add(ColorProperty('color', color, defaultValue: null)); 5305 properties.add(EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null)); 5306 properties.add(EnumProperty<BoxFit>('fit', fit, defaultValue: null)); 5307 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null)); 5308 properties.add(EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat)); 5309 properties.add(DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null)); 5310 properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction')); 5311 properties.add(DiagnosticsProperty<bool>('invertColors', invertColors)); 5312 properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality)); 5313 } 5314} 5315 5316/// A widget that determines the default asset bundle for its descendants. 5317/// 5318/// For example, used by [Image] to determine which bundle to use for 5319/// [AssetImage]s if no bundle is specified explicitly. 5320/// 5321/// {@tool sample} 5322/// 5323/// This can be used in tests to override what the current asset bundle is, thus 5324/// allowing specific resources to be injected into the widget under test. 5325/// 5326/// For example, a test could create a test asset bundle like this: 5327/// 5328/// ```dart 5329/// class TestAssetBundle extends CachingAssetBundle { 5330/// @override 5331/// Future<ByteData> load(String key) async { 5332/// if (key == 'resources/test') 5333/// return ByteData.view(Uint8List.fromList(utf8.encode('Hello World!')).buffer); 5334/// return null; 5335/// } 5336/// } 5337/// ``` 5338/// {@end-tool} 5339/// {@tool sample} 5340/// 5341/// ...then wrap the widget under test with a [DefaultAssetBundle] using this 5342/// bundle implementation: 5343/// 5344/// ```dart 5345/// await tester.pumpWidget( 5346/// MaterialApp( 5347/// home: DefaultAssetBundle( 5348/// bundle: TestAssetBundle(), 5349/// child: TestWidget(), 5350/// ), 5351/// ), 5352/// ); 5353/// ``` 5354/// {@end-tool} 5355/// 5356/// Assuming that `TestWidget` uses [DefaultAssetBundle.of] to obtain its 5357/// [AssetBundle], it will now see the [TestAssetBundle]'s "Hello World!" data 5358/// when requesting the "resources/test" asset. 5359/// 5360/// See also: 5361/// 5362/// * [AssetBundle], the interface for asset bundles. 5363/// * [rootBundle], the default default asset bundle. 5364class DefaultAssetBundle extends InheritedWidget { 5365 /// Creates a widget that determines the default asset bundle for its descendants. 5366 /// 5367 /// The [bundle] and [child] arguments must not be null. 5368 const DefaultAssetBundle({ 5369 Key key, 5370 @required this.bundle, 5371 @required Widget child, 5372 }) : assert(bundle != null), 5373 assert(child != null), 5374 super(key: key, child: child); 5375 5376 /// The bundle to use as a default. 5377 final AssetBundle bundle; 5378 5379 /// The bundle from the closest instance of this class that encloses 5380 /// the given context. 5381 /// 5382 /// If there is no [DefaultAssetBundle] ancestor widget in the tree 5383 /// at the given context, then this will return the [rootBundle]. 5384 /// 5385 /// Typical usage is as follows: 5386 /// 5387 /// ```dart 5388 /// AssetBundle bundle = DefaultAssetBundle.of(context); 5389 /// ``` 5390 static AssetBundle of(BuildContext context) { 5391 final DefaultAssetBundle result = context.inheritFromWidgetOfExactType(DefaultAssetBundle); 5392 return result?.bundle ?? rootBundle; 5393 } 5394 5395 @override 5396 bool updateShouldNotify(DefaultAssetBundle oldWidget) => bundle != oldWidget.bundle; 5397} 5398 5399/// An adapter for placing a specific [RenderBox] in the widget tree. 5400/// 5401/// A given render object can be placed at most once in the widget tree. This 5402/// widget enforces that restriction by keying itself using a [GlobalObjectKey] 5403/// for the given render object. 5404class WidgetToRenderBoxAdapter extends LeafRenderObjectWidget { 5405 /// Creates an adapter for placing a specific [RenderBox] in the widget tree. 5406 /// 5407 /// The [renderBox] argument must not be null. 5408 WidgetToRenderBoxAdapter({ 5409 @required this.renderBox, 5410 this.onBuild, 5411 }) : assert(renderBox != null), 5412 // WidgetToRenderBoxAdapter objects are keyed to their render box. This 5413 // prevents the widget being used in the widget hierarchy in two different 5414 // places, which would cause the RenderBox to get inserted in multiple 5415 // places in the RenderObject tree. 5416 super(key: GlobalObjectKey(renderBox)); 5417 5418 /// The render box to place in the widget tree. 5419 final RenderBox renderBox; 5420 5421 /// Called when it is safe to update the render box and its descendants. If 5422 /// you update the RenderObject subtree under this widget outside of 5423 /// invocations of this callback, features like hit-testing will fail as the 5424 /// tree will be dirty. 5425 final VoidCallback onBuild; 5426 5427 @override 5428 RenderBox createRenderObject(BuildContext context) => renderBox; 5429 5430 @override 5431 void updateRenderObject(BuildContext context, RenderBox renderObject) { 5432 if (onBuild != null) 5433 onBuild(); 5434 } 5435} 5436 5437 5438// EVENT HANDLING 5439 5440/// A widget that calls callbacks in response to common pointer events. 5441/// 5442/// It listens to events that can construct gestures, such as when the 5443/// pointer is pressed, moved, then released or canceled. 5444/// 5445/// It does not listen to events that are exclusive to mouse, such as when the 5446/// mouse enters, exits or hovers a region without pressing any buttons. For 5447/// these events, use [MouseRegion]. 5448/// 5449/// Rather than listening for raw pointer events, consider listening for 5450/// higher-level gestures using [GestureDetector]. 5451/// 5452/// ## Layout behavior 5453/// 5454/// _See [BoxConstraints] for an introduction to box layout models._ 5455/// 5456/// If it has a child, this widget defers to the child for sizing behavior. If 5457/// it does not have a child, it grows to fit the parent instead. 5458/// 5459/// {@tool snippet --template=stateful_widget_scaffold} 5460/// This example makes a [Container] react to being touched, showing a count of 5461/// the number of pointer downs and ups. 5462/// 5463/// ```dart imports 5464/// import 'package:flutter/widgets.dart'; 5465/// ``` 5466/// 5467/// ```dart 5468/// int _downCounter = 0; 5469/// int _upCounter = 0; 5470/// double x = 0.0; 5471/// double y = 0.0; 5472/// 5473/// void _incrementDown(PointerEvent details) { 5474/// _updateLocation(details); 5475/// setState(() { 5476/// _downCounter++; 5477/// }); 5478/// } 5479/// void _incrementUp(PointerEvent details) { 5480/// _updateLocation(details); 5481/// setState(() { 5482/// _upCounter++; 5483/// }); 5484/// } 5485/// void _updateLocation(PointerEvent details) { 5486/// setState(() { 5487/// x = details.position.dx; 5488/// y = details.position.dy; 5489/// }); 5490/// } 5491/// 5492/// @override 5493/// Widget build(BuildContext context) { 5494/// return Center( 5495/// child: ConstrainedBox( 5496/// constraints: new BoxConstraints.tight(Size(300.0, 200.0)), 5497/// child: Listener( 5498/// onPointerDown: _incrementDown, 5499/// onPointerMove: _updateLocation, 5500/// onPointerUp: _incrementUp, 5501/// child: Container( 5502/// color: Colors.lightBlueAccent, 5503/// child: Column( 5504/// mainAxisAlignment: MainAxisAlignment.center, 5505/// children: <Widget>[ 5506/// Text('You have pressed or released in this area this many times:'), 5507/// Text( 5508/// '$_downCounter presses\n$_upCounter releases', 5509/// style: Theme.of(context).textTheme.display1, 5510/// ), 5511/// Text( 5512/// 'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})', 5513/// ), 5514/// ], 5515/// ), 5516/// ), 5517/// ), 5518/// ), 5519/// ); 5520/// } 5521/// ``` 5522/// {@end-tool} 5523class Listener extends StatelessWidget { 5524 /// Creates a widget that forwards point events to callbacks. 5525 /// 5526 /// The [behavior] argument defaults to [HitTestBehavior.deferToChild]. 5527 const Listener({ 5528 Key key, 5529 this.onPointerDown, 5530 this.onPointerMove, 5531 // We have to ignore the lint rule here in order to use deprecated 5532 // parameters and keep backward compatibility. 5533 // TODO(tongmu): After it goes stable, remove these 3 parameters from Listener 5534 // and Listener should no longer need an intermediate class _PointerListener. 5535 // https://github.com/flutter/flutter/issues/36085 5536 @Deprecated('Use MouseRegion.onEnter instead') 5537 this.onPointerEnter, // ignore: deprecated_member_use_from_same_package 5538 @Deprecated('Use MouseRegion.onExit instead') 5539 this.onPointerExit, // ignore: deprecated_member_use_from_same_package 5540 @Deprecated('Use MouseRegion.onHover instead') 5541 this.onPointerHover, // ignore: deprecated_member_use_from_same_package 5542 this.onPointerUp, 5543 this.onPointerCancel, 5544 this.onPointerSignal, 5545 this.behavior = HitTestBehavior.deferToChild, 5546 Widget child, 5547 }) : assert(behavior != null), 5548 _child = child, 5549 super(key: key); 5550 5551 /// Called when a pointer comes into contact with the screen (for touch 5552 /// pointers), or has its button pressed (for mouse pointers) at this widget's 5553 /// location. 5554 final PointerDownEventListener onPointerDown; 5555 5556 /// Called when a pointer that triggered an [onPointerDown] changes position. 5557 final PointerMoveEventListener onPointerMove; 5558 5559 /// Called when a pointer enters the region for this widget. 5560 /// 5561 /// This is only fired for pointers which report their location when not down 5562 /// (e.g. mouse pointers, but not most touch pointers). 5563 /// 5564 /// If this is a mouse pointer, this will fire when the mouse pointer enters 5565 /// the region defined by this widget, or when the widget appears under the 5566 /// pointer. 5567 final PointerEnterEventListener onPointerEnter; 5568 5569 /// Called when a pointer that has not triggered an [onPointerDown] changes 5570 /// position. 5571 /// 5572 /// This is only fired for pointers which report their location when not down 5573 /// (e.g. mouse pointers, but not most touch pointers). 5574 final PointerHoverEventListener onPointerHover; 5575 5576 /// Called when a pointer leaves the region for this widget. 5577 /// 5578 /// This is only fired for pointers which report their location when not down 5579 /// (e.g. mouse pointers, but not most touch pointers). 5580 /// 5581 /// If this is a mouse pointer, this will fire when the mouse pointer leaves 5582 /// the region defined by this widget, or when the widget disappears from 5583 /// under the pointer. 5584 final PointerExitEventListener onPointerExit; 5585 5586 /// Called when a pointer that triggered an [onPointerDown] is no longer in 5587 /// contact with the screen. 5588 final PointerUpEventListener onPointerUp; 5589 5590 /// Called when the input from a pointer that triggered an [onPointerDown] is 5591 /// no longer directed towards this receiver. 5592 final PointerCancelEventListener onPointerCancel; 5593 5594 /// Called when a pointer signal occurs over this object. 5595 final PointerSignalEventListener onPointerSignal; 5596 5597 /// How to behave during hit testing. 5598 final HitTestBehavior behavior; 5599 5600 // The widget listened to by the listener. 5601 // 5602 // The reason why we don't expose it is that once the deprecated methods are 5603 // removed, Listener will no longer need to store the child, but will pass 5604 // the child to `super` instead. 5605 final Widget _child; 5606 5607 @override 5608 Widget build(BuildContext context) { 5609 Widget result = _child; 5610 if (onPointerEnter != null || 5611 onPointerExit != null || 5612 onPointerHover != null) { 5613 result = MouseRegion( 5614 onEnter: onPointerEnter, 5615 onExit: onPointerExit, 5616 onHover: onPointerHover, 5617 child: result, 5618 ); 5619 } 5620 result = _PointerListener( 5621 onPointerDown: onPointerDown, 5622 onPointerUp: onPointerUp, 5623 onPointerMove: onPointerMove, 5624 onPointerCancel: onPointerCancel, 5625 onPointerSignal: onPointerSignal, 5626 behavior: behavior, 5627 child: result, 5628 ); 5629 return result; 5630 } 5631} 5632 5633class _PointerListener extends SingleChildRenderObjectWidget { 5634 const _PointerListener({ 5635 Key key, 5636 this.onPointerDown, 5637 this.onPointerMove, 5638 this.onPointerUp, 5639 this.onPointerCancel, 5640 this.onPointerSignal, 5641 this.behavior = HitTestBehavior.deferToChild, 5642 Widget child, 5643 }) : assert(behavior != null), 5644 super(key: key, child: child); 5645 5646 final PointerDownEventListener onPointerDown; 5647 final PointerMoveEventListener onPointerMove; 5648 final PointerUpEventListener onPointerUp; 5649 final PointerCancelEventListener onPointerCancel; 5650 final PointerSignalEventListener onPointerSignal; 5651 final HitTestBehavior behavior; 5652 5653 @override 5654 RenderPointerListener createRenderObject(BuildContext context) { 5655 return RenderPointerListener( 5656 onPointerDown: onPointerDown, 5657 onPointerMove: onPointerMove, 5658 onPointerUp: onPointerUp, 5659 onPointerCancel: onPointerCancel, 5660 onPointerSignal: onPointerSignal, 5661 behavior: behavior, 5662 ); 5663 } 5664 5665 @override 5666 void updateRenderObject(BuildContext context, RenderPointerListener renderObject) { 5667 renderObject 5668 ..onPointerDown = onPointerDown 5669 ..onPointerMove = onPointerMove 5670 ..onPointerUp = onPointerUp 5671 ..onPointerCancel = onPointerCancel 5672 ..onPointerSignal = onPointerSignal 5673 ..behavior = behavior; 5674 } 5675 5676 @override 5677 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 5678 super.debugFillProperties(properties); 5679 final List<String> listeners = <String>[]; 5680 if (onPointerDown != null) 5681 listeners.add('down'); 5682 if (onPointerMove != null) 5683 listeners.add('move'); 5684 if (onPointerUp != null) 5685 listeners.add('up'); 5686 if (onPointerCancel != null) 5687 listeners.add('cancel'); 5688 if (onPointerSignal != null) 5689 listeners.add('signal'); 5690 properties.add(IterableProperty<String>('listeners', listeners, ifEmpty: '<none>')); 5691 properties.add(EnumProperty<HitTestBehavior>('behavior', behavior)); 5692 } 5693} 5694 5695/// A widget that tracks the movement of mice, even when no button is pressed. 5696/// 5697/// It does not listen to events that can construct gestures, such as when the 5698/// pointer is pressed, moved, then released or canceled. For these events, 5699/// use [Listener], or more preferably, [GestureDetector]. 5700/// 5701/// ## Layout behavior 5702/// 5703/// _See [BoxConstraints] for an introduction to box layout models._ 5704/// 5705/// If it has a child, this widget defers to the child for sizing behavior. If 5706/// it does not have a child, it grows to fit the parent instead. 5707/// 5708/// {@tool snippet --template=stateful_widget_scaffold} 5709/// This example makes a [Container] react to being entered by a mouse 5710/// pointer, showing a count of the number of entries and exits. 5711/// 5712/// ```dart imports 5713/// import 'package:flutter/widgets.dart'; 5714/// ``` 5715/// 5716/// ```dart 5717/// int _enterCounter = 0; 5718/// int _exitCounter = 0; 5719/// double x = 0.0; 5720/// double y = 0.0; 5721/// 5722/// void _incrementEnter(PointerEvent details) { 5723/// setState(() { 5724/// _enterCounter++; 5725/// }); 5726/// } 5727/// void _incrementExit(PointerEvent details) { 5728/// setState(() { 5729/// _exitCounter++; 5730/// }); 5731/// } 5732/// void _updateLocation(PointerEvent details) { 5733/// setState(() { 5734/// x = details.position.dx; 5735/// y = details.position.dy; 5736/// }); 5737/// } 5738/// 5739/// @override 5740/// Widget build(BuildContext context) { 5741/// return Center( 5742/// child: ConstrainedBox( 5743/// constraints: new BoxConstraints.tight(Size(300.0, 200.0)), 5744/// child: MouseRegion( 5745/// onEnter: _incrementEnter, 5746/// onHover: _updateLocation, 5747/// onExit: _incrementExit, 5748/// child: Container( 5749/// color: Colors.lightBlueAccent, 5750/// child: Column( 5751/// mainAxisAlignment: MainAxisAlignment.center, 5752/// children: <Widget>[ 5753/// Text('You have entered or exited this box this many times:'), 5754/// Text( 5755/// '$_enterCounter Entries\n$_exitCounter Exits', 5756/// style: Theme.of(context).textTheme.display1, 5757/// ), 5758/// Text( 5759/// 'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})', 5760/// ), 5761/// ], 5762/// ), 5763/// ), 5764/// ), 5765/// ), 5766/// ); 5767/// } 5768/// ``` 5769/// {@end-tool} 5770/// 5771/// See also: 5772/// 5773/// * [Listener], a similar widget that tracks pointer events when the pointer 5774/// have buttons pressed. 5775class MouseRegion extends SingleChildRenderObjectWidget { 5776 /// Creates a widget that forwards mouse events to callbacks. 5777 const MouseRegion({ 5778 Key key, 5779 this.onEnter, 5780 this.onExit, 5781 this.onHover, 5782 Widget child, 5783 }) : super(key: key, child: child); 5784 5785 /// Called when a mouse pointer (with or without buttons pressed) enters the 5786 /// region defined by this widget, or when the widget appears under the 5787 /// pointer. 5788 final PointerEnterEventListener onEnter; 5789 5790 /// Called when a mouse pointer (with or without buttons pressed) changes 5791 /// position, and the new position is within the region defined by this widget. 5792 final PointerHoverEventListener onHover; 5793 5794 /// Called when a mouse pointer (with or without buttons pressed) leaves the 5795 /// region defined by this widget, or when the widget disappears from under 5796 /// the pointer. 5797 final PointerExitEventListener onExit; 5798 5799 @override 5800 _ListenerElement createElement() => _ListenerElement(this); 5801 5802 @override 5803 RenderMouseRegion createRenderObject(BuildContext context) { 5804 return RenderMouseRegion( 5805 onEnter: onEnter, 5806 onHover: onHover, 5807 onExit: onExit, 5808 ); 5809 } 5810 5811 @override 5812 void updateRenderObject(BuildContext context, RenderMouseRegion renderObject) { 5813 renderObject 5814 ..onEnter = onEnter 5815 ..onHover = onHover 5816 ..onExit = onExit; 5817 } 5818 5819 @override 5820 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 5821 super.debugFillProperties(properties); 5822 final List<String> listeners = <String>[]; 5823 if (onEnter != null) 5824 listeners.add('enter'); 5825 if (onExit != null) 5826 listeners.add('exit'); 5827 if (onHover != null) 5828 listeners.add('hover'); 5829 properties.add(IterableProperty<String>('listeners', listeners, ifEmpty: '<none>')); 5830 } 5831} 5832 5833class _ListenerElement extends SingleChildRenderObjectElement { 5834 _ListenerElement(SingleChildRenderObjectWidget widget) : super(widget); 5835 5836 @override 5837 void activate() { 5838 super.activate(); 5839 final RenderMouseRegion renderMouseListener = renderObject; 5840 renderMouseListener.postActivate(); 5841 } 5842 5843 @override 5844 void deactivate() { 5845 final RenderMouseRegion renderMouseListener = renderObject; 5846 renderMouseListener.preDeactivate(); 5847 super.deactivate(); 5848 } 5849} 5850 5851/// A widget that creates a separate display list for its child. 5852/// 5853/// This widget creates a separate display list for its child, which 5854/// can improve performance if the subtree repaints at different times than 5855/// the surrounding parts of the tree. 5856/// 5857/// This is useful since [RenderObject.paint] may be triggered even if its 5858/// associated [Widget] instances did not change or rebuild. A [RenderObject] 5859/// will repaint whenever any [RenderObject] that shares the same [Layer] is 5860/// marked as being dirty and needing paint (see [RenderObject.markNeedsPaint]), 5861/// such as when an ancestor scrolls or when an ancestor or descendant animates. 5862/// 5863/// Containing [RenderObject.paint] to parts of the render subtree that are 5864/// actually visually changing using [RepaintBoundary] explicitly or implicitly 5865/// is therefore critical to minimizing redundant work and improving the app's 5866/// performance. 5867/// 5868/// When a [RenderObject] is flagged as needing to paint via 5869/// [RenderObject.markNeedsPaint], the nearest ancestor [RenderObject] with 5870/// [RenderObject.isRepaintBoundary], up to possibly the root of the application, 5871/// is requested to repaint. That nearest ancestor's [RenderObject.paint] method 5872/// will cause _all_ of its descendant [RenderObject]s to repaint in the same 5873/// layer. 5874/// 5875/// [RepaintBoundary] is therefore used, both while propagating the 5876/// `markNeedsPaint` flag up the render tree and while traversing down the 5877/// render tree via [RenderObject.paintChild], to strategically contain repaints 5878/// to the render subtree that visually changed for performance. This is done 5879/// because the [RepaintBoundary] widget creates a [RenderObject] that always 5880/// has a [Layer], decoupling ancestor render objects from the descendant 5881/// render objects. 5882/// 5883/// [RepaintBoundary] has the further side-effect of possibly hinting to the 5884/// engine that it should further optimize animation performance if the render 5885/// subtree behind the [RepaintBoundary] is sufficiently complex and is static 5886/// while the surrounding tree changes frequently. In those cases, the engine 5887/// may choose to pay a one time cost of rasterizing and caching the pixel 5888/// values of the subtree for faster future GPU re-rendering speed. 5889/// 5890/// Several framework widgets insert [RepaintBoundary] widgets to mark natural 5891/// separation points in applications. For instance, contents in Material Design 5892/// drawers typically don't change while the drawer opens and closes, so 5893/// repaints are automatically contained to regions inside or outside the drawer 5894/// when using the [Drawer] widget during transitions. 5895/// 5896/// See also: 5897/// 5898/// * [debugRepaintRainbowEnabled], a debugging flag to help visually monitor 5899/// render tree repaints in a running app. 5900/// * [debugProfilePaintsEnabled], a debugging flag to show render tree 5901/// repaints in the observatory's timeline view. 5902class RepaintBoundary extends SingleChildRenderObjectWidget { 5903 /// Creates a widget that isolates repaints. 5904 const RepaintBoundary({ Key key, Widget child }) : super(key: key, child: child); 5905 5906 /// Wraps the given child in a [RepaintBoundary]. 5907 /// 5908 /// The key for the [RepaintBoundary] is derived either from the child's key 5909 /// (if the child has a non-null key) or from the given `childIndex`. 5910 factory RepaintBoundary.wrap(Widget child, int childIndex) { 5911 assert(child != null); 5912 final Key key = child.key != null ? ValueKey<Key>(child.key) : ValueKey<int>(childIndex); 5913 return RepaintBoundary(key: key, child: child); 5914 } 5915 5916 /// Wraps each of the given children in [RepaintBoundary]s. 5917 /// 5918 /// The key for each [RepaintBoundary] is derived either from the wrapped 5919 /// child's key (if the wrapped child has a non-null key) or from the wrapped 5920 /// child's index in the list. 5921 static List<RepaintBoundary> wrapAll(List<Widget> widgets) { 5922 final List<RepaintBoundary> result = List<RepaintBoundary>(widgets.length); 5923 for (int i = 0; i < result.length; ++i) 5924 result[i] = RepaintBoundary.wrap(widgets[i], i); 5925 return result; 5926 } 5927 5928 @override 5929 RenderRepaintBoundary createRenderObject(BuildContext context) => RenderRepaintBoundary(); 5930} 5931 5932/// A widget that is invisible during hit testing. 5933/// 5934/// When [ignoring] is true, this widget (and its subtree) is invisible 5935/// to hit testing. It still consumes space during layout and paints its child 5936/// as usual. It just cannot be the target of located events, because it returns 5937/// false from [RenderBox.hitTest]. 5938/// 5939/// When [ignoringSemantics] is true, the subtree will be invisible to 5940/// the semantics layer (and thus e.g. accessibility tools). If 5941/// [ignoringSemantics] is null, it uses the value of [ignoring]. 5942/// 5943/// See also: 5944/// 5945/// * [AbsorbPointer], which also prevents its children from receiving pointer 5946/// events but is itself visible to hit testing. 5947class IgnorePointer extends SingleChildRenderObjectWidget { 5948 /// Creates a widget that is invisible to hit testing. 5949 /// 5950 /// The [ignoring] argument must not be null. If [ignoringSemantics], this 5951 /// render object will be ignored for semantics if [ignoring] is true. 5952 const IgnorePointer({ 5953 Key key, 5954 this.ignoring = true, 5955 this.ignoringSemantics, 5956 Widget child, 5957 }) : assert(ignoring != null), 5958 super(key: key, child: child); 5959 5960 /// Whether this widget is ignored during hit testing. 5961 /// 5962 /// Regardless of whether this widget is ignored during hit testing, it will 5963 /// still consume space during layout and be visible during painting. 5964 final bool ignoring; 5965 5966 /// Whether the semantics of this widget is ignored when compiling the semantics tree. 5967 /// 5968 /// If null, defaults to value of [ignoring]. 5969 /// 5970 /// See [SemanticsNode] for additional information about the semantics tree. 5971 final bool ignoringSemantics; 5972 5973 @override 5974 RenderIgnorePointer createRenderObject(BuildContext context) { 5975 return RenderIgnorePointer( 5976 ignoring: ignoring, 5977 ignoringSemantics: ignoringSemantics, 5978 ); 5979 } 5980 5981 @override 5982 void updateRenderObject(BuildContext context, RenderIgnorePointer renderObject) { 5983 renderObject 5984 ..ignoring = ignoring 5985 ..ignoringSemantics = ignoringSemantics; 5986 } 5987 5988 @override 5989 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 5990 super.debugFillProperties(properties); 5991 properties.add(DiagnosticsProperty<bool>('ignoring', ignoring)); 5992 properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics, defaultValue: null)); 5993 } 5994} 5995 5996/// A widget that absorbs pointers during hit testing. 5997/// 5998/// When [absorbing] is true, this widget prevents its subtree from receiving 5999/// pointer events by terminating hit testing at itself. It still consumes space 6000/// during layout and paints its child as usual. It just prevents its children 6001/// from being the target of located events, because it returns true from 6002/// [RenderBox.hitTest]. 6003/// 6004/// {@youtube 560 315 https://www.youtube.com/watch?v=65HoWqBboI8} 6005/// 6006/// See also: 6007/// 6008/// * [IgnorePointer], which also prevents its children from receiving pointer 6009/// events but is itself invisible to hit testing. 6010class AbsorbPointer extends SingleChildRenderObjectWidget { 6011 /// Creates a widget that absorbs pointers during hit testing. 6012 /// 6013 /// The [absorbing] argument must not be null 6014 const AbsorbPointer({ 6015 Key key, 6016 this.absorbing = true, 6017 Widget child, 6018 this.ignoringSemantics, 6019 }) : assert(absorbing != null), 6020 super(key: key, child: child); 6021 6022 /// Whether this widget absorbs pointers during hit testing. 6023 /// 6024 /// Regardless of whether this render object absorbs pointers during hit 6025 /// testing, it will still consume space during layout and be visible during 6026 /// painting. 6027 final bool absorbing; 6028 6029 /// Whether the semantics of this render object is ignored when compiling the 6030 /// semantics tree. 6031 /// 6032 /// If null, defaults to the value of [absorbing]. 6033 /// 6034 /// See [SemanticsNode] for additional information about the semantics tree. 6035 final bool ignoringSemantics; 6036 6037 @override 6038 RenderAbsorbPointer createRenderObject(BuildContext context) { 6039 return RenderAbsorbPointer( 6040 absorbing: absorbing, 6041 ignoringSemantics: ignoringSemantics, 6042 ); 6043 } 6044 6045 @override 6046 void updateRenderObject(BuildContext context, RenderAbsorbPointer renderObject) { 6047 renderObject 6048 ..absorbing = absorbing 6049 ..ignoringSemantics = ignoringSemantics; 6050 } 6051 6052 @override 6053 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6054 super.debugFillProperties(properties); 6055 properties.add(DiagnosticsProperty<bool>('absorbing', absorbing)); 6056 properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics, defaultValue: null)); 6057 } 6058} 6059 6060/// Holds opaque meta data in the render tree. 6061/// 6062/// Useful for decorating the render tree with information that will be consumed 6063/// later. For example, you could store information in the render tree that will 6064/// be used when the user interacts with the render tree but has no visual 6065/// impact prior to the interaction. 6066class MetaData extends SingleChildRenderObjectWidget { 6067 /// Creates a widget that hold opaque meta data. 6068 /// 6069 /// The [behavior] argument defaults to [HitTestBehavior.deferToChild]. 6070 const MetaData({ 6071 Key key, 6072 this.metaData, 6073 this.behavior = HitTestBehavior.deferToChild, 6074 Widget child, 6075 }) : super(key: key, child: child); 6076 6077 /// Opaque meta data ignored by the render tree 6078 final dynamic metaData; 6079 6080 /// How to behave during hit testing. 6081 final HitTestBehavior behavior; 6082 6083 @override 6084 RenderMetaData createRenderObject(BuildContext context) { 6085 return RenderMetaData( 6086 metaData: metaData, 6087 behavior: behavior, 6088 ); 6089 } 6090 6091 @override 6092 void updateRenderObject(BuildContext context, RenderMetaData renderObject) { 6093 renderObject 6094 ..metaData = metaData 6095 ..behavior = behavior; 6096 } 6097 6098 @override 6099 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6100 super.debugFillProperties(properties); 6101 properties.add(EnumProperty<HitTestBehavior>('behavior', behavior)); 6102 properties.add(DiagnosticsProperty<dynamic>('metaData', metaData)); 6103 } 6104} 6105 6106 6107// UTILITY NODES 6108 6109/// A widget that annotates the widget tree with a description of the meaning of 6110/// the widgets. 6111/// 6112/// Used by accessibility tools, search engines, and other semantic analysis 6113/// software to determine the meaning of the application. 6114/// 6115/// See also: 6116/// 6117/// * [MergeSemantics], which marks a subtree as being a single node for 6118/// accessibility purposes. 6119/// * [ExcludeSemantics], which excludes a subtree from the semantics tree 6120/// (which might be useful if it is, e.g., totally decorative and not 6121/// important to the user). 6122/// * [RenderObject.semanticsAnnotator], the rendering library API through which 6123/// the [Semantics] widget is actually implemented. 6124/// * [SemanticsNode], the object used by the rendering library to represent 6125/// semantics in the semantics tree. 6126/// * [SemanticsDebugger], an overlay to help visualize the semantics tree. Can 6127/// be enabled using [WidgetsApp.showSemanticsDebugger] or 6128/// [MaterialApp.showSemanticsDebugger]. 6129@immutable 6130class Semantics extends SingleChildRenderObjectWidget { 6131 /// Creates a semantic annotation. 6132 /// 6133 /// The [container] argument must not be null. To create a `const` instance 6134 /// of [Semantics], use the [Semantics.fromProperties] constructor. 6135 /// 6136 /// See also: 6137 /// 6138 /// * [SemanticsSortKey] for a class that determines accessibility traversal 6139 /// order. 6140 Semantics({ 6141 Key key, 6142 Widget child, 6143 bool container = false, 6144 bool explicitChildNodes = false, 6145 bool excludeSemantics = false, 6146 bool enabled, 6147 bool checked, 6148 bool selected, 6149 bool toggled, 6150 bool button, 6151 bool header, 6152 bool textField, 6153 bool readOnly, 6154 bool focused, 6155 bool inMutuallyExclusiveGroup, 6156 bool obscured, 6157 bool multiline, 6158 bool scopesRoute, 6159 bool namesRoute, 6160 bool hidden, 6161 bool image, 6162 bool liveRegion, 6163 String label, 6164 String value, 6165 String increasedValue, 6166 String decreasedValue, 6167 String hint, 6168 String onTapHint, 6169 String onLongPressHint, 6170 TextDirection textDirection, 6171 SemanticsSortKey sortKey, 6172 VoidCallback onTap, 6173 VoidCallback onLongPress, 6174 VoidCallback onScrollLeft, 6175 VoidCallback onScrollRight, 6176 VoidCallback onScrollUp, 6177 VoidCallback onScrollDown, 6178 VoidCallback onIncrease, 6179 VoidCallback onDecrease, 6180 VoidCallback onCopy, 6181 VoidCallback onCut, 6182 VoidCallback onPaste, 6183 VoidCallback onDismiss, 6184 MoveCursorHandler onMoveCursorForwardByCharacter, 6185 MoveCursorHandler onMoveCursorBackwardByCharacter, 6186 SetSelectionHandler onSetSelection, 6187 VoidCallback onDidGainAccessibilityFocus, 6188 VoidCallback onDidLoseAccessibilityFocus, 6189 Map<CustomSemanticsAction, VoidCallback> customSemanticsActions, 6190 }) : this.fromProperties( 6191 key: key, 6192 child: child, 6193 container: container, 6194 explicitChildNodes: explicitChildNodes, 6195 excludeSemantics: excludeSemantics, 6196 properties: SemanticsProperties( 6197 enabled: enabled, 6198 checked: checked, 6199 toggled: toggled, 6200 selected: selected, 6201 button: button, 6202 header: header, 6203 textField: textField, 6204 readOnly: readOnly, 6205 focused: focused, 6206 inMutuallyExclusiveGroup: inMutuallyExclusiveGroup, 6207 obscured: obscured, 6208 multiline: multiline, 6209 scopesRoute: scopesRoute, 6210 namesRoute: namesRoute, 6211 hidden: hidden, 6212 image: image, 6213 liveRegion: liveRegion, 6214 label: label, 6215 value: value, 6216 increasedValue: increasedValue, 6217 decreasedValue: decreasedValue, 6218 hint: hint, 6219 textDirection: textDirection, 6220 sortKey: sortKey, 6221 onTap: onTap, 6222 onLongPress: onLongPress, 6223 onScrollLeft: onScrollLeft, 6224 onScrollRight: onScrollRight, 6225 onScrollUp: onScrollUp, 6226 onScrollDown: onScrollDown, 6227 onIncrease: onIncrease, 6228 onDecrease: onDecrease, 6229 onCopy: onCopy, 6230 onCut: onCut, 6231 onPaste: onPaste, 6232 onMoveCursorForwardByCharacter: onMoveCursorForwardByCharacter, 6233 onMoveCursorBackwardByCharacter: onMoveCursorBackwardByCharacter, 6234 onDidGainAccessibilityFocus: onDidGainAccessibilityFocus, 6235 onDidLoseAccessibilityFocus: onDidLoseAccessibilityFocus, 6236 onDismiss: onDismiss, 6237 onSetSelection: onSetSelection, 6238 customSemanticsActions: customSemanticsActions, 6239 hintOverrides: onTapHint != null || onLongPressHint != null ? 6240 SemanticsHintOverrides( 6241 onTapHint: onTapHint, 6242 onLongPressHint: onLongPressHint, 6243 ) : null, 6244 ), 6245 ); 6246 6247 /// Creates a semantic annotation using [SemanticsProperties]. 6248 /// 6249 /// The [container] and [properties] arguments must not be null. 6250 const Semantics.fromProperties({ 6251 Key key, 6252 Widget child, 6253 this.container = false, 6254 this.explicitChildNodes = false, 6255 this.excludeSemantics = false, 6256 @required this.properties, 6257 }) : assert(container != null), 6258 assert(properties != null), 6259 super(key: key, child: child); 6260 6261 /// Contains properties used by assistive technologies to make the application 6262 /// more accessible. 6263 final SemanticsProperties properties; 6264 6265 /// If [container] is true, this widget will introduce a new 6266 /// node in the semantics tree. Otherwise, the semantics will be 6267 /// merged with the semantics of any ancestors (if the ancestor allows that). 6268 /// 6269 /// Whether descendants of this widget can add their semantic information to the 6270 /// [SemanticsNode] introduced by this configuration is controlled by 6271 /// [explicitChildNodes]. 6272 final bool container; 6273 6274 /// Whether descendants of this widget are allowed to add semantic information 6275 /// to the [SemanticsNode] annotated by this widget. 6276 /// 6277 /// When set to false descendants are allowed to annotate [SemanticNode]s of 6278 /// their parent with the semantic information they want to contribute to the 6279 /// semantic tree. 6280 /// When set to true the only way for descendants to contribute semantic 6281 /// information to the semantic tree is to introduce new explicit 6282 /// [SemanticNode]s to the tree. 6283 /// 6284 /// If the semantics properties of this node include 6285 /// [SemanticsProperties.scopesRoute] set to true, then [explicitChildNodes] 6286 /// must be true also. 6287 /// 6288 /// This setting is often used in combination with [SemanticsConfiguration.isSemanticBoundary] 6289 /// to create semantic boundaries that are either writable or not for children. 6290 final bool explicitChildNodes; 6291 6292 /// Whether to replace all child semantics with this node. 6293 /// 6294 /// Defaults to false. 6295 /// 6296 /// When this flag is set to true, all child semantics nodes are ignored. 6297 /// This can be used as a convenience for cases where a child is wrapped in 6298 /// an [ExcludeSemantics] widget and then another [Semantics] widget. 6299 final bool excludeSemantics; 6300 6301 @override 6302 RenderSemanticsAnnotations createRenderObject(BuildContext context) { 6303 return RenderSemanticsAnnotations( 6304 container: container, 6305 explicitChildNodes: explicitChildNodes, 6306 excludeSemantics: excludeSemantics, 6307 enabled: properties.enabled, 6308 checked: properties.checked, 6309 toggled: properties.toggled, 6310 selected: properties.selected, 6311 button: properties.button, 6312 header: properties.header, 6313 textField: properties.textField, 6314 readOnly: properties.readOnly, 6315 focused: properties.focused, 6316 liveRegion: properties.liveRegion, 6317 inMutuallyExclusiveGroup: properties.inMutuallyExclusiveGroup, 6318 obscured: properties.obscured, 6319 multiline: properties.multiline, 6320 scopesRoute: properties.scopesRoute, 6321 namesRoute: properties.namesRoute, 6322 hidden: properties.hidden, 6323 image: properties.image, 6324 label: properties.label, 6325 value: properties.value, 6326 increasedValue: properties.increasedValue, 6327 decreasedValue: properties.decreasedValue, 6328 hint: properties.hint, 6329 hintOverrides: properties.hintOverrides, 6330 textDirection: _getTextDirection(context), 6331 sortKey: properties.sortKey, 6332 onTap: properties.onTap, 6333 onLongPress: properties.onLongPress, 6334 onScrollLeft: properties.onScrollLeft, 6335 onScrollRight: properties.onScrollRight, 6336 onScrollUp: properties.onScrollUp, 6337 onScrollDown: properties.onScrollDown, 6338 onIncrease: properties.onIncrease, 6339 onDecrease: properties.onDecrease, 6340 onCopy: properties.onCopy, 6341 onDismiss: properties.onDismiss, 6342 onCut: properties.onCut, 6343 onPaste: properties.onPaste, 6344 onMoveCursorForwardByCharacter: properties.onMoveCursorForwardByCharacter, 6345 onMoveCursorBackwardByCharacter: properties.onMoveCursorBackwardByCharacter, 6346 onMoveCursorForwardByWord: properties.onMoveCursorForwardByWord, 6347 onMoveCursorBackwardByWord: properties.onMoveCursorBackwardByWord, 6348 onSetSelection: properties.onSetSelection, 6349 onDidGainAccessibilityFocus: properties.onDidGainAccessibilityFocus, 6350 onDidLoseAccessibilityFocus: properties.onDidLoseAccessibilityFocus, 6351 customSemanticsActions: properties.customSemanticsActions, 6352 ); 6353 } 6354 6355 TextDirection _getTextDirection(BuildContext context) { 6356 if (properties.textDirection != null) 6357 return properties.textDirection; 6358 6359 final bool containsText = properties.label != null || properties.value != null || properties.hint != null; 6360 6361 if (!containsText) 6362 return null; 6363 6364 return Directionality.of(context); 6365 } 6366 6367 @override 6368 void updateRenderObject(BuildContext context, RenderSemanticsAnnotations renderObject) { 6369 renderObject 6370 ..container = container 6371 ..explicitChildNodes = explicitChildNodes 6372 ..excludeSemantics = excludeSemantics 6373 ..scopesRoute = properties.scopesRoute 6374 ..enabled = properties.enabled 6375 ..checked = properties.checked 6376 ..toggled = properties.toggled 6377 ..selected = properties.selected 6378 ..button = properties.button 6379 ..header = properties.header 6380 ..textField = properties.textField 6381 ..readOnly = properties.readOnly 6382 ..focused = properties.focused 6383 ..inMutuallyExclusiveGroup = properties.inMutuallyExclusiveGroup 6384 ..obscured = properties.obscured 6385 ..multiline = properties.multiline 6386 ..hidden = properties.hidden 6387 ..image = properties.image 6388 ..liveRegion = properties.liveRegion 6389 ..label = properties.label 6390 ..value = properties.value 6391 ..increasedValue = properties.increasedValue 6392 ..decreasedValue = properties.decreasedValue 6393 ..hint = properties.hint 6394 ..hintOverrides = properties.hintOverrides 6395 ..namesRoute = properties.namesRoute 6396 ..textDirection = _getTextDirection(context) 6397 ..sortKey = properties.sortKey 6398 ..onTap = properties.onTap 6399 ..onLongPress = properties.onLongPress 6400 ..onScrollLeft = properties.onScrollLeft 6401 ..onScrollRight = properties.onScrollRight 6402 ..onScrollUp = properties.onScrollUp 6403 ..onScrollDown = properties.onScrollDown 6404 ..onIncrease = properties.onIncrease 6405 ..onDismiss = properties.onDismiss 6406 ..onDecrease = properties.onDecrease 6407 ..onCopy = properties.onCopy 6408 ..onCut = properties.onCut 6409 ..onPaste = properties.onPaste 6410 ..onMoveCursorForwardByCharacter = properties.onMoveCursorForwardByCharacter 6411 ..onMoveCursorBackwardByCharacter = properties.onMoveCursorForwardByCharacter 6412 ..onMoveCursorForwardByWord = properties.onMoveCursorForwardByWord 6413 ..onMoveCursorBackwardByWord = properties.onMoveCursorBackwardByWord 6414 ..onSetSelection = properties.onSetSelection 6415 ..onDidGainAccessibilityFocus = properties.onDidGainAccessibilityFocus 6416 ..onDidLoseAccessibilityFocus = properties.onDidLoseAccessibilityFocus 6417 ..customSemanticsActions = properties.customSemanticsActions; 6418 } 6419 6420 @override 6421 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6422 super.debugFillProperties(properties); 6423 properties.add(DiagnosticsProperty<bool>('container', container)); 6424 properties.add(DiagnosticsProperty<SemanticsProperties>('properties', this.properties)); 6425 this.properties.debugFillProperties(properties); 6426 } 6427} 6428 6429/// A widget that merges the semantics of its descendants. 6430/// 6431/// Causes all the semantics of the subtree rooted at this node to be 6432/// merged into one node in the semantics tree. For example, if you 6433/// have a widget with a Text node next to a checkbox widget, this 6434/// could be used to merge the label from the Text node with the 6435/// "checked" semantic state of the checkbox into a single node that 6436/// had both the label and the checked state. Otherwise, the label 6437/// would be presented as a separate feature than the checkbox, and 6438/// the user would not be able to be sure that they were related. 6439/// 6440/// Be aware that if two nodes in the subtree have conflicting 6441/// semantics, the result may be nonsensical. For example, a subtree 6442/// with a checked checkbox and an unchecked checkbox will be 6443/// presented as checked. All the labels will be merged into a single 6444/// string (with newlines separating each label from the other). If 6445/// multiple nodes in the merged subtree can handle semantic gestures, 6446/// the first one in tree order will be the one to receive the 6447/// callbacks. 6448class MergeSemantics extends SingleChildRenderObjectWidget { 6449 /// Creates a widget that merges the semantics of its descendants. 6450 const MergeSemantics({ Key key, Widget child }) : super(key: key, child: child); 6451 6452 @override 6453 RenderMergeSemantics createRenderObject(BuildContext context) => RenderMergeSemantics(); 6454} 6455 6456/// A widget that drops the semantics of all widget that were painted before it 6457/// in the same semantic container. 6458/// 6459/// This is useful to hide widgets from accessibility tools that are painted 6460/// behind a certain widget, e.g. an alert should usually disallow interaction 6461/// with any widget located "behind" the alert (even when they are still 6462/// partially visible). Similarly, an open [Drawer] blocks interactions with 6463/// any widget outside the drawer. 6464/// 6465/// See also: 6466/// 6467/// * [ExcludeSemantics] which drops all semantics of its descendants. 6468class BlockSemantics extends SingleChildRenderObjectWidget { 6469 /// Creates a widget that excludes the semantics of all widgets painted before 6470 /// it in the same semantic container. 6471 const BlockSemantics({ Key key, this.blocking = true, Widget child }) : super(key: key, child: child); 6472 6473 /// Whether this widget is blocking semantics of all widget that were painted 6474 /// before it in the same semantic container. 6475 final bool blocking; 6476 6477 @override 6478 RenderBlockSemantics createRenderObject(BuildContext context) => RenderBlockSemantics(blocking: blocking); 6479 6480 @override 6481 void updateRenderObject(BuildContext context, RenderBlockSemantics renderObject) { 6482 renderObject.blocking = blocking; 6483 } 6484 6485 @override 6486 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6487 super.debugFillProperties(properties); 6488 properties.add(DiagnosticsProperty<bool>('blocking', blocking)); 6489 } 6490} 6491 6492/// A widget that drops all the semantics of its descendants. 6493/// 6494/// When [excluding] is true, this widget (and its subtree) is excluded from 6495/// the semantics tree. 6496/// 6497/// This can be used to hide descendant widgets that would otherwise be 6498/// reported but that would only be confusing. For example, the 6499/// material library's [Chip] widget hides the avatar since it is 6500/// redundant with the chip label. 6501/// 6502/// See also: 6503/// 6504/// * [BlockSemantics] which drops semantics of widgets earlier in the tree. 6505class ExcludeSemantics extends SingleChildRenderObjectWidget { 6506 /// Creates a widget that drops all the semantics of its descendants. 6507 const ExcludeSemantics({ 6508 Key key, 6509 this.excluding = true, 6510 Widget child, 6511 }) : assert(excluding != null), 6512 super(key: key, child: child); 6513 6514 /// Whether this widget is excluded in the semantics tree. 6515 final bool excluding; 6516 6517 @override 6518 RenderExcludeSemantics createRenderObject(BuildContext context) => RenderExcludeSemantics(excluding: excluding); 6519 6520 @override 6521 void updateRenderObject(BuildContext context, RenderExcludeSemantics renderObject) { 6522 renderObject.excluding = excluding; 6523 } 6524 6525 @override 6526 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6527 super.debugFillProperties(properties); 6528 properties.add(DiagnosticsProperty<bool>('excluding', excluding)); 6529 } 6530} 6531 6532/// A widget that annotates the child semantics with an index. 6533/// 6534/// Semantic indexes are used by TalkBack/Voiceover to make announcements about 6535/// the current scroll state. Certain widgets like the [ListView] will 6536/// automatically provide a child index for building semantics. A user may wish 6537/// to manually provide semantic indexes if not all child of the scrollable 6538/// contribute semantics. 6539/// 6540/// {@tool sample} 6541/// 6542/// The example below handles spacers in a scrollable that don't contribute 6543/// semantics. The automatic indexes would give the spaces a semantic index, 6544/// causing scroll announcements to erroneously state that there are four items 6545/// visible. 6546/// 6547/// ```dart 6548/// ListView( 6549/// addSemanticIndexes: false, 6550/// semanticChildCount: 2, 6551/// children: const <Widget>[ 6552/// IndexedSemantics(index: 0, child: Text('First')), 6553/// Spacer(), 6554/// IndexedSemantics(index: 1, child: Text('Second')), 6555/// Spacer(), 6556/// ], 6557/// ) 6558/// ``` 6559/// {@end-tool} 6560/// 6561/// See also: 6562/// 6563/// * [CustomScrollView], for an explanation of index semantics. 6564class IndexedSemantics extends SingleChildRenderObjectWidget { 6565 /// Creates a widget that annotated the first child semantics node with an index. 6566 /// 6567 /// [index] must not be null. 6568 const IndexedSemantics({ 6569 Key key, 6570 @required this.index, 6571 Widget child, 6572 }) : assert(index != null), 6573 super(key: key, child: child); 6574 6575 /// The index used to annotate the first child semantics node. 6576 final int index; 6577 6578 @override 6579 RenderIndexedSemantics createRenderObject(BuildContext context) => RenderIndexedSemantics(index: index); 6580 6581 @override 6582 void updateRenderObject(BuildContext context, RenderIndexedSemantics renderObject) { 6583 renderObject.index = index; 6584 } 6585 @override 6586 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 6587 super.debugFillProperties(properties); 6588 properties.add(DiagnosticsProperty<int>('index', index)); 6589 } 6590} 6591 6592/// A widget that builds its child. 6593/// 6594/// Useful for attaching a key to an existing widget. 6595class KeyedSubtree extends StatelessWidget { 6596 /// Creates a widget that builds its child. 6597 const KeyedSubtree({ 6598 Key key, 6599 @required this.child, 6600 }) : assert(child != null), 6601 super(key: key); 6602 6603 /// Creates a KeyedSubtree for child with a key that's based on the child's existing key or childIndex. 6604 factory KeyedSubtree.wrap(Widget child, int childIndex) { 6605 final Key key = child.key != null ? ValueKey<Key>(child.key) : ValueKey<int>(childIndex); 6606 return KeyedSubtree(key: key, child: child); 6607 } 6608 6609 /// The widget below this widget in the tree. 6610 /// 6611 /// {@macro flutter.widgets.child} 6612 final Widget child; 6613 6614 /// Wrap each item in a KeyedSubtree whose key is based on the item's existing key or 6615 /// the sum of its list index and `baseIndex`. 6616 static List<Widget> ensureUniqueKeysForList(Iterable<Widget> items, { int baseIndex = 0 }) { 6617 if (items == null || items.isEmpty) 6618 return items; 6619 6620 final List<Widget> itemsWithUniqueKeys = <Widget>[]; 6621 int itemIndex = baseIndex; 6622 for (Widget item in items) { 6623 itemsWithUniqueKeys.add(KeyedSubtree.wrap(item, itemIndex)); 6624 itemIndex += 1; 6625 } 6626 6627 assert(!debugItemsHaveDuplicateKeys(itemsWithUniqueKeys)); 6628 return itemsWithUniqueKeys; 6629 } 6630 6631 @override 6632 Widget build(BuildContext context) => child; 6633} 6634 6635/// A platonic widget that calls a closure to obtain its child widget. 6636/// 6637/// See also: 6638/// 6639/// * [StatefulBuilder], a platonic widget which also has state. 6640class Builder extends StatelessWidget { 6641 /// Creates a widget that delegates its build to a callback. 6642 /// 6643 /// The [builder] argument must not be null. 6644 const Builder({ 6645 Key key, 6646 @required this.builder, 6647 }) : assert(builder != null), 6648 super(key: key); 6649 6650 /// Called to obtain the child widget. 6651 /// 6652 /// This function is called whenever this widget is included in its parent's 6653 /// build and the old widget (if any) that it synchronizes with has a distinct 6654 /// object identity. Typically the parent's build method will construct 6655 /// a new tree of widgets and so a new Builder child will not be [identical] 6656 /// to the corresponding old one. 6657 final WidgetBuilder builder; 6658 6659 @override 6660 Widget build(BuildContext context) => builder(context); 6661} 6662 6663/// Signature for the builder callback used by [StatefulBuilder]. 6664/// 6665/// Call [setState] to schedule the [StatefulBuilder] to rebuild. 6666typedef StatefulWidgetBuilder = Widget Function(BuildContext context, StateSetter setState); 6667 6668/// A platonic widget that both has state and calls a closure to obtain its child widget. 6669/// 6670/// The [StateSetter] function passed to the [builder] is used to invoke a 6671/// rebuild instead of a typical [State]'s [State.setState]. 6672/// 6673/// Since the [builder] is re-invoked when the [StateSetter] is called, any 6674/// variables that represents state should be kept outside the [builder] function. 6675/// 6676/// {@tool sample} 6677/// 6678/// This example shows using an inline StatefulBuilder that rebuilds and that 6679/// also has state. 6680/// 6681/// ```dart 6682/// await showDialog<void>( 6683/// context: context, 6684/// builder: (BuildContext context) { 6685/// int selectedRadio = 0; 6686/// return AlertDialog( 6687/// content: StatefulBuilder( 6688/// builder: (BuildContext context, StateSetter setState) { 6689/// return Column( 6690/// mainAxisSize: MainAxisSize.min, 6691/// children: List<Widget>.generate(4, (int index) { 6692/// return Radio<int>( 6693/// value: index, 6694/// groupValue: selectedRadio, 6695/// onChanged: (int value) { 6696/// setState(() => selectedRadio = value); 6697/// }, 6698/// ); 6699/// }), 6700/// ); 6701/// }, 6702/// ), 6703/// ); 6704/// }, 6705/// ); 6706/// ``` 6707/// {@end-tool} 6708/// 6709/// See also: 6710/// 6711/// * [Builder], the platonic stateless widget. 6712class StatefulBuilder extends StatefulWidget { 6713 /// Creates a widget that both has state and delegates its build to a callback. 6714 /// 6715 /// The [builder] argument must not be null. 6716 const StatefulBuilder({ 6717 Key key, 6718 @required this.builder, 6719 }) : assert(builder != null), 6720 super(key: key); 6721 6722 /// Called to obtain the child widget. 6723 /// 6724 /// This function is called whenever this widget is included in its parent's 6725 /// build and the old widget (if any) that it synchronizes with has a distinct 6726 /// object identity. Typically the parent's build method will construct 6727 /// a new tree of widgets and so a new Builder child will not be [identical] 6728 /// to the corresponding old one. 6729 final StatefulWidgetBuilder builder; 6730 6731 @override 6732 _StatefulBuilderState createState() => _StatefulBuilderState(); 6733} 6734 6735class _StatefulBuilderState extends State<StatefulBuilder> { 6736 @override 6737 Widget build(BuildContext context) => widget.builder(context, setState); 6738} 6739