예제 #1
0
        public void Layout(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom, bool independent)
        {
            bool changed = true;

            if (!independent)
            {
                changed = SetFrame(left.AsRoundedValue(),
                                   top.AsRoundedValue(),
                                   right.AsRoundedValue(),
                                   bottom.AsRoundedValue());
            }
            else
            {
                // If height or width specification is not explicitly defined,
                // the size of the owner view must be reset even the ExcludeLayouting is true.
                if (Owner.HeightSpecification < 0 || Owner.WidthSpecification < 0)
                {
                    Owner.SetSize(right.AsRoundedValue() - left.AsRoundedValue(), bottom.AsRoundedValue() - top.AsRoundedValue());
                }
            }

            // Check if Measure needed before Layouting
            if (changed || ((Flags & LayoutFlags.LayoutRequired) == LayoutFlags.LayoutRequired))
            {
                OnLayout(changed, left, top, right, bottom);
                // Clear flag
                Flags &= ~LayoutFlags.LayoutRequired;
            }
        }
예제 #2
0
        ///<summary>
        /// Utility to reconcile a desired size and state, with constraints imposed by a MeasureSpecification.
        ///</summary>
        /// <param name="size"> How big the layout wants to be.</param>
        /// <param name="measureSpecification"> Constraints imposed by the parent.</param>
        /// <param name="childMeasuredState"> Size information bit mask for the layout's children.</param>
        /// <returns> A measured size, which may indicate that it is too small. </returns>
        /// <since_tizen> 6 </since_tizen>
        protected MeasuredSize ResolveSizeAndState(LayoutLength size, MeasureSpecification measureSpecification, MeasuredSize.StateType childMeasuredState)
        {
            var          specMode = measureSpecification.Mode;
            LayoutLength specSize = measureSpecification.Size;
            MeasuredSize result   = new MeasuredSize(size, childMeasuredState);

            switch (specMode)
            {
            case MeasureSpecification.ModeType.AtMost:
            {
                if (specSize.AsRoundedValue() < size.AsRoundedValue())
                {
                    result = new MeasuredSize(specSize, MeasuredSize.StateType.MeasuredSizeTooSmall);
                }
                break;
            }

            case MeasureSpecification.ModeType.Exactly:
            {
                result.Size = specSize;
                break;
            }

            case MeasureSpecification.ModeType.Unspecified:
            default:
            {
                break;
            }
            }
            return(result);
        }
예제 #3
0
        private bool SetFrame(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
        {
            bool changed = false;

            if (_left != left || _right != right || _top != top || _bottom != bottom)
            {
                changed = true;
            }

            LayoutLength oldWidth    = _right - _left;
            LayoutLength oldHeight   = _bottom - _top;
            LayoutLength newWidth    = right - left;
            LayoutLength newHeight   = bottom - top;
            bool         sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);

            _left   = left;
            _top    = top;
            _right  = right;
            _bottom = bottom;

            // Set actual positions of View.
            Owner.SetX(_left.AsRoundedValue());
            Owner.SetY(_top.AsRoundedValue());
            Owner.SetSize((int)newWidth.AsRoundedValue(), (int)newHeight.AsRoundedValue());

            return(changed);
        }
예제 #4
0
        void ForceUniformWidth(int count, MeasureSpecification heightMeasureSpec)
        {
            // Pretend that the linear layout has an exact size.
            MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);

            for (int i = 0; i < count; ++i)
            {
                LayoutItem childLayout = _children[i];
                if (childLayout != null)
                {
                    LayoutLength desiredWidth  = new LayoutLength(childLayout.Owner.WidthSpecification);
                    LayoutLength desiredHeight = new LayoutLength(Owner.WidthSpecification);

                    if (desiredWidth.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                    {
                        // Temporarily force children to reuse their old measured height
                        LayoutLength oldHeight = desiredHeight;
                        childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();

                        // Remeasure with new dimensions
                        MeasureChildWithMargins(childLayout, uniformMeasureSpec, new LayoutLength(0),
                                                heightMeasureSpec, new LayoutLength(0));

                        childLayout.Owner.HeightSpecification = (int)oldHeight.AsRoundedValue();
                    }
                }
            }
        }
