Managing scrollable contents: Horizontal List

The Mosaic class Core::HorizontalList implements a special kind of view intended to display items arranged horizontally side by side. This so-called Horizontal List can be used to compose the appearance of a GUI component, in particular to present lists with options, menu items or data records the user can inspect, scroll and select. The list can, for example, display picture thumbnails stored in the device:

The Horizontal List view is optimized to efficiently manage with very long lists consisting of thousands of items. For this purpose, the view retains only few of the items in the memory. Later when the user scrolls the list, the view takes care of the old items being replaced with new contents so that the user has the impression of a continuous list. The view is also optimized regarding the speed permitting even very long lists being scrolled smoothly.

The consequence of the mentioned optimizations is that the view expects all items to have equal width. Mixing of items with different width within one and the same Horizontal List is thus not possible. If the number of items is manageable low, you can eventually implement such list by using the Outline Box configured to arrange its embedded views in a horizontal formation.

The following sections are intended to provide you an introduction and useful tips of how to work with the Horizontal List. For the complete reference please see the documentation of the Core::HorizontalList class. Moreover, please note, that there is a similar view Vertical List intended to manage and display the items arranged vertically one below the other.

Add new Horizontal List

To add a new Horizontal List just at the design time of a GUI component do following:

First ensure that the Templates window is visible.

In Templates window switch to the folder Views.

In the folder locate the template Horizontal List.

Drag & Drop the template into the canvas area of the Composer window:

Eventually name the new added Horizontal List.

As you see in the screenshot above, the new added Horizontal List appears per default accompanied by a slot method (usually named OnLoadItem). This method is important to provide the list with contents for the actually displayed items. It is added just to help you to start with the Horizontal List and to avoid that new lists appear empty. Being an advanced developer, you will probably replace this method by your own particular version. How this is done is addressed in the section below.

IMPORTANT

The Horizontal List doesn't provide any own appearance. Instead it manages and displays the items controlled by it. In order to be recognized while assembling the GUI component in the Composer window, the Horizontal List is slightly tinted with green color. This effect exists just for your convenience. In the Prototyper as well as in the target device the Horizontal List itself is invisible.

Inspect the Horizontal List

As long as the Horizontal List is selected you can inspect and modify its properties conveniently in the Inspector window as demonstrated with the property Bounds in the screenshot below:

This is in so far worth mentioning as all following sections describe diverse features of the Horizontal List by explicitly referring to its corresponding properties. If you are not familiar with the concept of a property and the usage of Inspector window, please read first the preceding chapter Compositing component appearance.

Arrange the Horizontal List

Once added, you can freely move the Horizontal List, or you simply grab one of its corners and resize it in this way. You can control the position and the size of this view also by directly modifying its property Bounds. If you want the Horizontal List to appear behind other views you can reorder it explicitly.

Please note, that resizing the Horizontal List has no effect on the current scroll position. Accordingly, it is possible, that after the list view has been enlarged a gap appears between the last item and the right edge of the Horizontal List. Is such case you have to adjust the scroll offset explicitly.

Specify the width of an item within the list

The Horizontal List view is optimized to handle very efficiently with long contents consisting of thousands of items. This, in turn, results in the strict limitation, that within a Horizontal List all items have the same width. Mixing of items with different width is currently not supported. If the number of items is manageable low, you can eventually implement such flexible list by using the Outline Box configured to arrange its embedded views in a horizontal formation.

The first step when working with the Horizontal List is thus to specify in its property ItemWidth the width in pixel of a single item you intend to display in the list.

TIP

If you want only an additional header and footer item being displayed together with the regular items, you can configure the Horizontal List to reserve space on the left of the first and on the right of the last item where you can arrange the header and footer contents. See Add padding at the begin and at the end of the list.

Specify the class of the items within the list

The second step when working with the Horizontal List is to specify in its property ItemClass which kind of view or GUI component you intend to use to display the items. Per default, the property is configured with Views::Image class, which means that the list manages and displays simple Image views. If you want the list to display Text views, you have to change this property to Views::Text.

Similarly, you can configure this property with a class representing one of your own GUI components. For example, if you want to implement an application displaying videos stored in a PVR database, you would probably initialize this property with the class of a GUI component intended to display the video information like its title, duration or thumbnail. The Horizontal List will then automatically create, manage and display the instances of your GUI component.

With the Inspector Assistant you can conveniently select the right class when you edit the initialization expression for the property ItemClass.

