UGUI源码分析系列总览 BaseClass: UIBehaviour Interface: ILayoutElement, ILayoutGroup Intro:布局系统的实施组件的基类 虽然UGUI组件中有一些组件都继承了ILayoutElement接口,但并不会涉及对接口方法的实现。这是因为这些组件主要是布局操作的接收方,只需要通过该接口被布局实施方所发现即可。 LayoutGroup,是布局组件的基类(GridLayoutGroup、HorizontalOrVerticalLayoutGroup)。本文主要针对纵横布局组件(HorizontalLayoutGroup、VerticalLayoutGroup)进行分析。 接下来,作者以HorizontalLayoutGroup为例,逐步进行布局实现的分析。 延续LayoutRebuilder的Rebuild方法(详情:UGUI源码分析:LayoutSystem布局系统),首先被执行的是ILayoutElement的CalculateLayoutInputHorizontal方法。该方法将收集其子节点下所有没有被标记ignoreLayout的物体(m_RectChildren)。 CalcAlongAxis 主要是做LayoutGroup的一些初始化参数的计算。 STEP2:接着会执行ILayoutController的SetLayoutHorizontal方法。这在GridLayoutGroup、HorizontalLayoutGroup、VerticalLayoutGroup中有不同的处理。 LayoutGroup组件如何调整子物体的位置与大小一句话概括:利用了Unity RectTransform中的一个方法 布局物体的方法主要是在 选择出目标边(Edge),计算出距离(inset),计算出子物体的大小(size)。 到此,纵横布局组件的布局分析就完毕啦,下篇文章作者会对GridLayoutGroup(网格布局组件)以及ILayoutController另一个衍生ContentSizeFitter(尺寸调节组件)进行详细分析。 . 嗨,我是作者Vin129,逐儿时之梦正在游戏制作的技术海洋中漂泊。知道的越多,不知道的也越多。希望我的文章对你有所帮助:)
系列
相关前置:
UGUI CanvasUpdateSystem源码分析
UGUI源码分析:LayoutSystem布局系统文章目录
UML图一览
LayoutGroup
属性介绍
布局过程
// HorizontalLayoutGroup public override void CalculateLayoutInputHorizontal() { // 基类(LayoutGroup)方法 base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0, false); }
//LayoutGroup public virtual void CalculateLayoutInputHorizontal() { //清空list,准备收集子节点下没有被ignoreLayout的物体 m_RectChildren.Clear(); var toIgnoreList = ListPool<Component>.Get(); for (int i = 0; i < rectTransform.childCount; i++) { var rect = rectTransform.GetChild(i) as RectTransform; if (rect == null || !rect.gameObject.activeInHierarchy) continue; rect.GetComponents(typeof(ILayoutIgnorer), toIgnoreList); if (toIgnoreList.Count == 0) { m_RectChildren.Add(rect); continue; } for (int j = 0; j < toIgnoreList.Count; j++) { var ignorer = (ILayoutIgnorer)toIgnoreList[j]; if (!ignorer.ignoreLayout) { m_RectChildren.Add(rect); break; } } } ListPool<Component>.Release(toIgnoreList); m_Tracker.Clear(); }
//LayoutGroup protected void CalcAlongAxis(int axis, bool isVertical) { float combinedPadding = (axis == 0 ? padding.horizontal : padding.vertical); bool controlSize = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight); bool childForceExpandSize = (axis == 0 ? childForceExpandWidth : childForceExpandHeight); float totalMin = combinedPadding; float totalPreferred = combinedPadding; float totalFlexible = 0; bool alongOtherAxis = (isVertical ^ (axis == 1)); for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); if (alongOtherAxis) { //另一条轴的情况简单处理,取其中最大的子物体的值即可 totalMin = Mathf.Max(min + combinedPadding, totalMin); totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred); totalFlexible = Mathf.Max(flexible, totalFlexible); } else { //目标轴处理,数值为子物体数值的累加 totalMin += min + spacing; totalPreferred += preferred + spacing; //包括间隔 // Increment flexible size with element's flexible size. totalFlexible += flexible; } //去掉多余的一次间隔 if (!alongOtherAxis && rectChildren.Count > 0) { totalMin -= spacing; totalPreferred -= spacing; } totalPreferred = Mathf.Max(totalMin, totalPreferred); //根据轴设置 m_TotalXXX值 SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis); }
//HorizontalLayoutGroup public override void SetLayoutHorizontal() { //根据轴设置子物体的布局 SetChildrenAlongAxis(0, false); }
SetInsetAndSizeFromParentEdge(RectTransform.Edge edge, float inset, float size);
//LayoutGroup protected void SetChildrenAlongAxis(int axis, bool isVertical) { //获取跟坐标轴有关的设置 float size = rectTransform.rect.size[axis]; bool controlSize = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight); bool childForceExpandSize = (axis == 0 ? childForceExpandWidth : childForceExpandHeight); float alignmentOnAxis = GetAlignmentOnAxis(axis); bool alongOtherAxis = (isVertical ^ (axis == 1)); // 当二者不同时为true 例(水平 y轴,垂直 x轴) if (alongOtherAxis) { //在水平或垂直布局中,另外一条轴的布局操作相对简单一些 //实际尺寸,根据padding计算 float innerSize = size - (axis == 0 ? padding.horizontal : padding.vertical); for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; //获取子物体的尺寸,最小、合适、灵活尺寸 GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); //若强制填充,则会以该部件组件的尺寸来决定,反之则以子物体的最佳尺寸 float requiredSpace = Mathf.Clamp(innerSize, min, flexible > 0 ? size : preferred); //计算距离边的距离 float startOffset = GetStartOffset(axis, requiredSpace); if (controlSize) { // 根据轴选取矩形的边,以及距离、尺寸,设置子物体的位置(API:SetInsetAndSizeFromParentEdge) SetChildAlongAxis(child, axis, startOffset, requiredSpace); } else { float offsetInCell = (requiredSpace - child.sizeDelta[axis]) * alignmentOnAxis; SetChildAlongAxis(child, axis, startOffset + offsetInCell); } } } else { //起始位置:对于边的距离 float pos = (axis == 0 ? padding.left : padding.top); if (GetTotalFlexibleSize(axis) == 0 && GetTotalPreferredSize(axis) < size) pos = GetStartOffset(axis, GetTotalPreferredSize(axis) - (axis == 0 ? padding.horizontal : padding.vertical)); //差值 float minMaxLerp = 0; if (GetTotalMinSize(axis) != GetTotalPreferredSize(axis)) minMaxLerp = Mathf.Clamp01((size - GetTotalMinSize(axis)) / (GetTotalPreferredSize(axis) - GetTotalMinSize(axis))); float itemFlexibleMultiplier = 0; if (size > GetTotalPreferredSize(axis)) { if (GetTotalFlexibleSize(axis) > 0) itemFlexibleMultiplier = (size - GetTotalPreferredSize(axis)) / GetTotalFlexibleSize(axis); } for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); float childSize = Mathf.Lerp(min, preferred, minMaxLerp); childSize += flexible * itemFlexibleMultiplier; if (controlSize) { // 根据轴选取矩形的边,以及距离、尺寸,设置子物体的位置(API:SetInsetAndSizeFromParentEdge) SetChildAlongAxis(child, axis, pos, childSize); } else { float offsetInCell = (childSize - child.sizeDelta[axis]) * alignmentOnAxis; SetChildAlongAxis(child, axis, pos + offsetInCell); } //更新距离,累计子物体尺寸与间隔 pos += childSize + spacing; } } }
.
.
.
.
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算