예제 #5
0
        } // LayoutVertical

        void ForceUniformHeight(int count, MeasureSpecification widthMeasureSpec)
        {
            // Pretend that the linear layout has an exact size. This is the measured height of
            // ourselves. The measured height should be the max height of the children, changed
            // to accommodate the heightMeasureSpec from the parent
            MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);

            for (int i = 0; i < count; ++i)
            {
                LayoutItem childLayout = _children[i];
                if (childLayout != null)
                {
                    LayoutLength desiredWidth  = new LayoutLength(childLayout.Owner.WidthSpecification);
                    LayoutLength desiredHeight = new LayoutLength(Owner.WidthSpecification);

                    if (desiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                    {
                        // Temporarily force children to reuse their old measured width
                        LayoutLength oldWidth = desiredWidth;
                        childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
                        // Remeasure with new dimensions
                        MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
                                                uniformMeasureSpec, new LayoutLength(0));

                        childLayout.Owner.WidthSpecification = (int)oldWidth.AsRoundedValue();
                    }
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Measure the layout and its content to determine the measured width and the measured height.<br />
        /// </summary>
        /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
        /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
        /// <since_tizen> 6 </since_tizen>
        protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
        {
            bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
            Extents padding = Owner.Padding;
            Extents margin = Owner.Margin;

            Interop.FlexLayout.FlexLayout_SetMargin(swigCPtr, Extents.getCPtr(margin));
            Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding));

            float width = FlexUndefined; // Behaves as WrapContent (Flex Auto)
            float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)

            if( widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly ||  widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
            {
                width = widthMeasureSpec.Size.AsDecimal();
            }

            if ( heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
            {
                height = heightMeasureSpec.Size.AsDecimal();
            }

            Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width, height, isLayoutRtl );

            LayoutLength flexLayoutWidth =  new LayoutLength( Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr) );
            LayoutLength flexLayoutHeight = new LayoutLength( Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr) );

            Debug.WriteLineIf( LayoutDebugFlex, "FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue()
                                                + " height:" + flexLayoutHeight.AsRoundedValue() );

            SetMeasuredDimensions( GetDefaultSize(flexLayoutWidth, widthMeasureSpec ),
                                   GetDefaultSize(flexLayoutHeight, heightMeasureSpec ) );
        }
예제 #7
0
        /// <summary>
        /// Assign a size and position to a layout and all of its descendants. <br />
        /// This is the second phase of the layout mechanism.  (The first is measuring). In this phase, each parent
        /// calls layout on all of its children to position them.  This is typically done using the child<br />
        /// measurements that were stored in the measure pass.<br />
        /// </summary>
        /// <param name="left">Left position, relative to parent.</param>
        /// <param name="top">Top position, relative to parent.</param>
        /// <param name="right">Right position, relative to parent.</param>
        /// <param name="bottom">Bottom position, relative to parent.</param>
        /// <since_tizen> 6 </since_tizen>
        public void Layout(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
        {
            bool changed = SetFrame(left.AsRoundedValue(),
                                    top.AsRoundedValue(),
                                    right.AsRoundedValue(),
                                    bottom.AsRoundedValue());

            // Check if Measure needed before Layouting
            if (changed || ((Flags & LayoutFlags.LayoutRequired) == LayoutFlags.LayoutRequired))
            {
                OnLayout(changed, left, top, right, bottom);
                // Clear flag
                Flags &= ~LayoutFlags.LayoutRequired;
            }
        }
예제 #8
0
        /// <summary>
        /// Measure the layout and its content to determine the measured width and the measured height.<br />
        /// </summary>
        /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
        /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
        /// <since_tizen> 6 </since_tizen>
        protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
        {
            bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
            Extents padding = Owner.Padding;
            Extents margin = Owner.Margin;

            Interop.FlexLayout.FlexLayout_SetMargin(swigCPtr, Extents.getCPtr(margin));
            Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding));

            float width = FlexUndefined; // Behaves as WrapContent (Flex Auto)
            float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)

            if( widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly ||  widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
            {
                width = widthMeasureSpec.Size.AsDecimal();
            }

            if ( heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
            {
                height = heightMeasureSpec.Size.AsDecimal();
            }

            // Save measureSpec to measure children.
            // In other Layout, we can pass it as parameter to measuring child but in FlexLayout we can't
            // because measurChild function is called by native callback.
            parentMeasureSpecificationWidth = widthMeasureSpec;
            parentMeasureSpecificationHeight = heightMeasureSpec;

            Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width, height, isLayoutRtl );

            LayoutLength flexLayoutWidth =  new LayoutLength( Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr) );
            LayoutLength flexLayoutHeight = new LayoutLength( Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr) );

            Debug.WriteLineIf( LayoutDebugFlex, "FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue()
                                                + " height:" + flexLayoutHeight.AsRoundedValue() );

            SetMeasuredDimensions( GetDefaultSize(flexLayoutWidth, widthMeasureSpec ),
                                   GetDefaultSize(flexLayoutHeight, heightMeasureSpec ) );
        }
