[NUI] Change RelativeLayout's default offset values
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Layouting / RelativeLayout.cs
1 /* Copyright (c) 2020 Samsung Electronics Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  */
16 using System;
17 using System.ComponentModel;
18 using Tizen.NUI.BaseComponents;
19 using Tizen.NUI.Binding;
20
21 namespace Tizen.NUI
22 {
23     /// <summary>
24     /// RelativeLayout calculates the size and position of all the children based on their relationship to each other.
25     /// </summary>
26     /// <since_tizen> 9 </since_tizen>
27     public partial class RelativeLayout : LayoutGroup
28     {
29         /// <summary>
30         /// LeftTargetProperty
31         /// </summary>
32         [EditorBrowsable(EditorBrowsableState.Never)]
33         public static readonly BindableProperty LeftTargetProperty = BindableProperty.CreateAttached("LeftTarget", typeof(View), typeof(RelativeLayout), null, propertyChanged: OnChildPropertyChanged);
34
35         /// <summary>
36         /// RightTargetProperty
37         /// </summary>
38         [EditorBrowsable(EditorBrowsableState.Never)]
39         public static readonly BindableProperty RightTargetProperty = BindableProperty.CreateAttached("RightTarget", typeof(View), typeof(RelativeLayout), null, propertyChanged: OnChildPropertyChanged);
40
41         /// <summary>
42         /// TopTargetProperty
43         /// </summary>
44         [EditorBrowsable(EditorBrowsableState.Never)]
45         public static readonly BindableProperty TopTargetProperty = BindableProperty.CreateAttached("TopTarget", typeof(View), typeof(RelativeLayout), null, propertyChanged: OnChildPropertyChanged);
46
47         /// <summary>
48         /// BottomTargetProperty
49         /// </summary>
50         [EditorBrowsable(EditorBrowsableState.Never)]
51         public static readonly BindableProperty BottomTargetProperty = BindableProperty.CreateAttached("BottomTarget", typeof(View), typeof(RelativeLayout), null, propertyChanged: OnChildPropertyChanged);
52
53         /// <summary>
54         /// LeftRelativeOffsetProperty
55         /// </summary>
56         [EditorBrowsable(EditorBrowsableState.Never)]
57         public static readonly BindableProperty LeftRelativeOffsetProperty = BindableProperty.CreateAttached("LeftRelativeOffset", typeof(float), typeof(RelativeLayout), 0.0f, propertyChanged: OnChildPropertyChanged);
58
59         /// <summary>
60         /// RightRelativeOffsetProperty
61         /// </summary>
62         [EditorBrowsable(EditorBrowsableState.Never)]
63         public static readonly BindableProperty RightRelativeOffsetProperty = BindableProperty.CreateAttached("RightRelativeOffset", typeof(float), typeof(RelativeLayout), 1.0f, propertyChanged: OnChildPropertyChanged);
64
65         /// <summary>
66         /// TopRelativeOffsetProperty
67         /// </summary>
68         [EditorBrowsable(EditorBrowsableState.Never)]
69         public static readonly BindableProperty TopRelativeOffsetProperty = BindableProperty.CreateAttached("TopRelativeOffset", typeof(float), typeof(RelativeLayout), 0.0f, propertyChanged: OnChildPropertyChanged);
70
71         /// <summary>
72         /// BottomRelativeOffsetProperty
73         /// </summary>
74         [EditorBrowsable(EditorBrowsableState.Never)]
75         public static readonly BindableProperty BottomRelativeOffsetProperty = BindableProperty.CreateAttached("BottomRelativeOffset", typeof(float), typeof(RelativeLayout), 1.0f, propertyChanged: OnChildPropertyChanged);
76
77         /// <summary>
78         /// HorizontalAlignmentProperty
79         /// </summary>
80         [EditorBrowsable(EditorBrowsableState.Never)]
81         public static readonly BindableProperty HorizontalAlignmentProperty = BindableProperty.CreateAttached("HorizontalAlignment", typeof(Alignment), typeof(RelativeLayout), default(Alignment), propertyChanged: OnChildPropertyChanged);
82
83         /// <summary>
84         /// VerticalAlignmentProperty
85         /// </summary>
86         [EditorBrowsable(EditorBrowsableState.Never)]
87         public static readonly BindableProperty VerticalAlignmentProperty = BindableProperty.CreateAttached("VerticalAlignment", typeof(Alignment), typeof(RelativeLayout), default(Alignment), propertyChanged: OnChildPropertyChanged);
88
89         /// <summary>
90         /// FillHorizontalProperty
91         /// </summary>
92         [EditorBrowsable(EditorBrowsableState.Never)]
93         public static readonly BindableProperty FillHorizontalProperty = BindableProperty.CreateAttached("FillHorizontal", typeof(bool), typeof(RelativeLayout), false, propertyChanged: OnChildPropertyChanged);
94
95         /// <summary>
96         /// FillVerticalProperty
97         /// </summary>
98         [EditorBrowsable(EditorBrowsableState.Never)]
99         public static readonly BindableProperty FillVerticalProperty = BindableProperty.CreateAttached("FillVertical", typeof(bool), typeof(RelativeLayout), false, propertyChanged: OnChildPropertyChanged);
100
101         /// <summary>
102         /// Constructor
103         /// </summary>
104         /// <since_tizen> 9 </since_tizen>
105         public RelativeLayout() { }
106
107         /// <summary>
108         /// Gets left target object whose size and position is being used as reference.
109         /// </summary>
110         /// <param name="view">The child view whose size and position is being changed.</param>
111         /// <returns>The object whose size and position is being used as reference.</returns>
112         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
113         /// <since_tizen> 9 </since_tizen>
114         [Binding.TypeConverter(typeof(RelativeTargetConverter))]
115         public static View GetLeftTarget(BindableObject view) => GetAttachedValue<View>(view, LeftTargetProperty);
116
117         /// <summary>
118         /// Gets right target object whose size and position is being used as reference.
119         /// </summary>
120         /// <param name="view">The child view whose size and position is being changed.</param>
121         /// <returns>The object whose size and position is being used as reference.</returns>
122         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
123         /// <since_tizen> 9 </since_tizen>
124         [Binding.TypeConverter(typeof(RelativeTargetConverter))]
125         public static View GetRightTarget(BindableObject view) => GetAttachedValue<View>(view, RightTargetProperty);
126
127         /// <summary>
128         /// Gets top target object whose size and position is being used as reference.
129         /// </summary>
130         /// <param name="view">The child view whose size and position is being changed.</param>
131         /// <returns>The object whose size and position is being used as reference.</returns>
132         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
133         /// <since_tizen> 9 </since_tizen>
134         [Binding.TypeConverter(typeof(RelativeTargetConverter))]
135         public static View GetTopTarget(BindableObject view) => GetAttachedValue<View>(view, TopTargetProperty);
136
137         /// <summary>
138         /// Gets bottom target object whose size and position is being used as reference.
139         /// </summary>
140         /// <param name="view">The child view whose size and position is being changed.</param>
141         /// <returns>The object whose size and position is being used as reference.</returns>
142         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
143         /// <since_tizen> 9 </since_tizen>
144         [Binding.TypeConverter(typeof(RelativeTargetConverter))]
145         public static View GetBottomTarget(BindableObject view) => GetAttachedValue<View>(view, BottomTargetProperty);
146
147         /// <summary>
148         /// Gets left relative offset.
149         /// </summary>
150         /// <param name="view">The child view whose size and position is being changed.</param>
151         /// <returns>The ratio between left and right of the <seealso cref="LeftTargetProperty"/>.</returns>
152         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
153         /// <since_tizen> 9 </since_tizen>
154         public static float GetLeftRelativeOffset(View view) => GetAttachedValue<float>(view, LeftRelativeOffsetProperty);
155
156         /// <summary>
157         /// Gets right relative offset.
158         /// </summary>
159         /// <param name="view">The child view whose size and position is being changed.</param>
160         /// <returns>The ratio between left and right of the <seealso cref="RightTargetProperty"/>.</returns>
161         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
162         /// <since_tizen> 9 </since_tizen>
163         public static float GetRightRelativeOffset(View view) => GetAttachedValue<float>(view, RightRelativeOffsetProperty);
164
165         /// <summary>
166         /// Gets top relative offset.
167         /// </summary>
168         /// <param name="view">The child view whose size and position is being changed.</param>
169         /// <returns>The ratio between top and bottom of the <seealso cref="TopTargetProperty"/>.</returns>
170         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
171         /// <since_tizen> 9 </since_tizen>
172         public static float GetTopRelativeOffset(View view) => GetAttachedValue<float>(view, TopRelativeOffsetProperty);
173
174         /// <summary>
175         /// Gets bottom relative offset.
176         /// </summary>
177         /// <param name="view">The child view whose size and position is being changed.</param>
178         /// <returns>The ratio between top and bottom of the <seealso cref="BottomTargetProperty"/>.</returns>
179         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
180         /// <since_tizen> 9 </since_tizen>
181         public static float GetBottomRelativeOffset(View view) => GetAttachedValue<float>(view, BottomRelativeOffsetProperty);
182
183         /// <summary>
184         /// Gets the horizontal alignment
185         /// </summary>
186         /// <param name="view">The child view.</param>
187         /// <returns>The horizontal alignment of <paramref name="view"/>.</returns>
188         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
189         /// <since_tizen> 9 </since_tizen>
190         public static Alignment GetHorizontalAlignment(View view) => GetAttachedValue<Alignment>(view, HorizontalAlignmentProperty);
191
192         /// <summary>
193         /// Gets the vertical alignment
194         /// </summary>
195         /// <param name="view">The child view.</param>
196         /// <returns>The vertical alignment of <paramref name="view"/>.</returns>
197         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
198         /// <since_tizen> 9 </since_tizen>
199         public static Alignment GetVerticalAlignment(View view) => GetAttachedValue<Alignment>(view, VerticalAlignmentProperty);
200
201         /// <summary>
202         /// Gets the boolean value whether child fills its horizontal space.
203         /// </summary>
204         /// <param name="view">The child view.</param>
205         /// <returns>True if to fill the space, false otherwise.</returns>
206         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
207         /// <since_tizen> 9 </since_tizen>
208         public static bool GetFillHorizontal(View view) => GetAttachedValue<bool>(view, FillHorizontalProperty);
209
210         /// <summary>
211         /// Gets the boolean value whether child fills its vertical space.
212         /// </summary>
213         /// <param name="view">The child view.</param>
214         /// <returns>True if to fill the space, false otherwise.</returns>
215         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
216         /// <since_tizen> 9 </since_tizen>
217         public static bool GetFillVertical(View view) => GetAttachedValue<bool>(view, FillVerticalProperty);
218
219         /// <summary>
220         /// Specifies the left side edge of the child view relative to the target view. <br/>
221         /// null <paramref name="reference"/> means parent relative layout.
222         /// </summary>
223         /// <param name="view">The child view whose size and position is being changed.</param>
224         /// <param name="reference">The object whose size and position is being used as reference.</param>
225         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
226         /// <since_tizen> 9 </since_tizen>
227         public static void SetLeftTarget(View view, View reference) => SetAttachedValue(view, LeftTargetProperty, reference);
228
229         /// <summary>
230         /// Specifies the right side edge of the child view relative to the target view. <br/>
231         /// null <paramref name="reference"/> means parent relative layout.
232         /// </summary>
233         /// <param name="view">The child view whose size and position is being changed.</param>
234         /// <param name="reference">The object whose size and position is being used as reference.</param>
235         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
236         /// <since_tizen> 9 </since_tizen>
237         public static void SetRightTarget(View view, View reference) => SetAttachedValue(view, RightTargetProperty, reference);
238
239         /// <summary>
240         /// Specifies the top side edge of the child view relative to the target view. <br/>
241         /// null <paramref name="reference"/> means parent relative layout.
242         /// </summary>
243         /// <param name="view">The child view whose size and position is being changed.</param>
244         /// <param name="reference">The object whose size and position is being used as reference.</param>
245         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
246         /// <since_tizen> 9 </since_tizen>
247         public static void SetTopTarget(View view, View reference) => SetAttachedValue(view, TopTargetProperty, reference);
248
249         /// <summary>
250         /// Specifies the bottom side edge of the child view relative to the target view. <br/>
251         /// null <paramref name="reference"/> means parent relative layout.
252         /// </summary>
253         /// <param name="view">The child view whose size and position is being changed.</param>
254         /// <param name="reference">The object whose size and position is being used as reference.</param>
255         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
256         /// <since_tizen> 9 </since_tizen>
257         public static void SetBottomTarget(View view, View reference) => SetAttachedValue(view, BottomTargetProperty, reference);
258
259         /// <summary>
260         /// Sets the relative offset for left target.
261         /// When <paramref name="value"/> is 0 the left edges of the left target and <paramref name="view"/> are aligned.<br/>
262         /// When <paramref name="value"/> is 1 the left edge of the <paramref name="view"/> is aligned to the right edge of the left target.
263         /// </summary>
264         /// <param name="view">The child view whose size and position is being changed.</param>
265         /// <param name="value">The ratio between left and right of the <seealso cref="LeftTargetProperty"/>.</param>
266         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
267         /// <since_tizen> 9 </since_tizen>
268         public static void SetLeftRelativeOffset(View view, float value) => SetAttachedValue(view, LeftRelativeOffsetProperty, value);
269
270         /// <summary>
271         /// Sets the relative offset for right target.
272         /// When <paramref name="value"/> is 0 the right edge of the <paramref name="view"/> is aligned to the left edge of the right target.<br/>
273         /// When <paramref name="value"/> is 1 the right edges of the right target and <paramref name="view"/> are aligned.
274         /// </summary>
275         /// <param name="view">The child view whose size and position is being changed.</param>
276         /// <param name="value">The ratio between left and right of the <seealso cref="RightTargetProperty"/>.</param>
277         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
278         /// <since_tizen> 9 </since_tizen>
279         public static void SetRightRelativeOffset(View view, float value) => SetAttachedValue(view, RightRelativeOffsetProperty, value);
280
281         /// <summary>
282         /// Sets the relative offset for top target.
283         /// When <paramref name="value"/> is 0 the top edges of the top target and <paramref name="view"/> are aligned.<br/>
284         /// When <paramref name="value"/> is 1 the top edge of the <paramref name="view"/> is aligned to the bottom edge of the top target.
285         /// </summary>
286         /// <param name="view">The child view whose size and position is being changed.</param>
287         /// <param name="value">The ratio between left and right of the <seealso cref="TopTargetProperty"/>.</param>
288         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
289         /// <since_tizen> 9 </since_tizen>
290         public static void SetTopRelativeOffset(View view, float value) => SetAttachedValue(view, TopRelativeOffsetProperty, value);
291
292         /// <summary>
293         /// Sets the relative offset for bottom target.
294         /// When <paramref name="value"/> is 0 the bottom edge of the <paramref name="view"/> is aligned to the top edge of the bottom target.<br/>
295         /// When <paramref name="value"/> is 1 the bottom edges of the bottom target and <paramref name="view"/> are aligned.
296         /// </summary>
297         /// <param name="view">The child view whose size and position is being changed.</param>
298         /// <param name="value">The ratio between left and right of the <seealso cref="BottomTargetProperty"/>.</param>
299         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
300         /// <since_tizen> 9 </since_tizen>
301         public static void SetBottomRelativeOffset(View view, float value) => SetAttachedValue(view, BottomRelativeOffsetProperty, value);
302
303         /// <summary>
304         /// Sets the horizontal alignment of this child view.
305         /// </summary>
306         /// <param name="view">The child view.</param>
307         /// <param name="value">The horizontal alignment of <paramref name="view"/>.</param>
308         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
309         /// <since_tizen> 9 </since_tizen>
310         public static void SetHorizontalAlignment(View view, Alignment value) => SetAttachedValue(view, HorizontalAlignmentProperty, value);
311
312         /// <summary>
313         /// Sets the vertical alignment of this child view.
314         /// </summary>
315         /// <param name="view">The child view.</param>
316         /// <param name="value">The vertical alignment of <paramref name="view"/>.</param>
317         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
318         /// <since_tizen> 9 </since_tizen>
319         public static void SetVerticalAlignment(View view, Alignment value) => SetAttachedValue(view, VerticalAlignmentProperty, value);
320
321         /// <summary>
322         /// Sets the boolean value whether child fills its horizontal space.
323         /// </summary>
324         /// <param name="view">The child view.</param>
325         /// <param name="value">True if to fill the space, false otherwise.</param>
326         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
327         /// <since_tizen> 9 </since_tizen>
328         public static void SetFillHorizontal(View view, bool value) => SetAttachedValue(view, FillHorizontalProperty, value);
329
330         /// <summary>
331         /// Sets the boolean value whether child fills its vertical space.
332         /// </summary>
333         /// <param name="view">The child view.</param>
334         /// <param name="value">True if to fill the space, false otherwise.</param>
335         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
336         /// <since_tizen> 9 </since_tizen>
337         public static void SetFillVertical(View view, bool value) => SetAttachedValue(view, FillVerticalProperty, value);
338
339         /// <inheritdoc/>
340         /// <since_tizen> 9 </since_tizen>
341         protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
342         {
343             MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
344             MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
345
346             for (int i = 0; i < LayoutChildren.Count; i++)
347             {
348                 LayoutItem childLayout = LayoutChildren[i];
349                 if (childLayout != null)
350                 {
351                     MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
352
353                     if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
354                     {
355                         childWidthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
356                     }
357                     if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
358                     {
359                         childHeightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
360                     }
361                 }
362             }
363
364             (float childrenWidth, float childrenHeight) = CalculateChildrenSize(widthMeasureSpec.Size.AsDecimal(), heightMeasureSpec.Size.AsDecimal());
365             SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(childrenWidth), widthMeasureSpec, childWidthState),
366                                   ResolveSizeAndState(new LayoutLength(childrenHeight), heightMeasureSpec, childHeightState));
367
368             // There are 2 cases which require to calculate children's MeasuredWidth/Height as follows.
369             //
370             // 1. Text with Ellipsis true
371             //    TextLabel and TextField calculate MeasuredWidth/Height to cover their text string if they have WrapContent.
372             //    This causes children's Ellipsis cannot be displayed with RelativeLayout.
373             //    To resolve the above, RelativeLayout recalculates its children's MeasuredWidth/Height based on the children's space calculated by RelativeLayout APIs.
374             //
375             // 2. FillHorizontal/Vertical true
376             //    If children set FillHorizontal/Vertical true, then children's MeasuredWidth/Height are not correctly alculated.
377             //    Instead, children's size and position are correctly calculated in OnLayout().
378             //    This causes that the grand children's MeasuredWidth/Height are calculated incorrectly.
379             //    To resolve the above, RelativeLayout calculates its children's MeasuredWidth/Height based on the children's geometry calculated by RelativeLayout APIs.
380             //
381             //    e.g.
382             //    Let parent have RelativeLayout and parent's size be 1920x1080.
383             //    Let child have WrapContent with SetFillHorizontal/Vertical true.
384             //    Let grand child have MatchParent.
385             //    Then, child's size is 1920x1080 but child's MeasuredWidth/Height is 0x0.
386             //    Then, grand child's MeasuredWidth/Height is 0x0 and size is 0x0.
387             //
388             // TODO: Not to do duplicate operations in OnLayout() again.
389             bool needClearCache = false;
390
391             for (int i = 0; i < LayoutChildren.Count; i++)
392             {
393                 LayoutItem childLayout = LayoutChildren[i];
394                 if (childLayout != null)
395                 {
396                     bool ellipsisText = false;
397                     bool needMeasuredWidth = false;
398                     bool needMeasuredHeight = false;
399
400                     if (((childLayout.Owner is TextLabel textLabel) && textLabel.Ellipsis) || ((childLayout.Owner is TextField textField) && textField.Ellipsis))
401                     {
402                         ellipsisText = true;
403                         needClearCache = true;
404                     }
405                     else
406                     {
407                         if (RelativeLayout.GetFillHorizontal(childLayout.Owner))
408                         {
409                             needMeasuredWidth = true;
410                             needClearCache = true;
411                         }
412
413                         if (RelativeLayout.GetFillVertical(childLayout.Owner))
414                         {
415                             needMeasuredHeight = true;
416                             needClearCache = true;
417                         }
418                     }
419
420                     if ((ellipsisText == false) && (needMeasuredWidth == false) && (needMeasuredHeight == false))
421                     {
422                         continue;
423                     }
424
425                     float width = childLayout.MeasuredWidth.Size.AsDecimal();
426                     float height = childLayout.MeasuredWidth.Size.AsDecimal();
427
428                     if (ellipsisText)
429                     {
430                         Geometry horizontalSpace = GetHorizontalSpace(childLayout.Owner);
431
432                         if ((width > horizontalSpace.Size) || ((width < horizontalSpace.Size) && RelativeLayout.GetFillVertical(childLayout.Owner)))
433                         {
434                             width = horizontalSpace.Size;
435                         }
436
437                         Geometry verticalSpace = GetVerticalSpace(childLayout.Owner);
438
439                         if ((height > verticalSpace.Size) || ((height < verticalSpace.Size) && RelativeLayout.GetFillHorizontal(childLayout.Owner)))
440                         {
441                             height = verticalSpace.Size;
442                         }
443                     }
444                     else
445                     {
446                         if (needMeasuredWidth)
447                         {
448                             Geometry horizontalGeometry = GetHorizontalLayout(childLayout.Owner);
449                             width = horizontalGeometry.Size;
450                         }
451
452                         if (needMeasuredHeight)
453                         {
454                             Geometry verticalGeometry = GetVerticalLayout(childLayout.Owner);
455                             height = verticalGeometry.Size;
456                         }
457                     }
458
459                     // Padding sizes are added because Padding sizes will be subtracted in MeasureChild().
460                     MeasureSpecification childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(width + Padding.Start + Padding.End), MeasureSpecification.ModeType.Exactly);
461                     MeasureSpecification childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(height + Padding.Top + Padding.Bottom), MeasureSpecification.ModeType.Exactly);
462
463                     // To calculate the grand children's Measure() with the mode type Exactly,
464                     // children's Measure() is called with MatchParent if the children have WrapContent.
465                     //
466                     // i.e.
467                     // If children have Wrapcontent and the grand children have MatchParent,
468                     // then grand children's MeasuredWidth/Height do not fill the children
469                     // because the grand children's Measure() is called with the mode type AtMost.
470                     int origWidthSpecification = childLayout.Owner.WidthSpecification;
471                     int origHeightSpecification = childLayout.Owner.HeightSpecification;
472
473                     if (ellipsisText || needMeasuredWidth)
474                     {
475                         origWidthSpecification = childLayout.Owner.WidthSpecification;
476                         childLayout.Owner.WidthSpecification = LayoutParamPolicies.MatchParent;
477                     }
478                     if (ellipsisText || needMeasuredHeight)
479                     {
480                         origHeightSpecification = childLayout.Owner.HeightSpecification;
481                         childLayout.Owner.HeightSpecification = LayoutParamPolicies.MatchParent;
482                     }
483
484                     MeasureChildWithMargins(childLayout, childWidthMeasureSpec, new LayoutLength(0), childHeightMeasureSpec, new LayoutLength(0));
485
486                     if (ellipsisText || needMeasuredWidth)
487                     {
488                         childLayout.Owner.WidthSpecification = origWidthSpecification;
489                     }
490                     if (ellipsisText || needMeasuredHeight)
491                     {
492                         childLayout.Owner.HeightSpecification = origHeightSpecification;
493                     }
494                 }
495             }
496
497             if (needClearCache)
498             {
499                 HorizontalRelativeCache.Clear();
500                 VerticalRelativeCache.Clear();
501             }
502         }
503
504         /// <inheritdoc/>
505         /// <since_tizen> 9 </since_tizen>
506         protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
507         {
508             for (int i = 0; i < LayoutChildren.Count; i++)
509             {
510                 LayoutItem childLayout = LayoutChildren[i];
511                 if (childLayout != null)
512                 {
513                     Geometry horizontalGeometry = GetHorizontalLayout(childLayout.Owner);
514                     Geometry verticalGeometry = GetVerticalLayout(childLayout.Owner);
515
516                     LayoutLength childLeft = new LayoutLength(horizontalGeometry.Position + Padding.Start + childLayout.Margin.Start);
517                     LayoutLength childRight = new LayoutLength(horizontalGeometry.Position + horizontalGeometry.Size + Padding.Start - childLayout.Margin.End);
518                     LayoutLength childTop = new LayoutLength(verticalGeometry.Position + Padding.Top + childLayout.Margin.Top);
519                     LayoutLength childBottom = new LayoutLength(verticalGeometry.Position + verticalGeometry.Size + Padding.Top - childLayout.Margin.Bottom);
520
521                     childLayout.Layout(childLeft, childTop, childRight, childBottom);
522                 }
523             }
524             HorizontalRelativeCache.Clear();
525             VerticalRelativeCache.Clear();
526         }
527
528         /// <summary>The alignment of the relative layout child.</summary>
529         /// <since_tizen> 9 </since_tizen>
530         public enum Alignment
531         {
532             /// <summary>At the start of the container.</summary>
533             /// <since_tizen> 9 </since_tizen>
534             Start = 0,
535             /// <summary>At the center of the container.</summary>
536             /// <since_tizen> 9 </since_tizen>
537             Center = 1,
538             /// <summary>At the end of the container.</summary>
539             /// <since_tizen> 9 </since_tizen>
540             End = 2,
541         }
542     }
543
544     // Extension Method of RelativeLayout.Alignment.
545     internal static partial class RelativeLayoutAlignmentExtension
546     {
547         public static float ToFloat(this RelativeLayout.Alignment align)
548         {
549             return 0.5f * (float)align;
550         }
551     }
552 }