1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 using Tizen.NUI.BaseComponents;
18 using System.Collections.Generic;
19 using System.ComponentModel;
20 using Tizen.NUI.Binding;
22 namespace Tizen.NUI.Components
25 /// Default layout manager for CollectionView.
26 /// Lay out ViewItem and recycle ViewItem.
28 [EditorBrowsable(EditorBrowsableState.Never)]
29 public abstract class ItemsLayouter : ICollectionChangedNotifier, IDisposable
31 private bool disposed = false;
34 /// Container which contains ViewItems.
36 [EditorBrowsable(EditorBrowsableState.Never)]
37 protected View Container{ get ; set; }
42 [EditorBrowsable(EditorBrowsableState.Never)]
43 protected RecyclerView ItemsView{ get; set; }
46 /// The last scrolled position which is calculated by ScrollableBase. The value should be updated in the Recycle() method.
48 [EditorBrowsable(EditorBrowsableState.Never)]
49 protected float PrevScrollPosition { get; set; }
52 /// First index of visible items.
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 protected int FirstVisible { get; set; } = -1;
58 /// Last index of visible items.
60 [EditorBrowsable(EditorBrowsableState.Never)]
61 protected int LastVisible { get; set; } = -1;
66 [EditorBrowsable(EditorBrowsableState.Never)]
67 protected List<RecyclerViewItem> VisibleItems { get; } = new List<RecyclerViewItem>();
70 /// Flag of layouter initialization.
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 protected bool IsInitialized { get; set; } = false;
76 /// Candidate item step size for scroll size measure.
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 protected float StepCandidate { get; set; }
82 /// Content size of scrollable.
84 [EditorBrowsable(EditorBrowsableState.Never)]
85 protected float ScrollContentSize { get; set; }
88 /// boolean flag of scrollable horizontal direction.
90 [EditorBrowsable(EditorBrowsableState.Never)]
91 protected bool IsHorizontal { get; set; }
94 /// Clean up ItemsLayouter.
96 /// <param name="view"> ItemsView of layouter.</param>
97 [EditorBrowsable(EditorBrowsableState.Never)]
98 public virtual void Initialize(RecyclerView view)
100 ItemsView = view ?? throw new ArgumentNullException(nameof(view));
101 Container = view.ContentContainer;
102 PrevScrollPosition = 0.0f;
104 IsHorizontal = (view.ScrollingDirection == ScrollableBase.Direction.Horizontal);
106 IsInitialized = true;
110 /// This is called to find out where items are lain out according to current scroll position.
112 /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param>
113 /// <param name="force">boolean force flag to layouting forcely.</param>
114 [EditorBrowsable(EditorBrowsableState.Never)]
115 public virtual void RequestLayout(float scrollPosition, bool force = false)
117 // Layouting Items in scrollPosition.
121 /// Clear the current screen and all properties.
123 [EditorBrowsable(EditorBrowsableState.Never)]
124 public virtual void Clear()
126 foreach (RecyclerViewItem item in VisibleItems)
128 if (ItemsView != null) ItemsView.UnrealizeItem(item, false);
130 VisibleItems.Clear();
136 /// Position of layouting item.
138 /// <param name="item">item of dataset.</param>
139 [EditorBrowsable(EditorBrowsableState.Never)]
140 public virtual (float X, float Y) GetItemPosition(object item)
142 if (item == null) throw new ArgumentNullException(nameof(item));
143 // Layouting Items in scrollPosition.
148 /// Size of layouting item.
150 /// <param name="item">item of dataset.</param>
151 [EditorBrowsable(EditorBrowsableState.Never)]
152 public virtual (float X, float Y) GetItemSize(object item)
154 if (item == null) throw new ArgumentNullException(nameof(item));
155 // Layouting Items in scrollPosition.
160 /// This is called to find out how much container size can be.
162 [EditorBrowsable(EditorBrowsableState.Never)]
163 public virtual float CalculateLayoutOrientationSize()
169 /// Adjust scrolling position by own scrolling rules.
171 /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param>
172 [EditorBrowsable(EditorBrowsableState.Never)]
173 public virtual float CalculateCandidateScrollPosition(float scrollPosition)
175 return scrollPosition;
179 /// Notify the relayout of ViewItem.
181 /// <param name="item">updated ViewItem.</param>
182 [EditorBrowsable(EditorBrowsableState.Never)]
183 public virtual void NotifyItemSizeChanged(RecyclerViewItem item)
188 /// Notify the dataset is Changed.
190 [EditorBrowsable(EditorBrowsableState.Never)]
191 public virtual void NotifyDataSetChanged()
193 Initialize(ItemsView);
197 /// Notify the observable item in startIndex is changed.
199 /// <param name="source">Dataset source.</param>
200 /// <param name="startIndex">Changed item index.</param>
201 [EditorBrowsable(EditorBrowsableState.Never)]
202 public virtual void NotifyItemChanged(IItemSource source, int startIndex)
207 /// Notify the observable item is inserted in dataset.
209 /// <param name="source">Dataset source.</param>
210 /// <param name="startIndex">Inserted item index.</param>
211 [EditorBrowsable(EditorBrowsableState.Never)]
212 public virtual void NotifyItemInserted(IItemSource source, int startIndex)
217 /// Notify the observable item is moved from fromPosition to ToPosition.
219 /// <param name="source">Dataset source.</param>
220 /// <param name="fromPosition">Previous item position.</param>
221 /// <param name="toPosition">Moved item position.</param>
222 [EditorBrowsable(EditorBrowsableState.Never)]
223 public virtual void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition)
228 /// Notify the range of observable items from start to end are changed.
230 /// <param name="source">Dataset source.</param>
231 /// <param name="startRange">Start index of changed items range.</param>
232 /// <param name="endRange">End index of changed items range.</param>
233 [EditorBrowsable(EditorBrowsableState.Never)]
234 public virtual void NotifyItemRangeChanged(IItemSource source, int startRange, int endRange)
239 /// Notify the count range of observable items are inserted in startIndex.
241 /// <param name="source">Dataset source.</param>
242 /// <param name="startIndex">Start index of inserted items range.</param>
243 /// <param name="count">The number of inserted items.</param>
244 [EditorBrowsable(EditorBrowsableState.Never)]
245 public virtual void NotifyItemRangeInserted(IItemSource source, int startIndex, int count)
250 /// Notify the count range of observable items from the startIndex are removed.
252 /// <param name="source">Dataset source.</param>
253 /// <param name="startIndex">Start index of removed items range.</param>
254 /// <param name="count">The number of removed items</param>
255 [EditorBrowsable(EditorBrowsableState.Never)]
256 public virtual void NotifyItemRangeRemoved(IItemSource source, int startIndex, int count)
261 /// Notify the observable item in startIndex is removed.
263 /// <param name="source">Dataset source.</param>
264 /// <param name="startIndex">Index of removed item.</param>
265 [EditorBrowsable(EditorBrowsableState.Never)]
266 public virtual void NotifyItemRemoved(IItemSource source, int startIndex)
271 /// Gets the next keyboard focusable view in this control towards the given direction.<br />
272 /// A control needs to override this function in order to support two dimensional keyboard navigation.<br />
274 /// <param name="currentFocusedView">The current focused view.</param>
275 /// <param name="direction">The direction to move the focus towards.</param>
276 /// <param name="loopEnabled">Whether the focus movement should be looped within the control.</param>
277 /// <returns>The next keyboard focusable view in this control or an empty handle if no view can be focused.</returns>
278 [EditorBrowsable(EditorBrowsableState.Never)]
279 public virtual View RequestNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
285 /// Dispose ItemsLayouter and all children on it.
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public void Dispose()
291 GC.SuppressFinalize(this);
295 /// Measure the size of chlid ViewItem manually.
297 /// <param name="parent">Parent ItemsView.</param>
298 /// <param name="child">Child ViewItem to Measure()</param>
299 [EditorBrowsable(EditorBrowsableState.Never)]
300 protected virtual void MeasureChild(RecyclerView parent, RecyclerViewItem child)
302 if (parent == null) throw new ArgumentNullException(nameof(parent));
303 if (child == null) throw new ArgumentNullException(nameof(child));
305 if (child.Layout == null) return;
307 //FIXME: This measure can be restricted size of child to be less than parent size.
308 // but in some multiple-line TextLabel can be long enough to over the it's parent size.
310 MeasureSpecification childWidthMeasureSpec = LayoutGroup.GetChildMeasureSpecification(
311 new MeasureSpecification(new LayoutLength(parent.Size.Width), MeasureSpecification.ModeType.Exactly),
313 new LayoutLength(child.WidthSpecification));
315 MeasureSpecification childHeightMeasureSpec = LayoutGroup.GetChildMeasureSpecification(
316 new MeasureSpecification(new LayoutLength(parent.Size.Height), MeasureSpecification.ModeType.Exactly),
318 new LayoutLength(child.HeightSpecification));
320 child.Layout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
324 /// Find consecutive visible items index.
326 /// <param name="visibleArea">float turple of visible area start position to end position. </param>
327 /// <return>int turple of start index to end index</return>
328 [EditorBrowsable(EditorBrowsableState.Never)]
329 protected virtual (int start, int end) FindVisibleItems((float X, float Y) visibleArea)
335 /// Dispose ItemsLayouter and all children on it.
337 /// <param name="disposing">true when it disposed by Dispose(). </param>
338 [EditorBrowsable(EditorBrowsableState.Never)]
339 protected virtual void Dispose(bool disposing)
347 if (disposing) Clear();