예제 #9
0
        /// <summary>
        /// Calculate the right measure spec for this child.
        /// Does the hard part of MeasureChildren: figuring out the MeasureSpec to
        /// pass to a particular child. This method figures out the right MeasureSpec
        /// for one dimension (height or width) of one child view.<br />
        /// </summary>
        /// <param name="parentMeasureSpec">The requirements for this view. MeasureSpecification.</param>
        /// <param name="padding">The padding of this view for the current dimension and margins, if applicable. LayoutLength.</param>
        /// <param name="childDimension"> How big the child wants to be in the current dimension. LayoutLength.</param>
        /// <returns>a MeasureSpec for the child.</returns>
        public static MeasureSpecification GetChildMeasureSpecification(MeasureSpecification parentMeasureSpec, LayoutLength padding, LayoutLength childDimension)
        {
            MeasureSpecification.ModeType specMode   = parentMeasureSpec.Mode;
            MeasureSpecification.ModeType resultMode = MeasureSpecification.ModeType.Unspecified;
            LayoutLength resultSize = new LayoutLength(Math.Max(0.0f, (parentMeasureSpec.Size.AsDecimal() - padding.AsDecimal())));    // reduce available size by the owners padding

            switch (specMode)
            {
            // Parent has imposed an exact size on us
            case MeasureSpecification.ModeType.Exactly:
            {
                if ((int)childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                {
                    // Child wants to be our size. So be it.
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }
                else if ((int)childDimension.AsRoundedValue() == LayoutParamPolicies.WrapContent)
                {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else
                {
                    resultSize = childDimension;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }

                break;
            }

            // Parent has imposed a maximum size on us
            case MeasureSpecification.ModeType.AtMost:
            {
                if (childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                {
                    // Child wants to be our size, but our size is not fixed.
                    // Constrain child to not be bigger than us.
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else if (childDimension.AsRoundedValue() == LayoutParamPolicies.WrapContent)
                {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else
                {
                    // Child wants a specific size... so be it
                    resultSize = childDimension + padding;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }

                break;
            }

            // Parent asked to see how big we want to be
            case MeasureSpecification.ModeType.Unspecified:
            {
                if ((childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent))
                {
                    // Child wants to be our size... find out how big it should be
                    resultMode = MeasureSpecification.ModeType.Unspecified;
                }
                else if (childDimension.AsRoundedValue() == (LayoutParamPolicies.WrapContent))
                {
                    // Child wants to determine its own size.... find out how big
                    // it should be
                    resultMode = MeasureSpecification.ModeType.Unspecified;
                }
                else
                {
                    // Child wants a specific size... let him have it
                    resultSize = childDimension + padding;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }
                break;
            }
            } // switch

            return(new MeasureSpecification(resultSize, resultMode));
        }
예제 #10
0
        /// <summary>
        /// Calculate the right measure spec for this child.
        /// Does the hard part of MeasureChildren: figuring out the MeasureSpec to
        /// pass to a particular child. This method figures out the right MeasureSpec
        /// for one dimension (height or width) of one child view.<br />
        /// </summary>
        /// <param name="parentMeasureSpec">The requirements for this view. MeasureSpecification.</param>
        /// <param name="padding">The padding of this view for the current dimension and margins, if applicable. LayoutLength.</param>
        /// <param name="childDimension"> How big the child wants to be in the current dimension. LayoutLength.</param>
        /// <returns>a MeasureSpec for the child.</returns>
        public static MeasureSpecification GetChildMeasureSpecification(MeasureSpecification parentMeasureSpec, LayoutLength padding, LayoutLength childDimension)
        {
            MeasureSpecification.ModeType specMode   = parentMeasureSpec.Mode;
            MeasureSpecification.ModeType resultMode = MeasureSpecification.ModeType.Unspecified;

            // Child only can use parent's size without parent's padding and own margin.
            LayoutLength resultSize = new LayoutLength(Math.Max(0.0f, (parentMeasureSpec.Size - padding).AsDecimal()));

            switch (specMode)
            {
            // Parent has imposed an exact size on us
            case MeasureSpecification.ModeType.Exactly:
            {
                if ((int)childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                {
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }
                else if ((int)childDimension.AsRoundedValue() == LayoutParamPolicies.WrapContent)
                {
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else
                {
                    resultSize = childDimension;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }

                break;
            }

            // Parent has imposed a maximum size on us
            case MeasureSpecification.ModeType.AtMost:
            {
                if (childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                {
                    // Crashed. Cannot calculate.

                    // Child wants to be our size, but our size is not fixed.
                    // Constrain child to not be bigger than us.
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else if (childDimension.AsRoundedValue() == LayoutParamPolicies.WrapContent)
                {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.

                    // Don't need parent's size. Size of this child will be determined by its children.
                    resultMode = MeasureSpecification.ModeType.AtMost;
                }
                else
                {
                    // Child wants a specific size... so be it
                    resultSize = childDimension;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }

                break;
            }

            // Parent asked to see how big we want to be
            case MeasureSpecification.ModeType.Unspecified:
            {
                if ((childDimension.AsRoundedValue() == LayoutParamPolicies.MatchParent))
                {
                    // Child wants to be our size... find out how big it should be

                    // There is no one who has exact size in parent hierarchy.
                    // Cannot calculate.
                    resultMode = MeasureSpecification.ModeType.Unspecified;
                }
                else if (childDimension.AsRoundedValue() == (LayoutParamPolicies.WrapContent))
                {
                    // Child wants to determine its own size.... find out how big
                    // it should be
                    resultMode = MeasureSpecification.ModeType.Unspecified;
                }
                else
                {
                    // Child wants a specific size... let him have it
                    resultSize = childDimension;
                    resultMode = MeasureSpecification.ModeType.Exactly;
                }
                break;
            }
            } // switch

            return(new MeasureSpecification(resultSize, resultMode));
        }
예제 #11
0
        /// <summary>
        /// Measure the layout and its content to determine the measured width and the measured height.<br />
        /// </summary>
        /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
        /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
        /// <since_tizen> 6 </since_tizen>
        protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
        {
            bool    isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
            Extents padding     = Owner.Padding;
            Extents margin      = Owner.Margin;

            Interop.FlexLayout.FlexLayout_SetMargin(swigCPtr, Extents.getCPtr(margin));
            Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding));

            float width  = FlexUndefined; // Behaves as WrapContent (Flex Auto)
            float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)

            if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
            {
                width = widthMeasureSpec.Size.AsDecimal();
            }

            if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
            {
                height = heightMeasureSpec.Size.AsDecimal();
            }

            // Save measureSpec to measure children.
            // In other Layout, we can pass it as parameter to measuring child but in FlexLayout we can't
            // because measurChild function is called by native callback.
            parentMeasureSpecificationWidth  = widthMeasureSpec;
            parentMeasureSpecificationHeight = heightMeasureSpec;

            // Assign child properties
            for (int i = 0; i < LayoutChildren.Count; i++)
            {
                LayoutItem layoutItem     = LayoutChildren[i];
                View       Child          = layoutItem?.Owner;
                HandleRef  childHandleRef = (HandleRef)Child.GetValue(FlexItemProperty);
                if (childHandleRef.Handle == IntPtr.Zero || Child == null)
                {
                    continue;
                }

                AlignmentType flexAlignemnt   = GetFlexAlignmentSelf(Child);
                PositionType  flexPosition    = GetFlexPositionType(Child);
                float         flexAspectRatio = GetFlexAspectRatio(Child);
                float         flexBasis       = GetFlexBasis(Child);
                float         flexShrink      = GetFlexShrink(Child);
                float         flexGrow        = GetFlexGrow(Child);

                Interop.FlexLayout.FlexLayout_SetFlexAlignmentSelf(childHandleRef, (int)flexAlignemnt);
                Interop.FlexLayout.FlexLayout_SetFlexPositionType(childHandleRef, (int)flexPosition);
                Interop.FlexLayout.FlexLayout_SetFlexAspectRatio(childHandleRef, flexAspectRatio);
                Interop.FlexLayout.FlexLayout_SetFlexBasis(childHandleRef, flexBasis);
                Interop.FlexLayout.FlexLayout_SetFlexShrink(childHandleRef, flexShrink);
                Interop.FlexLayout.FlexLayout_SetFlexGrow(childHandleRef, flexGrow);
            }

            Interop.FlexLayout.FlexLayout_CalculateLayout(swigCPtr, width, height, isLayoutRtl);

            LayoutLength flexLayoutWidth  = new LayoutLength(Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr));
            LayoutLength flexLayoutHeight = new LayoutLength(Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr));

            Debug.WriteLineIf(LayoutDebugFlex, "FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue()
                              + " height:" + flexLayoutHeight.AsRoundedValue());

            SetMeasuredDimensions(GetDefaultSize(flexLayoutWidth, widthMeasureSpec),
                                  GetDefaultSize(flexLayoutHeight, heightMeasureSpec));
        }
예제 #12
0
        } // MeasureHorizontally

        void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
        {
            var   widthMode           = widthMeasureSpec.Mode;
            var   heightMode          = heightMeasureSpec.Mode;
            bool  isExactly           = (heightMode == MeasureSpecification.ModeType.Exactly);
            bool  matchWidth          = false;
            bool  allFillParent       = true;
            float maxWidth            = 0.0f;
            float alternativeMaxWidth = 0.0f;
            float weightedMaxWidth    = 0.0f;
            float totalWeight         = 0.0f;

            // Reset total length
            _totalLength = 0.0f;
            LayoutLength usedExcessSpace = new LayoutLength(0);

            HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
                                                                     MeasuredSize.StateType.MeasuredSizeTooSmall);


            // measure children, and determine if further resolution is required

            // 1st phase:
            // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
            // to accumulate total used space in mTotalLength based on measured sizes and margins.
            // Weighted children are not measured at this phase.
            // Available space for weighted children will be calculated in the phase 2 based on mTotalLength value.
            uint index = 0;

            foreach (LayoutItem childLayout in _children)
            {
                LayoutLength childDesiredWidth  = new LayoutLength(childLayout.Owner.WidthSpecification);
                LayoutLength childDesiredHeight = new LayoutLength(childLayout.Owner.HeightSpecification);
                float        childWeight        = childLayout.Owner.Weight;
                Extents      childMargin        = childLayout.Margin;
                totalWeight += childWeight;

                bool useExcessSpace = (childDesiredHeight.AsRoundedValue() == 0) && (childWeight > 0);

                if (isExactly && useExcessSpace)
                {
                    LayoutLength totalLength = new LayoutLength(_totalLength);
                    _totalLength = Math.Max(totalLength.AsDecimal(), (totalLength + childMargin.Top + childMargin.Bottom).AsDecimal());
                }
                else
                {
                    LayoutLength childHeight = new LayoutLength(0);
                    if (useExcessSpace)
                    {
                        // The heightMode is either Unspecified or AtMost, and
                        // this child is only laid out using excess space. Measure
                        // using WrapContent so that we can find out the view's
                        // optimal height. We'll restore the original height of 0
                        // after measurement.
                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec,
                                                                                                  new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
                                                                                                  childDesiredWidth);
                        MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(heightMeasureSpec,
                                                                                                   new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
                                                                                                   new LayoutLength(LayoutParamPolicies.WrapContent));
                        childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
                        childHeight      = childLayout.MeasuredHeight.Size;
                        usedExcessSpace += childHeight;
                    }
                    else
                    {
                        MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
                        childHeight = childLayout.MeasuredHeight.Size;
                    }

                    float length      = (childHeight + childMargin.Top + childMargin.Bottom).AsDecimal();
                    float cellPadding = CellPadding.Height;
                    // No need to add cell padding to the end of last item.
                    if (index >= _children.Count - 1)
                    {
                        cellPadding = 0.0f;
                    }
                    _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding);
                }

                bool matchWidthLocally = false;
                if (widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth == new LayoutLength(LayoutParamPolicies.MatchParent))
                {
                    // Will have to re-measure at least this child when we know exact height.
                    matchWidth        = true;
                    matchWidthLocally = true;
                }

                float        marginWidth = (childLayout.Margin.Start) + (childLayout.Margin.End);
                LayoutLength childWidth  = new LayoutLength(childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth);

                // was combineMeasuredStates()
                if (childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
                {
                    childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
                }
                if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
                {
                    childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
                }

                maxWidth      = (Math.Max(maxWidth, childWidth.AsDecimal()));
                allFillParent = (allFillParent && (childDesiredWidth == new LayoutLength(LayoutParamPolicies.MatchParent)));

                float widthforWeight = childWidth.AsDecimal();
                if (matchWidthLocally)
                {
                    widthforWeight = marginWidth;
                }

                if (childWeight > 0)
                {
                    /*
                     * Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
                     */
                    weightedMaxWidth = Math.Max(weightedMaxWidth, widthforWeight);
                }
                else
                {
                    alternativeMaxWidth = Math.Max(alternativeMaxWidth, widthforWeight);
                }
            } // foreach


            Extents padding = Padding;

            _totalLength += padding.Top + padding.Bottom;
            LayoutLength heightSize = new LayoutLength(_totalLength);

            heightSize = new LayoutLength(Math.Max(heightSize.AsDecimal(), SuggestedMinimumHeight.AsDecimal()));
            MeasuredSize heightSizeAndState = ResolveSizeAndState(heightSize, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);

            heightSize = heightSizeAndState.Size;

            // Either expand children with weight to take up available space or
            // shrink them if they extend beyond our current bounds. If we skipped
            // measurement on any children, we need to measure them now.

            // 2nd phase:
            // We cycle through weighted children now (children with weight > 0).
            // The children are measured with exact size equal to their share of the available space based on their weights.
            // TotalLength is updated to include weighted children measured sizes.

            float remainingExcess = heightSize.AsDecimal() - _totalLength + usedExcessSpace.AsDecimal();

            if (remainingExcess != 0 && totalWeight > 0.0f)
            {
                float remainingWeightSum = totalWeight;

                _totalLength = 0;

                foreach (LayoutItem childLayout in _children)
                {
                    int     desiredWidth  = childLayout.Owner.WidthSpecification;
                    int     desiredHeight = childLayout.Owner.HeightSpecification;
                    float   childWeight   = childLayout.Owner.Weight;
                    Extents childMargin   = childLayout.Margin;

                    float childHeight = 0;
                    if (childWeight > 0)
                    {
                        float share = (childWeight * remainingExcess) / remainingWeightSum;
                        remainingExcess    -= share;
                        remainingWeightSum -= childWeight;

                        // Always lay out weighted elements with intrinsic size regardless of the parent spec
                        // for consistency between specs.
                        if (desiredHeight == 0)
                        {
                            // This child needs to be laid out from scratch using
                            // only its share of excess space.
                            childHeight = share;
                        }
                        else
                        {
                            // This child had some intrinsic width to which we
                            // need to add its share of excess space.
                            childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + share;
                        }

                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec,
                                                                                                  new LayoutLength(Padding.Start + Padding.End),
                                                                                                  new LayoutLength(desiredWidth));

                        MeasureSpecification childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childHeight), MeasureSpecification.ModeType.Exactly);
                        childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);

                        // Child may now not fit in vertical dimension.
                        if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
                        {
                            childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
                        }
                    }

                    bool matchWidthLocally = false;
                    if (widthMode != MeasureSpecification.ModeType.Exactly && desiredWidth == (int)ChildLayoutData.MatchParent)
                    {
                        // Will have to re-measure at least this child when we know exact height.
                        matchWidth        = true;
                        matchWidthLocally = true;
                    }

                    float marginWidth = childMargin.Start + childMargin.End;
                    float childWidth  = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
                    maxWidth      = Math.Max(maxWidth, childWidth);
                    allFillParent = allFillParent && desiredWidth == (int)ChildLayoutData.MatchParent;


                    alternativeMaxWidth = Math.Max(alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth);

                    childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
                    float length      = childHeight + childMargin.Top + childMargin.Bottom;
                    float cellPadding = CellPadding.Height;
                    // No need to add cell padding to the end of last item.
                    if (index >= _children.Count - 1)
                    {
                        cellPadding = 0.0f;
                    }
                    _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding);
                } // foreach

                // Add in our padding
                _totalLength += Padding.Top + Padding.Bottom;
            }
            else
            {
                alternativeMaxWidth = Math.Max(alternativeMaxWidth, weightedMaxWidth);
            }

            if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
            {
                maxWidth = alternativeMaxWidth;
            }
            maxWidth += padding.Start + padding.End;
            maxWidth  = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());

            heightSizeAndState.State = childState.heightState;

            SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
                                  heightSizeAndState);

            if (matchWidth)
            {
                ForceUniformWidth(_children.Count, heightMeasureSpec);
            }
        } // MeasureVertically
