Click or drag to resize

OSATParams, TItemViewsHolder Class

Old name: ScrollRectItemsAdapter (renamed in 3.0 to SRIA, and in v4.1 to OSA as a final name - short for Optimized ScrollView Adapter)

Base abstract component that you need to extend in order to provide an implementation for CreateViewsHolder(Int32) and UpdateViewsHolder(TItemViewsHolder). Should be attached instead of the Unity's ScrollRect component. Any views holder should extend BaseItemViewsHolder, so you can provide it as the generic parameter TItemViewsHolder when implementing OSA. Extending BaseParams is optional. Based on your needs. Provide it as generic parameter TParams when implementing OSA

How it works, in a nutshell (it's recommended to manually go through the example code in order to fully understand the mechanism):

1. create your own implementation of BaseItemViewsHolder, let's name it MyItemViewsHolder

2. create your own implementation of BaseParams (if needed), let's name it MyParams

3. create your own implementation of OSA<MyParams, MyItemViewsHolder>, let's name it MyScrollViewAdapter

4. instantiate MyScrollViewAdapter

5. call MyScrollViewAdapter.ResetItems(int) once (and any time your dataset is changed) and the following things will happen:

5.1. CollectItemsSizes(ItemCountChangeMode, Int32, Int32, ItemsDescriptor) will be called (which you can optionally implement to provide your own sizes, if known beforehand)

5.2. CreateViewsHolder(Int32) will be called for enough items to fill the viewport. Once a ViewsHolder is created, it'll be re-used when it goes off-viewport

- newOrRecycledViewsHolder.root will be null, so you need to instantiate your prefab, assign it and call newOrRecycledViewsHolder.CollectViews(). Alternatively, you can call its Init(GameObject, Int32, Boolean, Boolean) method, which can do a lot of things for you, mainly instantiate the prefab and (if you want) call CollectViews() for you

- after creation, only UpdateViewsHolder(TItemViewsHolder) will be called for it when its represented item changes and becomes visible

5.3. UpdateViewsHolder(TItemViewsHolder) will be called when an item is to be displayed or simply needs updating:

- use ItemIndex to get the item index, so you can retrieve its associated model from your data set (most common practice is to store the data list in your Params implementation)

- root is not null here (given the views holder was properly created in CreateViewsHolder(..)). It's assigned a valid object whose UI elements only need their values changed (common practice is to implement helper methods in the views holder that take the model and update the views themselves)

ResetItems(Int32, Boolean, Boolean) is also called when the viewport's size changes (like for orientation changes on mobile or window resizing on sandalone platforms)

*NOTE: No LayoutGroup (vertical/horizontal/grid) on content panel are allowed, since all the layouting is delegated to this adapter

Inheritance Hierarchy
SystemObject
  Object
    Component
      Behaviour
        MonoBehaviour
          Com.ForbiddenByte.OSA.CoreOSATParams, TItemViewsHolder
            More...

Namespace:  Com.ForbiddenByte.OSA.Core
Assembly:  Assembly-CSharp (in Assembly-CSharp.dll) Version: 0.0.0.0
Syntax
C#
public abstract class OSA<TParams, TItemViewsHolder> : MonoBehaviour, 
	IOSA, IScrollRectProxy, IInitializePotentialDragHandler, IEventSystemHandler, IBeginDragHandler, 
	IDragHandler, IEndDragHandler, IScrollHandler
where TParams : BaseParams
where TItemViewsHolder : BaseItemViewsHolder

Type Parameters

TParams
The params type to use
TItemViewsHolder

The OSATParams, TItemViewsHolder type exposes the following members.

Constructors
Properties
  NameDescription
Public propertyAsMonoBehaviour
Simply casts the adapter to a MonoBehaviour and returns it. Guaranteed to be non-null, because OSATParams, TItemViewsHolder implements MonoBehaviour
Public propertyBaseParameters
The adapter's params that can be retrieved from anywhere through an IOSA reference to this adapter
Public propertyContent
Public propertyContentVirtualInsetFromViewportEnd
Public propertyContentVirtualInsetFromViewportStart
Public propertyContentVirtualSizeToViewportRatio Obsolete.
Public propertyIsDragging
Wether the scrollrect is currently dragged (i.e. the finger/mouse holds onto it)
Public propertyIsHorizontal
Public propertyIsInitialized
Public propertyIsVertical
Public propertyParameters
The adapter's parameters as seen in inspector
Public propertyRecyclableItemsCount
The number of items that are cached and waiting to be recycled
Public propertyVelocity
The velocity of the content panel in local UI space (from left to right = positive, from bottom to top = positive)
Public propertyViewport
Public propertyVisibleItemsCount
The number of currently visible items (views holders). Can be used to iterate through all of them using GetItemViewsHolder(Int32)
Top
Methods
  NameDescription
Protected methodAwake
Public methodCancelAnimationsIfAny
Public methodChangeItemsCount

Self-explanatory. See ItemCountChangeMode in order to understand how change modes differ from each other.

Every count change operation (Refresh(Boolean, Boolean), InsertItems(Int32, Int32, Boolean, Boolean) etc.) ultimately calls this method, so it's a good place for example to fire a custom "ItemsChanged" event, if you need to

Protected methodClearCachedRecyclableItems
Destroying any remaining game objects in the _RecyclableItems list and clearing it
Protected methodClearVisibleItems
Destroying any remaining game objects in the _VisibleItems list, clearing it and setting VisibleItemsCount to 0
Protected methodCollectItemsSizes
This is called during changing the items count. The base implementation reinitializes the items descriptor so that all items will have the same size, specified in DefaultItemSize If overriding the method and the item default size should remain the same as DefaultItemSize, don't forget to call the base implementation! Otherwise, call ReinitializeSizes(ItemCountChangeMode, Int32, Int32, NullableDouble) with the new default size as parameter. Use BeginChangingItemsSizes(Int32) before and EndChangingItemsSizes after setting sizes. The indices of items for which you set custom sizes must be one after another (4,5,6,7.. etc). Gaps are not allowed. Use "itemsDesc[itemIndexInView] = size" syntax for setting custom sizes. In this call, ItemIndex will be the same as itemIndexInView, even if looping is enabled.
Public methodConvertViewportLocalPointToViewportLongitudinalPointStart0End1
Converts from viewport local point to a point in range [0..1] longitudinally (in the ScrollView's orientation direction). 0=start, 1=end. The transversal component is ignored, of course (x for vertical, y for horizontal) In english, 0=top, 1=bottom, assuming vertical ScrollView. 0=left, 1=right, if horizontal ScrollView
Protected methodCreateViewsHolder

Called when there are no recyclable views for itemIndex. Provide a new viewsholder instance for itemIndex. This is the place where you must initialize the viewsholder

via Init(GameObject, Int32, Boolean, Boolean) shortcut or manually set its itemIndex, instantiate the prefab and call its CollectViews

Protected methodDispose
Public methodGetContentSize
Floating point rounding errors occur the bigger the content size, but generally it's accurrate enough. Returns MaxValue if the (virtual) content size is bigger than MaxValue
Public methodGetItemRealInsetFromParentEnd

returns the REAL distance of the item's right (if scroll view is Horizontal) or bottom (if scroll view is Vertical) edge

from the parent's right (respectively, bottm) edge

Public methodGetItemRealInsetFromParentStart

returns the REAL distance of the item's left (if scroll view is Horizontal) or top (if scroll view is Vertical) edge

from the parent's left (respectively, top) edge

Public methodGetItemsCount
Public methodGetItemViewsHolder

Get the viewsHolder with a specific index in the "visible items" list.

Example: if you pass 0, the first visible ViewsHolder will be returned (if there's any)

Not to be mistaken to the other method 'GetItemViewsHolderIfVisible(int withItemIndex)', which uses the itemIndex, i.e. the index in the list of data models.

Returns null if the supplied parameter is >= VisibleItemsCount

Public methodGetItemViewsHolderIfVisible(Int32)
Gets the views holder representing the withItemIndex'th item in the list of data models, if it's visible.
Public methodGetItemViewsHolderIfVisible(RectTransform)
Same as GetItemViewsHolderIfVisible(int withItemIndex), but searches by the root RectTransform reference, rather than the item index
Public methodGetItemVirtualInsetFromParentStart

returns the VIRTUAL distance of the item's left (if scroll view is Horizontal) or top (if scroll view is Vertical) edge

from the parent's left (respectively, top) edge

Public methodGetNormalizedPosition
Floating point rounding errors occur the bigger the content size, but generally it's accurrate enough
Public methodGetViewportSize
Self-explanatory
Protected methodGetViewsHolderClosestoViewportNormalizedAbastractPoint
Public methodGetViewsHolderClosestToViewportLongitudinalNormalizedAbstractPoint
Will set distance to MaxValue if no ViewsHolder is found. The point's format is in range [0=startEdge(top or left) .. 1=endEdge (bottom or right)] The transversal component of the point is considered to be 0.5f (middle). Transversal = vertical, if horizontal ScrollView. Else, horizontal
Protected methodGetViewsHolderClosestToViewportNormalizedPoint
Public methodGetViewsHolderClosestToViewportPoint
Public methodGetVirtualAbstractNormalizedScrollPosition

Used internally. Returns values in [0f, 1f] interval, 1 meaning the scrollrect is at start, and 0 meaning end.

It uses a different approach when content size is smaller than viewport's size, so it can yield consistent results for ComputeVisibility(Double)

Public methodInit

Initialize the adapter. This is automatically called in Start(), but it may also be called manually, if for some reason you implement Start() and don't want to call base.Start()

Will call Canvas.ForceUpdateCanvases(), Params.InitIfNeeded(), will initialize the internal state and will change the items count to 0

IMPORTANT: Do not call it in Awake(), OnEnable(), OnDisable(). OnStart() is the best place to do it.

Public methodInsertItems
Public methodInsertItemWithViewsHolder

Call it when a stolen ViewsHolder won't be added to the adapter and so the adapter should not be responsible for its lifecycle anymore.

If the item was stolen, it'll be unregistered automatically

Protected methodIsRecyclable
Self-explanatory. The default implementation returns true each time
Public methodIsViewsHolderEnabled
Protected methodLateUpdate
Protected methodOnBeforeRecycleOrDisableViewsHolder
Perfect place to clean the views in order to prepare them to be potentially recycled this frame or soon. newItemIndex will be -1 if the item will be disabled/destroyed instead of being recycled.
Public methodOnBeginDrag
Protected methodOnDestroy
Public methodOnDrag
Public methodOnEndDrag
Public methodOnInitializePotentialDrag
Protected methodOnItemHeightChangedPreTwinPass
Only called for vertical ScrollRects. Called just before a "Twin" ComputeVisibility will execute. This can be used, for example, to disable a ContentSizeFitter on the item which was used to externally calculate the item's size in the current Twin ComputeVisibility pass
Protected methodOnItemIndexChangedDueInsertOrRemove

Called when an insert or remove event happens. You'll only need this if some of your views depend on the item's index itself as opposed to depending only on the model's data

For example, if your item is from a leaderboard and each player's place is given by the order of the models (i.e. you don't have an int in the model named 'place'), you may want to display the item's title as '#233 PlayerName'. This works well if you're only using ResetItems(Int32, Boolean, Boolean), but if you'll call InsertItems(Int32, Int32, Boolean, Boolean) or RemoveItems(Int32, Int32, Boolean, Boolean), the indices of some views holders are shifted, while they'll maintain their data. In this case, you'll override this method and only update the title from its model

This is an important optimization, because you shouldn't update items that are already updated, especially when fetching them from the web

Protected methodOnItemWidthChangedPreTwinPass
Same as OnItemHeightChangedPreTwinPass(TItemViewsHolder), but for horizontal ScrollRects
Public methodOnScroll
Protected methodOnScrollViewSizeChanged
This is called automatically when the size of this ScrollView changes
Protected methodRebuildLayoutDueToScrollViewSizeChange

Called mainly when it's detected that the scroll view's size has changed. Marks everything for a layout rebuild and then calls Canvas.ForceUpdateCanvases().

IMPORTANT: Make sure to override MarkForRebuild in your views holder implementation if you have child layout groups and call LayoutRebuilder.MarkForRebuild() on them

Public methodRefresh
Public methodRemoveItems
Public methodRemoveItemWithViewsHolder
Public methodRequestChangeItemSizeAndUpdateLayout(Int32, Single, Boolean, Boolean)

An item width/height can be changed with this method.

Should NOT be called during ComputeVisibilityForCurrentPosition(Boolean, Boolean), UpdateViewsHolder(TItemViewsHolder), CreateViewsHolder(Int32) or from any critical view-recycling code. Suggestion: call it from MonBehaviour.Update()

Will change the size of the item's RectTransform to requestedSize and will shift the other items accordingly, if needed.

Public methodRequestChangeItemSizeAndUpdateLayout(TItemViewsHolder, Single, Boolean, Boolean)
See RequestChangeItemSizeAndUpdateLayout(Int32, Single, Boolean, Boolean) for additional info or if you want to resize an item which isn't visible
Public methodResetItems
Protected methodScheduleComputeVisibilityTwinPass

This can be called in order to schedule a "Twin" ComputeVisibility() call after exactly 1 frame.

A use case is to enable a ContentSizeFitter on your item, call this,

and then disable the ContentSizeFitter in OnItemHeightChangedPreTwinPass(TItemViewsHolder) (or OnItemWidthChangedPreTwinPass(TItemViewsHolder) if horizontal ScrollView)

Public methodScrollByAbstractDelta
positite => scroll towards start negative => scroll towards end
Public methodScrollTo

By default, it aligns the ScrollView's content so that the item with itemIndex will be at the top.

But the two optional parameters can be used for more fine-tuning. One common use-case is to set them both at 0.5 so the item will be end up exactly in the middle of the viewport

Public methodSetNormalizedPosition
Floating point rounding errors occur the bigger the content size, but generally it's accurrate enough
Public methodSetViewsHolderDisabled
Public methodSetViewsHolderEnabled(TItemViewsHolder)
Public methodSetViewsHolderEnabled(TItemViewsHolder, Boolean)
Public methodSetVirtualAbstractNormalizedScrollPosition
Same thing as normalizedPosition, just that the position is 1 for start and 0 for end, regardless if using a horizontal or vertical ScrollRect
Protected methodShouldDestroyRecyclableItem
Self-explanatory. The default implementation returns true if isInExcess is true
Public methodSmoothBringToView
Similar to SmoothScrollTo(Int32, Single, Single, Single, FuncSingle, Boolean, Boolean) (see it for more info about the other params), but scrolls the content only by the minimum needed amount to make the item fully visible and optionally adding some spacing as specified by spacingFromViewportEdge
Public methodSmoothScrollTo
Utility to smooth scroll. Identical to ScrollTo(Int32, Single, Single) in functionality, but the scroll is animated (scroll is done gradually, throughout multiple frames)
Protected methodStart
Public methodStopMovement
Protected methodUpdate
Protected methodUpdateViewsHolder

Here the data in your model should be bound to the views. Use newOrRecycled.ItemIndex (ItemIndex) to retrieve its associated model

Note that views holders are re-used (this is the main purpose of this adapter), so a views holder's views will contain data from its previously associated model and if,

for example, you're downloading an image to be set as an icon, it makes sense to first clear the previous one (and probably temporarily replace it with a generic "Loading" image)

Note that this is not called for items that will remain visible after an Insert or Remove operation is done

Top
Events
  NameDescription
Public eventInitialized
Fired at the end of an Init call, which is usually done in Start(), if you're not calling it manually
Public eventItemsRefreshed
Fired when the item count changes or the views are refreshed (more exactly, after each ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) call). Params are (1st=prevCount, 2nd=newCount)
Public eventScrollPositionChanged
The float parameter has the same format as described in SetNormalizedPosition(Double)
Top
Fields
Extension Methods
Version Information

Optimized ScrollView Adapter

Supported in: 4.1
See Also
Inheritance Hierarchy
SystemObject
  Object
    Component
      Behaviour
        MonoBehaviour
          Com.ForbiddenByte.OSA.CoreOSATParams, TItemViewsHolder
            Com.ForbiddenByte.OSA.CoreSRIATParams, TItemViewsHolder
            Com.ForbiddenByte.OSA.CustomAdapters.DateTimePickerDateTimePickerAdapter
            Com.ForbiddenByte.OSA.CustomAdapters.GridViewGridAdapterTParams, TCellVH
            Com.ForbiddenByte.OSA.Demos.ChatChatExample
            Com.ForbiddenByte.OSA.Demos.ContentSizeFitterContentSizeFitterExample
            Com.ForbiddenByte.OSA.Demos.HierarchyHierarchyExample
            Com.ForbiddenByte.OSA.Demos.IncrementalItemFetchIncrementalItemFetchExample
            Com.ForbiddenByte.OSA.Demos.ItemDraggingItemDraggingExample
            Com.ForbiddenByte.OSA.Demos.LoopingSpinnersLoopingSpinnerExample
            Com.ForbiddenByte.OSA.Demos.MainMainExample
            Com.ForbiddenByte.OSA.Demos.MultiplePrefabsMultiplePrefabsExample
            Com.ForbiddenByte.OSA.Demos.NestedScrollViewsNestedScrollViewsExample
            Com.ForbiddenByte.OSA.Demos.PageViewPageViewExample
            Com.ForbiddenByte.OSA.Demos.SimpleSimpleExample