一区二区三区欧美日韩-一区二区三区欧美-一区二区三区免费在线视频-一区二区三区免费在线观看-久久精品店-久久精品第一页

歡迎您光臨深圳塔燈網絡科技有限公司!
電話圖標 余先生:13699882642

網站百科

為您解碼網站建設的點點滴滴

Flutter自定義布局套路

發表日期:2018-08 文章編輯:小燈 瀏覽次數:1817

開始

在Android中我們要實現一個布局需要繼承ViewGroup, 重寫其中的onLayoutonMeasure方法. 其中onLayout負責給子控件設置布局區域, onMeaseure度量子控件大小和自身大小. 今天我們就研究下Flutter是如何實現布局的.

Flutter布局

首先我們挑選一個Flutter控件去看源碼, 我們就選Stack, 因為它足夠簡單. 從表象上講它只要重疊擺放一組子控件即可. 先看下Stack的源碼:

class Stack extends MultiChildRenderObjectWidget { Stack({ Key key, this.alignment: AlignmentDirectional.topStart, this.textDirection, this.fit: StackFit.loose, this.overflow: Overflow.clip, List<Widget> children: const <Widget>[], }) : super(key: key, children: children);final AlignmentGeometry alignment; final StackFit fit; final Overflow overflow;@override RenderStack createRenderObject(BuildContext context) { return new RenderStack( alignment: alignment, textDirection: textDirection ?? Directionality.of(context), fit: fit, overflow: overflow, ); }@override void updateRenderObject(BuildContext context, RenderStack renderObject) { renderObject ..alignment = alignment ..textDirection = textDirection ?? Directionality.of(context) ..fit = fit ..overflow = overflow; }@override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(new EnumProperty<StackFit>('fit', fit)); properties.add(new EnumProperty<Overflow>('overflow', overflow)); } } 

Stack繼承自MultiChildRenderObjectWidget, 重寫了createRenderObject其返回了一個RenderStack對象, 實際的工作者. 而updateRenderObject則只是修改RenderStack對象的屬性. debugFillProperties方法則是填充該類屬性的參數值到DiagnosticPropertiesBuilder中.

我們看看Flex, 也是如此, 重寫了createRenderObject其返回了一個RenderFlex對象, 實際的工作者. 而updateRenderObject則只是修改RenderFlex對象的屬性.

所以我們接下來看看RenderStack, 精簡代碼如下:

class RenderStack extends RenderBox with ContainerRenderObjectMixin<RenderBox, StackParentData>,RenderBoxContainerDefaultsMixin<RenderBox, StackParentData> { RenderStack({ List<RenderBox> children, AlignmentGeometry alignment: AlignmentDirectional.topStart, TextDirection textDirection, StackFit fit: StackFit.loose, Overflow overflow: Overflow.clip, }) : assert(alignment != null),assert(fit != null),assert(overflow != null),_alignment = alignment,_textDirection = textDirection,_fit = fit,_overflow = overflow { addAll(children); }bool _hasVisualOverflow = false;@override void performLayout() { _resolve(); assert(_resolvedAlignment != null); _hasVisualOverflow = false; bool hasNonPositionedChildren = false; if (childCount == 0) { size = constraints.biggest; assert(size.isFinite); return; }double width = constraints.minWidth; double height = constraints.minHeight;BoxConstraints nonPositionedConstraints; assert(fit != null); switch (fit) { case StackFit.loose: nonPositionedConstraints = constraints.loosen(); break; case StackFit.expand: nonPositionedConstraints = new BoxConstraints.tight(constraints.biggest); break; case StackFit.passthrough: nonPositionedConstraints = constraints; break; } assert(nonPositionedConstraints != null);RenderBox child = firstChild; while (child != null) { final StackParentData childParentData = child.parentData;if (!childParentData.isPositioned) { hasNonPositionedChildren = true;child.layout(nonPositionedConstraints, parentUsesSize: true);final Size childSize = child.size; width = math.max(width, childSize.width); height = math.max(height, childSize.height); }child = childParentData.nextSibling; }if (hasNonPositionedChildren) { size = new Size(width, height); assert(size.width == constraints.constrainWidth(width)); assert(size.height == constraints.constrainHeight(height)); } else { size = constraints.biggest; }assert(size.isFinite);child = firstChild; while (child != null) { final StackParentData childParentData = child.parentData;if (!childParentData.isPositioned) { childParentData.offset = _resolvedAlignment.alongOffset(size - child.size); } else { BoxConstraints childConstraints = const BoxConstraints();if (childParentData.left != null && childParentData.right != null) childConstraints = childConstraints.tighten(width: size.width - childParentData.right - childParentData.left); else if (childParentData.width != null) childConstraints = childConstraints.tighten(width: childParentData.width);if (childParentData.top != null && childParentData.bottom != null) childConstraints = childConstraints.tighten(height: size.height - childParentData.bottom - childParentData.top); else if (childParentData.height != null) childConstraints = childConstraints.tighten(height: childParentData.height);child.layout(childConstraints, parentUsesSize: true);double x; if (childParentData.left != null) { x = childParentData.left; } else if (childParentData.right != null) { x = size.width - childParentData.right - child.size.width; } else { x = _resolvedAlignment.alongOffset(size - child.size).dx; }if (x < 0.0 || x + child.size.width > size.width) _hasVisualOverflow = true;double y; if (childParentData.top != null) { y = childParentData.top; } else if (childParentData.bottom != null) { y = size.height - childParentData.bottom - child.size.height; } else { y = _resolvedAlignment.alongOffset(size - child.size).dy; }if (y < 0.0 || y + child.size.height > size.height) _hasVisualOverflow = true;childParentData.offset = new Offset(x, y); }assert(child.parentData == childParentData); child = childParentData.nextSibling; } }@protected void paintStack(PaintingContext context, Offset offset) { defaultPaint(context, offset); }@override void paint(PaintingContext context, Offset offset) { if (_overflow == Overflow.clip && _hasVisualOverflow) { context.pushClipRect(needsCompositing, offset, Offset.zero & size, paintStack); } else { paintStack(context, offset); } } } 