예제 #13
0
        private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
        {
            var   widthMode            = widthMeasureSpec.Mode;
            var   heightMode           = heightMeasureSpec.Mode;
            bool  isExactly            = (widthMode == MeasureSpecification.ModeType.Exactly);
            bool  matchHeight          = false;
            bool  allFillParent        = true;
            float maxHeight            = 0.0f;
            float alternativeMaxHeight = 0.0f;
            float weightedMaxHeight    = 0.0f;
            float totalWeight          = 0.0f;

            // Reset total length
            _totalLength = 0.0f;
            LayoutLength usedExcessSpace = new LayoutLength(0);

            HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
                                                                     MeasuredSize.StateType.MeasuredSizeOK);

            // Measure children, and determine if further resolution is required

            // 1st phase:
            // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
            // to accumulate total used space in totalLength based on measured sizes and margins.
            // Weighted children are not measured at this phase.
            // Available space for weighted children will be calculated in the phase 2 based on totalLength value.

            foreach (LayoutItem childLayout in _children)
            {
                LayoutLength childDesiredWidth  = new LayoutLength(childLayout.Owner.WidthSpecification);
                LayoutLength childDesiredHeight = new LayoutLength(childLayout.Owner.HeightSpecification);
                float        childWeight        = childLayout.Owner.Weight;
                Extents      childMargin        = childLayout.Margin;
                totalWeight += childWeight;

                bool useExcessSpace = (childDesiredWidth.AsRoundedValue() == 0) && (childWeight > 0);
                if (isExactly && useExcessSpace)
                {
                    _totalLength += childMargin.Start + childMargin.End;
                }
                else
                {
                    if (useExcessSpace)
                    {
                        // The widthMode is either UNSPECIFIED or AT_MOST, and
                        // this child is only laid out using excess space. Measure
                        // using WRAP_CONTENT so that we can find out the view's
                        // optimal width.
                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec, new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
                                                                                                  new LayoutLength(LayoutParamPolicies.WrapContent));
                        MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(heightMeasureSpec, new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
                                                                                                   childDesiredHeight);
                        childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
                        usedExcessSpace += childLayout.MeasuredWidth.Size;
                    }
                    else
                    {
                        MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
                    }
                    LayoutLength childWidth = childLayout.MeasuredWidth.Size;

                    LayoutLength length = childWidth + childMargin.Start + childMargin.End;
                    if (isExactly)
                    {
                        _totalLength += length.AsDecimal();
                    }
                    else
                    {
                        _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Width);
                    }
                }

                bool matchHeightLocally = false;
                if (heightMode != MeasureSpecification.ModeType.Exactly && (int)childDesiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent)
                {
                    // Will have to re-measure at least this child when we know exact height.
                    matchHeight        = true;
                    matchHeightLocally = true;
                }

                LayoutLength marginHeight = new LayoutLength(childMargin.Top + childMargin.Bottom);
                LayoutLength childHeight  = childLayout.MeasuredHeight.Size + marginHeight;

                if (childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
                {
                    childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
                }
                if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
                {
                    childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
                }

                maxHeight     = Math.Max(maxHeight, childHeight.AsDecimal());
                allFillParent = (allFillParent && childDesiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent);

                if (childWeight > 0)
                {
                    /*
                     * Heights of weighted Views are bogus if we end up
                     * remeasuring, so keep them separate.
                     */
                    weightedMaxHeight = Math.Max(weightedMaxHeight, matchHeightLocally ? marginHeight.AsDecimal() : childHeight.AsDecimal());
                }
                else
                {
                    alternativeMaxHeight = Math.Max(alternativeMaxHeight, matchHeightLocally ? marginHeight.AsDecimal() : childHeight.AsDecimal());
                }
            } // foreach

            Extents padding = Padding;

            _totalLength += padding.Start + padding.End;
            LayoutLength widthSize = new LayoutLength(_totalLength);

            widthSize = new LayoutLength(Math.Max(widthSize.AsDecimal(), SuggestedMinimumWidth.AsDecimal()));
            MeasuredSize widthSizeAndState = ResolveSizeAndState(widthSize, widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);

            widthSize = widthSizeAndState.Size;

            if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
            {
                maxHeight = alternativeMaxHeight;
            }
            maxHeight += padding.Top + padding.Bottom;
            maxHeight  = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());

            widthSizeAndState.State = childState.widthState;

            SetMeasuredDimensions(widthSizeAndState,
                                  ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));

            if (matchHeight)
            {
                ForceUniformHeight(_children.Count, widthMeasureSpec);
            }
        } // MeasureHorizontally