Implement the OnLoadItem slot method to load the items

The Horizontal List view doesn't maintain actively the entire stock of items in the memory. Instead, it manages a cache small enough to store the currently visible and few of the above and below lying items. Even, if the original stock consists of thousands of items, the Horizontal List stores only very few of them. This approach however means, that the list requires a technique to load new items in its cache as soon as these are exposed, for example, after the user has scrolled the list. The items are thus loaded on demand.

To load an item, the Horizontal List sends a signal to a slot method stored in its property OnLoadItem. This slot method has then the job to obtain the data associated with the requested item (from your data storage, data base, etc.) and to initialize the corresponding item view so it reflects this information. Please recall the above described property ItemClass. With this property you specify the class of the view to be used to display a single item within the list. The implementation of the slot method is thus intended to initialize an instance of exact this class.

The following code demonstrates the original implementation of the default version of the slot method provided with the template you used to add a new Horizontal List. As you remember, the Horizontal List is per default configured to handle with Image view items. The slot method is accordingly implemented to handle with instances of the Views::Image class:

// Get the number of the item to load. The list component takes care of the // creation of the corresponding item view. Just access it ... var int32 itemNo = HorizontalList.Item; var Views::Image itemView = (Views::Image)HorizontalList.View; // The implementation of this slot method does not match the item class // specified in the associated list component. Or the slot method is not // called in context of the OnLoadItem list operation. if ( itemView == null ) return; // Configure the item view ... itemView.Bitmap = Resources::SymbolIconsLarge; itemView.FrameNumber = ( itemNo % itemView.Bitmap.NoOfFrames ); switch ( itemNo % 4 ) { case 1 : itemView.Color = #0000FFFF; case 2 : itemView.Color = #FF0000FF; case 3 : itemView.Color = #00FF00FF; default : itemView.Color = #FFFF00FF; } // Ensure that the item has correct size. The position of the item will be // managed by the list component. itemView.Bounds.size = point( HorizontalList.ItemWidth, HorizontalList.Bounds.h );

When calling the slot method, the Horizontal List provides in its variable Item the index of the item to load. The items are numbered strictly starting with the number 0 (zero) for the first item. You evaluate this variable in order to determine which item is requested to be loaded. Knowing this number you can query your particular data storage or data base and get the information related to the requested item.

In the second variable View the Horizontal list provides a direct access to the view instance representing the corresponding item on the screen. Modifying properties of this instance will thus result in the item changing its appearance. In every case View does refer to a valid instance of the class specified in the above described property ItemClass.

The variable View is declared with the very basic class Core::View. Before you can access and initialize the view you have thus to perform an object runtime casting and test whether it was successful. Afterwards you can access the view and initialize it as required in your particular application case. In the above implementation, the view (being a Image view) is initialized with a bitmap resource selected depending on the number of the item. You can imagine, that after obtaining information for the affected item from the data storage or data base, you can assign this information to the view.

IMPORTANT

When the content of the Horizontal List is scrolled, the list recycles the existing item views instead of creating new instances again and again. Thus when implementing the OnLoadItem slot method, you should consider that the provided View instance has eventually been initialized in the past with other item information. The best is to always initialize the view with the complete available information.

Usually after adding a new Horizontal List you will open the per default provided OnLoadItem slot method for editing and modify its implementation as required in your application case. You can, of course, rename or even remove the default slot method and replace it by your own. In such case, don't forget to assign the new slot method to the property OnLoadItem of the affected Horizontal List.

The following example contains the implementation of a list managing picture thumbnails stored in a device. It demonstrates, in particular, how the Horizontal List is configured to use a GUI component instead of simple view to display the items and how the OnLoadItem initializes the properties of such GUI component when the list loads the items on demand:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

Specify the number of items within the list