可以看出RenderStack接收了所有傳遞給Stack的參數, 畢竟RenderStack才是實際干活的^^. performLayout負責了所有布局相關的工作. performLayout首先分析StackFit參數, 該參數有3個值:

  • StackFit.loose 按最小的來.
  • StackFit.expand 按最大的來.
  • StackFit.passthrough Stack上層為->Expanded->Row, 橫向盡量大, 縱向盡量小.

得出BoxConstraints. 然后遍歷所有子控件, 如果不是Positioned類型子控件, 則將BoxConstraints傳給子控件讓它根據父控件大小自己內部布局. 并且記錄下所有子控件結合RenderStack自生大小得出的最大高度和寬度. 將其設置為當前控件大小.

接著再繼續從頭遍歷子控件, 如果不是Positioned類型子控件, 根據alignment參數, 設置子控件在父控件中的偏移量, 比如Stack設置了居中, 上面計算出寬100, 高200, 而子控件寬30, 高30, 那么子控件需要偏移x=35, y=85. 如果是Positioned類型的子控件, 先將RenderStacksize大小, 減去Positioned屬性里的大小. 再來計算便宜量.

這個里面有_hasVisualOverflow變量, 如果內容超出RenderStack大小, 其值為true. 也就是我們寫布局時, 內容超過范圍了, 報出來一個色塊提示, 就是如此得出的.
_overflow屬性則指定了子控件的繪制區域是否能超過父控件, 跟Android中的clipChildren屬性很像.

另外我們再分析下IndexedStack, 該控件一次只能顯示一個子控件. 其實際差異在RenderIndexedStack

class RenderIndexedStack extends RenderStack { ... @override bool hitTestChildren(HitTestResult result, { @required Offset position }) { if (firstChild == null || index == null) return false; assert(position != null); final RenderBox child = _childAtIndex(); final StackParentData childParentData = child.parentData; return child.hitTest(result, position: position - childParentData.offset); }@override void paintStack(PaintingContext context, Offset offset) { if (firstChild == null || index == null) return; final RenderBox child = _childAtIndex(); final StackParentData childParentData = child.parentData; context.paintChild(child, childParentData.offset + offset); } ... } 

重寫了RenderStackpaintStackhitTestChildren方法, 只繪制選中的子控件, 和接收事件.

總結

實現一個自定義布局, 我們需要先繼承MultiChildRenderObjectWidget, 然后重寫createRenderObjectupdateRenderObject方法, 前者返回我們自定義的RenderBox的對象. 后者更新想要傳遞的屬性. 然后需要我們繼承RenderBox, 來擴展我們想要的功能特性.


本頁內容由塔燈網絡科技有限公司通過網絡收集編輯所得,所有資料僅供用戶學習參考,本站不擁有所有權,如您認為本網頁中由涉嫌抄襲的內容,請及時與我們聯系,并提供相關證據,工作人員會在5工作日內聯系您,一經查實,本站立刻刪除侵權內容。本文鏈接:http://www.junxiaosheng.cn/17531.html
相關APP開發
 八年  行業經驗

多一份參考,總有益處

聯系深圳網站公司塔燈網絡,免費獲得網站建設方案及報價

咨詢相關問題或預約面談,可以通過以下方式與我們聯系

業務熱線:余經理:13699882642

Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.    

主站蜘蛛池模板: 亚洲 自拍 清纯 综合图区| 国产高清精品国语特黄A片| 天美麻豆成人AV精品视频| 久久re这里视频只有精品首页| 扒开她的黑森林让我添动态图 | 在线免费观看国产精品| 色大姐综合网| 男人国产AV天堂WWW麻豆| 解开美女胸衣2破解版| 国产高清免费视频免费观看| 99热这里只有精品6| 中文无码热在线视频| 亚洲国产系列一区二区三区| 三级黄色在线视频中文| 男人吃奶摸下弄进去好爽| 久久99热狠狠色一区二区| 国产欧美另类久久久精品免费| s8sp视频高清在线播放| 5g在视影讯天天5g免费观看| 亚洲色图p| 亚洲免费视频日本一区二区| 偷偷鲁青春草原视频| 三级网址在线播放| 欧美重口绿帽video| 男人脱女人衣服吃奶视频| 久久视频这里只精品99热在线 | 亚洲国产精品久久人人爱| 日韩一区二区三区视频在线观看| 免费又黄又硬又爽大片| 门鱼电影完整版免费版| 老阿姨才是最有味的一区二区| 久久AV喷吹AV高潮欧美| 国内精品久久久久影院网站| 国产婷婷一区二区在线观看| 国产成人免费网站在线观看 | 伦理片97影视网| 久久青草影院| 恋夜直播午夜秀场最新| 毛片免费观看视频| 欧美激情社区| 日本后进式猛烈xx00动态图|