/* Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using Tizen.NUI.BaseComponents;
using System.Collections.Generic;
namespace Tizen.NUI
{
///
/// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
///
internal class LinearLayout : LayoutGroup
{
///
/// [Draft] Enumeration for the direction in which the content is laid out
///
public enum Orientation
{
///
/// Horizontal (row)
///
Horizontal,
///
/// Vertical (column)
///
Vertical
}
///
/// [Draft] Enumeration for the alignment of the linear layout items
///
public enum Alignment
{
///
/// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
///
Begin = 0x1,
///
/// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
///
End = 0x2,
///
/// At the horizontal center of the container
///
CenterHorizontal = 0x4,
///
/// At the top edge of the container
///
Top = 0x8,
///
/// At the bottom edge of the container
///
Bottom = 0x10,
///
/// At the vertical center of the container
///
CenterVertical = 0x20
}
struct HeightAndWidthState
{
public MeasuredSize.StateType widthState;
public MeasuredSize.StateType heightState;
public HeightAndWidthState( MeasuredSize.StateType width, MeasuredSize.StateType height)
{
widthState = width;
heightState = height;
}
}
///
/// [Draft] Get/Set the orientation in the layout
///
public LinearLayout.Orientation LinearOrientation
{
get
{
return _linearOrientation;
}
set
{
_linearOrientation = value;
RequestLayout();
}
}
///
/// [Draft] Get/Set the padding between cells in the layout
///
public Size2D CellPadding
{
get
{
return _cellPadding;
}
set
{
_cellPadding = value;
RequestLayout();
}
}
///
/// [Draft] Get/Set the alignment in the layout
///
public LinearLayout.Alignment LinearAlignment{ get; set; } = Alignment.CenterVertical;
private float _totalLength = 0.0f;
private Size2D _cellPadding = new Size2D(0,0);
private Orientation _linearOrientation = Orientation.Horizontal;
///
/// [Draft] Constructor
///
public LinearLayout()
{
}
protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
{
if (_linearOrientation == Orientation.Horizontal)
{
MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
else
{
MeasureVertical(widthMeasureSpec, heightMeasureSpec);
}
}
protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
{
if (_linearOrientation == Orientation.Horizontal)
{
LayoutHorizontal(left, top, right, bottom);
}
else
{
LayoutVertical(left, top, right, bottom);
}
}
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
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
void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
{
bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
LayoutLength childTop = new LayoutLength(Padding.Top);
LayoutLength childLeft = new LayoutLength(Padding.Start);
// Where bottom of child should go
LayoutLength height = new LayoutLength(bottom - top);
// Space available for child
LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
int count = _children.Count;
switch (LinearAlignment)
{
case Alignment.Begin:
default:
// totalLength contains the padding already
// In case of RTL map BEGIN alignment to the right edge
if (isLayoutRtl)
{
childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
}
else
{
childLeft = new LayoutLength(Padding.Start);
}
break;
case Alignment.End:
// totalLength contains the padding already
// In case of RTL map END alignment to the left edge
if (isLayoutRtl)
{
childLeft = new LayoutLength(Padding.Start);
}
else
{
childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
}
break;
case Alignment.CenterHorizontal:
// totalLength contains the padding already
childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
break;
}
int start = 0;
int dir = 1;
// In case of RTL, start drawing from the last child.
if (isLayoutRtl)
{
start = count - 1;
dir = -1;
}
for( int i = 0; i < count; i++)
{
int childIndex = start + dir * i;
// Get a reference to the childLayout at the given index
LayoutItem childLayout = _children[childIndex];
if( childLayout != null )
{
LayoutLength childWidth = childLayout.MeasuredWidth.Size;
LayoutLength childHeight = childLayout.MeasuredHeight.Size;
Extents childMargin = childLayout.Margin;
switch ( LinearAlignment )
{
case Alignment.Top:
childTop = new LayoutLength(Padding.Top + childMargin.Top);
break;
case Alignment.Bottom:
childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
break;
case Alignment.CenterVertical: // FALLTHROUGH
default:
childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
break;
}
childLeft += childMargin.Start;
childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + childMargin.End + CellPadding.Width;
}
}
} // LayoutHorizontally
void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
{
LayoutLength childTop = new LayoutLength(Padding.Top);
LayoutLength childLeft = new LayoutLength(Padding.Start);
// Where end of child should go
LayoutLength width = new LayoutLength(right - left);
// Space available for child
LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
int count = _children.Count;
switch (LinearAlignment)
{
case Alignment.Top:
// totalLength contains the padding already
childTop = new LayoutLength( Padding.Top );
break;
case Alignment.Bottom:
// totalLength contains the padding already
childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
break;
case Alignment.CenterVertical:
default:
// totalLength contains the padding already
childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
break;
}
for( int i = 0; i < count; i++)
{
LayoutItem childLayout = _children[i];
if( childLayout != null )
{
LayoutLength childWidth = childLayout.MeasuredWidth.Size;
LayoutLength childHeight = childLayout.MeasuredHeight.Size;
Extents childMargin = childLayout.Margin;
childTop += childMargin.Top;
switch ( LinearAlignment )
{
case Alignment.Begin:
default:
{
childLeft = new LayoutLength(Padding.Start + childMargin.Start);
break;
}
case Alignment.End:
{
childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
break;
}
case Alignment.CenterHorizontal:
{
childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
break;
}
}
childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
childTop += childHeight + childMargin.Bottom + CellPadding.Height;
}
}
} // 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();
}
}
}
}
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();
}
}
}
}
} //LinearLayout
} // namespace