With the property NoOfItems you determine how many records in total are available in your data storage, data base, etc.. Accordingly, the Horizontal List will allow the user to scroll and see all those items. For example, if you intend to implement a spin control where the user can scroll and select the hour, you would initialize the property NoOfItems with 24 (or with 12 if your country's time convention is the 12-hour clock).

Please note, that at the runtime, when the user scrolls the list, the associated OnLoadItem method may be called for all the items in the specified range 0 .. NoOfItems-1. This means, the value in the NoOfItems property should always correspond to the total number of available records in your data storage.

When the content in the data storage changes at the runtime, e.g. the records disappear or new records are added to the storage, you should always adjust the property NoOfItems. Doing that causes the list to be refreshed implicitly.

Please note, that changing the NoOfItems property has no effect on the current scroll position. Accordingly, it is possible, that after the number of items has been reduced a gap appears between the last item and the right edge of the Horizontal List. Is such case you have to adjust the scroll offset explicitly.

Configure an endless list

With the property Endless you can control how the Horizontal List should behave when its content is scrolled beyond the last item. The default setting of this property is false. In this case the list is considered as finite without any further contents being displayed after the last or before the first item.

Setting this property to the value true will cause the list to behave as if its content were infinite. In particular the list displays all items according to their order and after the last item has been reached the list starts again with the first item. The effect is as if the list items were arranged on an endless band.

IMPORTANT

Enabling the endless list mode will cause the eventually specified left and right padding areas to be ignored. Moreover, if the list area is bigger than the area occupied by all available items, several duplicates of one and the same item will appear within the list area.

Force the list to reload items

The Horizontal List uses internally a cache to maintain the currently visible items. The corresponding implementation is optimized with regard to the memory usage and the performance. Thus the Horizontal List decides by itself when and which items are loaded. For example, when the user scrolls the list, the newly exposed items not yet being available in the cache are loaded automatically. This however has the disadvantage, that when something changes in the data storage, the Horizontal List is not updated implicitly.

By calling the method InvalidateItems you can explicitly inform the Horizontal List, that some items have changed their contents. Depending on whether the affected items are actually visible or not, the Horizontal List will reload them again by sending signals to the OnLoadItem slot method as described above.

In other words, to maintain coherent the Horizontal List view with the corresponding data storage, you should always call the method InvalidateItems when you recognize that data records in the data storage has been changed. The method expects two parameters determining the index of the first and the last affected item. Accordingly you can inform the list that one or a complete range of items are not up to date. Calling the method multiple times is accumulated. The following code demonstrates it:

// Example 1: // The item #7 has been changed, so ask the list to eventually reload it. HorizontalList.InvalidateItems( 7, 7 ); // Example 2: // All items have been changed (e.g. after loading new contents for the // data storage). HorizontalList.InvalidateItems( 0, HorizontalList.NoOfItems - 1 ); // Example 3: // The items #7, #12 and #13 have been changed. HorizontalList.InvalidateItems( 7, 7 ); HorizontalList.InvalidateItems( 12, 13 );

Let's assume you have a Horizontal List displaying counter values taken from an array. Thus this array will store for every list item a number (the corresponding counter). If you want one counter being incremented, the following code takes care of it and forces the list to reload the corresponding item:

// Step 1: In the data store: increment the counter corresponding to the 'item_number' DataArray[ item_number ] = DataArray[ item_number ] + 1; // Step 2: Force the list to refresh the item_number HorizontalList.InvalidateItems( item_number, item_number );

The following example project demonstrates the above implementation of a list displaying counters. When the user taps on an item, the counter is incremented and the list is updated:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

Access list items and views

As already mentioned the Horizontal List is optimized to handle efficiently with thousands of items. For this purpose the list maintains only few item views in the memory and reuses them while the user scrolls the list. Thus you should consider that the Horizontal List is just a display mechanism and not the primary resource for maintaining and getting data!

Even knowing the valid item index, there is no direct way to get the corresponding item data from the Horizontal List. Similarly, the views associated to items are not guaranteed to be available. The Horizontal List provides a method GetViewForItem() you can use to access the view associated with an item. This, however, works only if the affected view is currently in memory. If the item in question is not visible, the associated view is probably not available causing the method GetViewForItem() to return null.

The right approach to work with lists is following:

Manage the complete item related information in a storage, e.g. an array.

Implement the OnLoadItem slot method to load the requested item with the corresponding information from the storage.

When the content in the storage changes, invalidate the affected item only. The list will take care of the necessary reload operation.

When the user interacts with the list causing some item contents being changed, the alternation should affect the data in the storage only. Then invalidate the affected item. Don't use the actually visible views to temporarily store data or other status or selection information. Store the status or selection information in the storage!

If it is inevitable to directly access a view, use the method GetViewForItem(). If the method returns null, the view is not available - the item evidently lies outside the list area.

CAUTION

Please note, while the horizontal list is actually reloading its items, the list changes the order of views preventing the method GetViewForItem() from being able to access the right view. To avoid that your implementation accesses a wrong view, the method GetViewForItem() returns null if it has been called in context of an active OnLoadItem slot method. In other words, don't use GetViewForItem() while the list loads items.

Mix different types of items within the same list

The Horizontal List view is restricted to handle with items of one and the same explicitly specified class. Mixing of various classes is as such not possible. This is inconvenient, when your application requires different kinds of content being shown within the same list. For example, a list providing the overview of audio and video material stored in a media center. It is comprehensible, that the items for the both types are displayed differently. The item for the video could be present as a preview thumbnail, while the audio item could show a play button, etc.

You have two options how this challenge can be solved:

1.You implement all variants of the item within one and the same GUI component. The GUI component contains thus all views necessary to display the information about audio as well as video data records. Depending on the content, the respective views will be hidden or shown. The disadvantage of this approach is, that with the many hidden views it generates an overhead. Although hidden, every view will occupy a small part in the memory. The advantage of this approach is, that it is simple.

2.You implement separate item components for the various item types. For example a component to display audio information and another component to display video information. Then you implement a wrapper component, which depending on the type of the respective content instantiates and embeds dynamically the right version of the item component. The Horizontal List itself has to be configured to use the wrapper component as its item class. The disadvantage of this approach is the additional complexity to be implemented.

The first approach is to prefer when you have few different item variants or the items are very similar. In turn the second approach is better when you have many different item variants. And exactly this is demonstrated in the example below with a menu displaying different types of setting items. For every item type (switch, button, etc.) a particular item class is implemented. Depending on the type of the item, the wrapper class creates the right item and shows it in its own boundary area:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

TIP

If you want only an additional header and footer item being displayed together with the regular items, you can configure the Horizontal List to reserve space on the left of the first and on the right of the last item where you can arrange the header and footer contents. See Add padding at the begin and at the end of the list.

Scroll the list items

With the Horizontal List you can easily scroll the displayed items. The scrolling is controlled by the property ScrollOffset. With positive values the items are scrolled to the right. With negative values to the left. The following example shows how this property affects the position of the displayed items within one and the same Horizontal List (the thin blue borders indicate the Horizontal List areas):

An alternative approach to scroll the items is to use the method EnsureVisible(). This method expects in its parameter an index of the item you want to expose within the Horizontal List. By calling this method, the entire list content is scrolled until the specified item has become visible.

Per default, calling EnsureVisible causes the items being scrolled instantly. By preparing a Change int32 effect and passing it in a parameter to the EnsureVisible() method, the scrolling can be performed with a smooth animation. The following Chora code demonstrates the approach:

// The item you want to ensure to be visible within the Horizontal List. var int32 itemNo = ...; // Create a new animation effect instance. var Effects::Int32Effect effect = new Effects::Int32Effect; // Configure the animation duration and the timing (easing) effect.CycleDuration = 250; // milliseconds effect.NoOfCycles = 1; effect.Timing = Effects::Timing.Exp_InOut; // Finally instruct the Horizontal List to scroll its items with // the prepared animation until the item with the index 'itemNo' is // fully visible. HorizontalList.EnsureVisible( itemNo, true, effect, null );

The method EnsureVisible() scrolls the items only when it is necessary. If the specified item is already fully visible, the method returns immediately. Please note the last parameter of the method, which is null in the above example. Using this parameter you can specify a slot method to send a signal to as soon as the scrolling has been finished.

Accordingly, your implementation of the slot method can perform operations to complete the task. For example, it is usual to suppress user inputs while performing animations in order to avoid any interferences. With the mentioned slot method you can restore the event handling again when the animation is done. The following example implements this approach:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

An alternative approach to control running animations is to use the methods IsScrollEffectActive() and StopScrollEffect(). With the method IsScrollEffectActive() you can easily check whether the affected Horizontal List is actually performing an animation activated by a preceding EnsureVisible() or AdjustList() method invocation. If such animation is active, the method returns true and your implementation can react to this situation. The method StopScrollEffect(), in turn, allows you to immediately finish the active animation. With method parameters you determine whether the effect should stop at its actual position or whether it should skip to the previously estimated end position.

Please note, to avoid any interferences, invoking the EnsureVisible() method stops the animation started eventually by the preceding EnsureVisible() or AdjustList() invocation.

Adjust the scroll position

When the boundary area of the Horizontal List view is enlarged or the number of items managed by the list shrinks, the current scroll offset remains unchanged. This can result in an undesired gap appearing just between the last item and the right edge of the list view. Depending on your application case, you will probably need to adjust the list so it entire area is filled with items as good as possible.

This can be achieved conveniently by calling the method AdjustList. The method verifies whether there is some gap between the last item and the right edge of the Horizontal List, which can be filled by simply scrolling the list. Similar is calculated with the eventual gap between the left edge of the view and the first item. In all cases, the method tries to calculate the minimal scroll adjustment so the undesired gaps disappear.

Per default, calling AdjustList causes the items being scrolled instantly. By preparing a Change int32 effect and passing it in a parameter to the AdjustList() method, the scrolling can be performed with a smooth animation. The following Chora code demonstrates the approach:

// Create a new animation effect instance. var Effects::Int32Effect effect = new Effects::Int32Effect; // Configure the animation duration and the timing (easing) effect.CycleDuration = 250; // milliseconds effect.NoOfCycles = 1; effect.Timing = Effects::Timing.Exp_InOut; // Finally instruct the Horizontal List to adjust the scrolling offset // with the prepared animation. HorizontalList.AdjustList( effect, null );

The method AdjustList() scrolls the items only when it is necessary. If there is no gap to fill with items, or the number of items is too less to fill the entire list view, the method returns immediately. Please note the last parameter of the method, which is null in the above example. Using this parameter you can specify a slot method to send a signal to as soon as the scrolling has been finished.

Accordingly, your implementation of the slot method can perform operations to complete the task. For example, it is usual to suppress user inputs while performing animations in order to avoid any interferences. With the mentioned slot method you can restore the event handling again when the animation is done. This approach is demonstrated in the example from the section above.

An alternative approach to control running animations is to use the methods IsScrollEffectActive() and StopScrollEffect(). With the method IsScrollEffectActive() you can easily check whether the affected Horizontal List is actually performing an animation activated by a preceding AdjustList() or EnsureVisible() method invocation. If such animation is active, the method returns true and your implementation can react to this situation. The method StopScrollEffect(), in turn, allows you to immediately finish the active animation. With method parameters you determine whether the effect should stop at its actual position or whether it should skip to the previously estimated end position.

Please note, to avoid any interferences, invoking the AdjustList() method stops the animation started eventually by the preceding AdjustList() or EnsureVisible() invocation.

Modulate the opacity of the displayed items

Using the property Opacity you can modulate the opacity of the displayed items, so that they appear semi-transparent even if they are originally opaque. The valid values for the property Opacity are 0 .. 255, whereby the smaller the value the more transparent the resulting items. For example:

Connect Horizontal List with a Slide Touch Handler

For your convenience the Core::HorizontalList class implements an interface for easy coupling Horizontal Lists with Slide Touch Handlers. In this manner, the user can scroll the content displayed within the list by simply touching the associated Slide Touch Handler. Assuming that you have already a Horizontal List in your GUI component, then:

Follow the instructions to add a new Slide Touch Handler.

Arrange the Slide Touch Handler so it covers the area of the destined Horizontal List.

Assign the Slide Touch Handler to the property SlideHandler of the Horizontal List.

If desired, configure the property SnapNext of the Slide Touch Handler with the width of an item, so that the handler will automatically stop at the borders between items.

TIP

If the items within the Horizontal List implement any touch handler, it is convenient to reorder the Slide Touch Handler just behind the Horizontal List in order to ensure, that the handler doesn't overlap any of the items managed by the Horizontal List. Otherwise the items will be suppressed in the processing of their touch events. See also Combine several touch handlers together.

Select an item within the list

With the property SelectedItem you can specify the index of the item to be considered as currently selected within the list. Depending on your application case, the affected item can adapt its appearance and e.g. be shown highlighted. Moreover, if the Horizontal List is currently focused for keyboard inputs, the selected item will also be able to handle the keyboard events. Initializing the property SelectedItem with the value -1 deselects the currently selected item without selecting another one.

The property SelectedItem is convenient, if you intend to present to the user a list with options and you want the currently selected option being shown highlighted. The user can scroll the list and select another option, if desired. Such list can e.g. present languages available on the device:

When the property SelectedItem is modified, the Horizontal List informs the GUI components displaying the affected items, that their selection state has changed. This causes the UpdateViewState methods of the components being called. In the implementation of this method you can evaluate the current selection state and depending on it show or hide any highlight decorations. More about the state management and the implementation of the UpdateViewState method is found in the chapter Managing component state.

The following example demonstrates how the property SelectedItem is used. It implements a simple language selection list. The user can scroll the list and select the desired language by simply taping on the corresponding item. The current language is highlighted as demonstrated in the screenshot above:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

Implement keyboard navigation

The above described property SelectedItem is ideal to implement lists which the user can control by using the keyboard. The property SelectedItem is used then to refer to the item which is currently selected. When the user presses a key e.g. Left or Right, the value of the property SelectedItem is decreased or increased causing the selection being moved accordingly. To implement such keyboard navigation:

Follow the instructions to add a new Key Press Handler.

Configure the property Filter of the Key Press Handler with the value Core::KeyCode.CursorKeys to react to cursor keys only.

Add a new slot method to your GUI component.

Assign the slot method to the property OnPress of the previously added Key Press Handler.

Open the slot method for editing.

In the Code Editor implement the following Chora code:

// Which item is currently selected? var int32 itemNo = HorizontalList.SelectedItem; // When the user presses the 'LEFT' or 'UP' key, get the index of the next // higher item if (( KeyHandler.Code == Core::KeyCode.Left ) || ( KeyHandler.Code == Core::KeyCode.Up )) itemNo = itemNo - 1; // When the user presses the 'RIGHT' or 'DOWN' key, get the item of the // item below. if (( KeyHandler.Code == Core::KeyCode.Right ) || ( KeyHandler.Code == Core::KeyCode.Down )) itemNo = itemNo + 1; // The upper or lower end of the list has been reached if (( itemNo < 0 ) || ( itemNo >= HorizontalList.NoOfItems )) return; // Select the item ... HorizontalList.SelectedItem = itemNo; // ... and eventually scroll the list, so the item is fully visible. HorizontalList.EnsureVisible( itemNo, true, null, null );

In particular, when controlling your device by the keyboard, it is interesting to know, that as long as the Horizontal List is focused for keyboard inputs the currently selected item is also able to handle the events. In other words, when you press a key, the corresponding event arrives also to the GUI component of the currently selected item.

The following example demonstrates the implementation of a Horizontal List with keyboard navigation:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.20

Arrange other views on the content of the Horizontal List

Sometimes it is necessary to know the position of individual items within the Horizontal List or to query which item lies at a given position. This can, for example, be the case when the user taps the list and you want to perform operation associated with the affected item.

The Core::HorizontalList class provides for such application cases various useful methods. The following table gives you a short overview of them:

Method

Description

GetItemsArea()

Returns the rectangular area containing one or more items specified in the parameters of the method.

GetItemAtPosition()

Returns the index of the item lying at the given position. The items are numbered starting with 0 (zero). If no item is found at the position, the method returns -1.

GetPaddingLeftArea()

Returns the rectangular area within the list view reserved for the padding specified in the property PaddingLeft. See also section below.

GetPaddingRightArea()

Returns the rectangular area within the list view reserved for the padding specified in the property PaddingRight. See also section below.

You can call those methods whenever your GUI component implementation requires the corresponding information. More sophisticated, however, is to join the update mechanism provided natively by the Horizontal List. Precisely, when you assign a slot method to its property OnUpdate, the slot method will receive postsignals every time the list is scrolled or changed. Accordingly, within the slot method you can react on this notification and e.g. arrange other views at the right position. The following steps describe how to do this:

First add a new slot method to your GUI component.

Assign the slot method to the property OnUpdate of the Horizontal List.

Open the slot method for editing.

In the Code Editor implement your desired arrangement algorithm by using the values returned from the above described Horizontal List methods.

Let's assume, you want to add a scrollbar to your Horizontal List. The position and the size of the scrollbar should reflect the current scrolling situation within the Horizontal List. For this purpose implement the slot method as follow. In this example, the scrollbar is represented by a simple Filled Rectangle view:

// Get the boundary area of the Horizontal List var rect viewRect = HorizontalList.Bounds; // Get the complete area enclosing all list items var rect contentRect = HorizontalList.GetItemsArea( 0, HorizontalList.NoOfItems - 1 ); // From the proportion between the both areas calculate the relative position // of the left and right end of the scrollbar. The max. width of the scrollbar // is the width of the Horizontal List itself (viewRect.w). var int32 x1 = (( viewRect.x1 - contentRect.x1 ) * viewRect.w ) / contentRect.w; var int32 x2 = (( viewRect.x2 - contentRect.x1 ) * viewRect.w ) / contentRect.w; // Limit the left end of the scrollbar if ( x1 < 0 ) x1 = 0; // Limit the right end of the scrollbar if ( x2 > viewRect.w ) x2 = viewRect.w; // Arrange the scrollbar, so it appears below the Horizontal List with 10 pixel // margin. The scrollbar itself is 10 pixel wide. Scrollbar.Bounds = rect( x1 + viewRect.x1, viewRect.y2 + 10, x2 + viewRect.x1, viewRect.y2 + 20 );

The following example demonstrates the implementation of the scrollbar:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

Add padding at the begin and at the end of the list

In some cases it is necessary to display a header or footer contents just before the first or after the last list item. The Horizontal List, however, is restricted to display items only. The solution is to reserve some space on the left of the first or/and on the right of the last item and within your GUI component arrange there the desired header or footer contents. The additional space is specifying in the properties PaddingLeft and PaddingRight. Both properties expect the space being expressed in pixel.

As soon as the property PaddingLeft is greater than 0 (zero), the Horizontal List calculates with an additional space just before the first item. This gap is considered as being part of the entire list. When the list scrolls the gap is scrolled with it. Similarly, when the property PaddingRight is greater than 0 (zero), the Horizontal List will manage an additional gap just after the last item. The following figure demonstrates how the settings of those properties affect the layout of the Horizontal List. The reserved padding areas are used then to accommodate header and footer contents:

Once configured the desired left or right padding, you can arrange in your component some header or footer contents to overlap the padding areas. Usually, you will implement for this purpose a slot method and assign it to the property OnUpdate as described above. The Horizontal List provides the methods GetPaddingLeftArea() and GetPaddingRightArea() you can call from the OnUpdate slot method in order to obtain the current position and the size of the respective padding area. Knowing the area, it is simple to arrange there the desired header or footer contents. Following is an example of how the OnUpdate slot method is implemented in such case:

HeaderComponent.Bounds = HorizontalList.GetPaddingLeftArea(); FooterComponent.Bounds = HorizontalList.GetPaddingRightArea();

Using this implementation, the header and footer components are updated automatically when the items in the list are scrolled. The additional components, however, don't belong to the Horizontal List. They are ordinary sibling views of it. Accordingly, unlike the items within the list, the header and the footer are permanently visible even if they are arranged outside the boundary area of the Horizontal List. As long as the Horizontal List occupies the entire space of the GUI component, this is unproblematic. However, if the list view is smaller, then you have to ensure that header or footer components disappear when they are scrolled outside the list view area.

This can be achieved by displaying the header and the footer components embedded within an Outline Box, which is configured to exactly overlap the Horizontal List. As soon as the header or footer components leave the boundary area of the Outline Box, they are clipped and not visible. To do this:

Follow the instructions to add a new Outline Box to your GUI component.

Arrange the Outline Box, so it exactly overlaps the Horizontal List.

Embed the header and/or the footer components within the Outline Box.

Please note, that being individually specified by the properties PaddingLeft and PaddingRight, neither the header nor the footer have to correspond to the width of a regular list item. This can thus be used to manage within the list a kind of an additional leading and trailing item with different width even if the list is restricted to its items having the same width.

TIP

If you have connected the Horizontal List with a Slide Touch handler configured to automatically snap at the borders between two items, you should also specify the width of the left and right padding in the corresponding properties SnapFirst and SnapLast of the Slide Touch Handler. With it, the handler will stop at the borders between the header, footer and the regular items.

The following example demonstrates, how the additional header and footer are managed with a Horizontal List. This example uses also the Outline Box to clip header and footer as soon as these leave the area of the Horizontal List. The user has the impression, that the header and footer are regular list contents:

DOWNLOAD EXAMPLE

Please note, the example presents eventually features available as of version 8.10

Control the visibility of the Horizontal List

The Horizontal List itself is not visible, except in the Composer window, where it appears tinted with green color. The Horizontal List provides however a property Visible. This property affects the visibility of the items displayed within the list. Also the opacity may affect the resulting appearance of the items in the Horizontal List.

TIP

In the complete GUI application an individual view is visible on the screen only when all of its superior Owner components are visible too, the view itself does lie within the visible area of the superior components and the view is not covered by other sibling views nor components.