2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.ComponentModel;
20 namespace Tizen.NUI.Components
23 /// Layout collection of views horizontally/vertically.
25 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
26 [EditorBrowsable(EditorBrowsableState.Never)]
27 public partial class LinearLayoutManager : FlexibleViewLayoutManager
30 /// Constant value: 0.
32 /// <since_tizen> 6 </since_tizen>
33 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
34 [EditorBrowsable(EditorBrowsableState.Never)]
35 public static readonly int HORIZONTAL = OrientationHelper.HORIZONTAL;
37 /// Constant value: 1.
39 /// <since_tizen> 6 </since_tizen>
40 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
41 [EditorBrowsable(EditorBrowsableState.Never)]
42 public static readonly int VERTICAL = OrientationHelper.VERTICAL;
44 /// Constant value: -1.
46 /// <since_tizen> 6 </since_tizen>
47 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
48 [EditorBrowsable(EditorBrowsableState.Never)]
49 public static readonly int NO_POSITION = FlexibleView.NO_POSITION;
51 /// Constant value: -2^31.
53 /// <since_tizen> 6 </since_tizen>
54 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
55 [EditorBrowsable(EditorBrowsableState.Never)]
56 public static readonly int INVALID_OFFSET = -2147483648;
58 private const float MAX_SCROLL_FACTOR = 1 / 3f;
61 /// Current orientation.
63 /// <since_tizen> 6 </since_tizen>
64 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
65 [EditorBrowsable(EditorBrowsableState.Never)]
66 protected int mOrientation;
68 internal OrientationHelper mOrientationHelper;
70 private LayoutState mLayoutState;
71 private AnchorInfo mAnchorInfo = new AnchorInfo();
73 // Stashed to avoid allocation, currently only used in #fill()
74 private LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();
76 private bool mShouldReverseLayout = false;
78 // When LayoutManager needs to scroll to a position, it sets this variable and requests a
79 // layout which will check this variable and re-layout accordingly.
80 private int mPendingScrollPosition = NO_POSITION;
82 // Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
84 private int mPendingScrollPositionOffset = INVALID_OFFSET;
87 /// Creates a LinearLayoutManager with orientation.
89 /// <param name="orientation">Layout orientation.Should be HORIZONTAL or VERTICAL</param>
90 /// <since_tizen> 6 </since_tizen>
91 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
92 [EditorBrowsable(EditorBrowsableState.Never)]
93 public LinearLayoutManager(int orientation)
95 mOrientation = orientation;
96 mOrientationHelper = OrientationHelper.CreateOrientationHelper(this, mOrientation);
98 mLayoutState = new LayoutState();
99 mLayoutState.Offset = mOrientationHelper.GetStartAfterPadding();
103 /// Retrieves the first visible item position.
105 /// <since_tizen> 6 </since_tizen>
106 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
107 [EditorBrowsable(EditorBrowsableState.Never)]
108 public int FirstVisibleItemPosition
112 FlexibleViewViewHolder child = FindFirstVisibleItemView();
113 return child == null ? NO_POSITION : child.LayoutPosition;
118 /// Retrieves the first complete visible item position.
120 /// <since_tizen> 6 </since_tizen>
121 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public int FirstCompleteVisibleItemPosition
127 FlexibleViewViewHolder child = FindFirstCompleteVisibleItemView();
128 return child == null ? NO_POSITION : child.LayoutPosition;
133 /// Retrieves the last visible item position.
135 /// <since_tizen> 6 </since_tizen>
136 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
137 [EditorBrowsable(EditorBrowsableState.Never)]
138 public int LastVisibleItemPosition
142 FlexibleViewViewHolder child = FindLastVisibleItemView();
143 return child == null ? NO_POSITION : child.LayoutPosition;
148 /// Retrieves the last complete visible item position.
150 /// <since_tizen> 6 </since_tizen>
151 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
152 [EditorBrowsable(EditorBrowsableState.Never)]
153 public int LastCompleteVisibleItemPosition
157 FlexibleViewViewHolder child = FindLastCompleteVisibleItemView();
158 return child == null ? NO_POSITION : child.LayoutPosition;
163 /// Query if horizontal scrolling is currently supported. The default implementation returns false.
165 /// <since_tizen> 6 </since_tizen>
166 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
167 [EditorBrowsable(EditorBrowsableState.Never)]
168 public override bool CanScrollHorizontally()
170 return mOrientation == HORIZONTAL;
174 /// Query if vertical scrolling is currently supported. The default implementation returns false.
176 /// <since_tizen> 6 </since_tizen>
177 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
178 [EditorBrowsable(EditorBrowsableState.Never)]
179 public override bool CanScrollVertically()
181 return mOrientation == VERTICAL;
185 /// Lay out all relevant child views from the given adapter.
187 /// <param name="recycler">Recycler to use for fetching potentially cached views for a position</param>
188 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
189 [EditorBrowsable(EditorBrowsableState.Never)]
190 public override void OnLayoutChildren(FlexibleViewRecycler recycler)
192 mLayoutState.Recycle = false;
193 if (!mAnchorInfo.Valid || mPendingScrollPosition != NO_POSITION)
196 mAnchorInfo.LayoutFromEnd = mShouldReverseLayout;
197 // calculate anchor position and coordinate
198 UpdateAnchorInfoForLayout(recycler, mAnchorInfo);
199 mAnchorInfo.Valid = true;
202 int firstLayoutDirection;
203 if (mAnchorInfo.LayoutFromEnd)
205 firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
206 : LayoutState.ITEM_DIRECTION_HEAD;
210 firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
211 : LayoutState.ITEM_DIRECTION_TAIL;
213 EnsureAnchorReady(recycler, mAnchorInfo, firstLayoutDirection);
214 ScrapAttachedViews(recycler);
216 if (mAnchorInfo.LayoutFromEnd == true)
218 UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
219 Fill(recycler, mLayoutState, false, true);
220 Cache(recycler, mLayoutState, true);
222 UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
223 mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
224 Fill(recycler, mLayoutState, false, true);
225 Cache(recycler, mLayoutState, true);
229 UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
230 Fill(recycler, mLayoutState, false, true);
231 Cache(recycler, mLayoutState, true);
233 UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
234 mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
235 Fill(recycler, mLayoutState, false, true);
236 Cache(recycler, mLayoutState, true);
243 /// Scroll horizontally by dy pixels in screen coordinates.
245 /// <param name="dx">distance to scroll in pixels. Y increases as scroll position approaches the top.</param>
246 /// <param name="recycler">Recycler to use for fetching potentially cached views for a position</param>
247 /// <param name="immediate">Specify if the scroll need animation</param>
248 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
249 [EditorBrowsable(EditorBrowsableState.Never)]
250 public override float ScrollHorizontallyBy(float dx, FlexibleViewRecycler recycler, bool immediate)
252 if (mOrientation == VERTICAL)
256 return ScrollBy(dx, recycler, immediate);
260 /// Scroll vertically by dy pixels in screen coordinates.
262 /// <param name="dy">distance to scroll in pixels. Y increases as scroll position approaches the top.</param>
263 /// <param name="recycler">Recycler to use for fetching potentially cached views for a position</param>
264 /// <param name="immediate">Specify if the scroll need animation</param>
265 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
266 [EditorBrowsable(EditorBrowsableState.Never)]
267 public override float ScrollVerticallyBy(float dy, FlexibleViewRecycler recycler, bool immediate)
269 if (mOrientation == HORIZONTAL)
273 return ScrollBy(dy, recycler, immediate);
277 /// Compute the offset of the scrollbar's thumb within the range.
279 /// <since_tizen> 6 </since_tizen>
280 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
281 [EditorBrowsable(EditorBrowsableState.Never)]
282 public override float ComputeScrollOffset()
284 FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
285 FlexibleViewViewHolder endChild = FindLastVisibleItemView();
286 if (ChildCount == 0 || startChild == null || endChild == null)
290 int minPosition = Math.Min(startChild.LayoutPosition, endChild.LayoutPosition);
291 int maxPosition = Math.Max(startChild.LayoutPosition, endChild.LayoutPosition);
292 int itemsBefore = mShouldReverseLayout
293 ? Math.Max(0, ItemCount - maxPosition - 1)
294 : Math.Max(0, minPosition);
296 float laidOutArea = Math.Abs(mOrientationHelper.GetViewHolderEnd(endChild)
297 - mOrientationHelper.GetViewHolderStart(startChild));
298 int itemRange = Math.Abs(startChild.LayoutPosition - endChild.LayoutPosition) + 1;
299 float avgSizePerRow = laidOutArea / itemRange;
301 return (float)Math.Round(itemsBefore * avgSizePerRow + (mOrientationHelper.GetStartAfterPadding()
302 - mOrientationHelper.GetViewHolderStart(startChild)));
306 /// Compute the extent of the scrollbar's thumb within the range.
308 /// <since_tizen> 6 </since_tizen>
309 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
310 [EditorBrowsable(EditorBrowsableState.Never)]
311 public override float ComputeScrollExtent()
313 FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
314 FlexibleViewViewHolder endChild = FindLastVisibleItemView();
315 if (ChildCount == 0 || startChild == null || endChild == null)
319 float extend = mOrientationHelper.GetViewHolderEnd(endChild)
320 - mOrientationHelper.GetViewHolderStart(startChild);
321 return Math.Min(mOrientationHelper.GetTotalSpace(), extend);
325 /// Compute the range that the scrollbar represents.
327 /// <since_tizen> 6 </since_tizen>
328 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
329 [EditorBrowsable(EditorBrowsableState.Never)]
330 public override float ComputeScrollRange()
332 FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
333 FlexibleViewViewHolder endChild = FindLastVisibleItemView();
334 if (ChildCount == 0 || startChild == null || endChild == null)
338 float laidOutArea = mOrientationHelper.GetViewHolderEnd(endChild)
339 - mOrientationHelper.GetViewHolderStart(startChild);
340 int laidOutRange = Math.Abs(startChild.LayoutPosition - endChild.LayoutPosition) + 1;
341 // estimate a size for full list.
342 return laidOutArea / laidOutRange * ItemCount;
346 /// Scroll the FlexibleView to make the position visible.
348 /// <param name="position">Scroll to this adapter position</param>
349 /// <since_tizen> 6 </since_tizen>
350 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
351 [EditorBrowsable(EditorBrowsableState.Never)]
352 public override void ScrollToPosition(int position)
354 mPendingScrollPosition = position;
355 mPendingScrollPositionOffset = INVALID_OFFSET;
361 /// Scroll to the specified adapter position with the given offset from resolved layout start.
363 /// <param name="position">Scroll to this adapter position</param>
364 /// <param name="offset">The distance (in pixels) between the start edge of the item view and start edge of the FlexibleView.</param>
365 /// <since_tizen> 6 </since_tizen>
366 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
367 [EditorBrowsable(EditorBrowsableState.Never)]
368 public override void ScrollToPositionWithOffset(int position, int offset)
370 mPendingScrollPosition = position;
371 mPendingScrollPositionOffset = offset;
377 /// Called after a full layout calculation is finished.
379 /// <since_tizen> 6 </since_tizen>
380 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
381 [EditorBrowsable(EditorBrowsableState.Never)]
382 public override void OnLayoutCompleted()
384 if (mPendingScrollPosition != NO_POSITION)
386 ChangeFocus(mPendingScrollPosition);
388 mPendingScrollPosition = NO_POSITION;
389 mPendingScrollPositionOffset = INVALID_OFFSET;
394 internal virtual void EnsureAnchorReady(FlexibleViewRecycler recycler, AnchorInfo anchorInfo, int itemDirection)
401 /// Retrieves a position that neighbor to current position by direction.
403 /// <param name="position">The anchor adapter position</param>
404 /// <param name="direction">The direction.</param>
405 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
406 [EditorBrowsable(EditorBrowsableState.Never)]
407 protected override int GetNextPosition(int position, FlexibleViewLayoutManager.Direction direction)
409 if (mOrientation == HORIZONTAL)
413 case FlexibleViewLayoutManager.Direction.Left:
419 case FlexibleViewLayoutManager.Direction.Right:
420 if (position < ItemCount - 1)
431 case FlexibleViewLayoutManager.Direction.Up:
437 case FlexibleViewLayoutManager.Direction.Down:
438 if (position < ItemCount - 1)
450 /// Retrieves the first visible item view.
452 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
453 [EditorBrowsable(EditorBrowsableState.Never)]
454 protected override FlexibleViewViewHolder FindFirstVisibleItemView()
456 int childCount = ChildCount;
457 if (mShouldReverseLayout == false)
459 for (int i = 0; i < childCount; i++)
461 FlexibleViewViewHolder child = GetChildAt(i);
462 int end = (int)mOrientationHelper.GetViewHolderEnd(child);
463 if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
471 for (int i = childCount - 1; i >= 0; i--)
473 FlexibleViewViewHolder child = GetChildAt(i);
474 int end = (int)mOrientationHelper.GetViewHolderEnd(child);
475 if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
485 /// Retrieves the last visible item view.
487 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
488 [EditorBrowsable(EditorBrowsableState.Never)]
489 protected override FlexibleViewViewHolder FindLastVisibleItemView()
491 int childCount = ChildCount;
492 if (mShouldReverseLayout == false)
494 for (int i = childCount - 1; i >= 0; i--)
496 FlexibleViewViewHolder child = GetChildAt(i);
497 int start = (int)mOrientationHelper.GetViewHolderStart(child);
498 if (start > 0 && start < (int)mOrientationHelper.GetEnd())
506 for (int i = 0; i < childCount; i++)
508 FlexibleViewViewHolder child = GetChildAt(i);
509 int start = (int)mOrientationHelper.GetViewHolderStart(child);
510 if (start > 0 && start < (int)mOrientationHelper.GetEnd())