544 views
in GUI Development by
I want to realize a HorizontalScrollList, which has the characteristic that the item in the middle has different distances to his neighbour-items than the rest.

The HorizontalScrollList of the Mosaic Framework assumes that all items has the same distance to one another. But the ScrollList I want violates this assumtion.

My HorizontalScrollList has an item in the middle. This item has a different distance X1 to the left neighbour and a different distance X2 to the right neighbour. The rest of the items has the same distance X3 to his neighbours.

Is there a good way to implement such a ScrollList ?

1 Answer

+2 votes
by

This article demonstrates one possible approach how to implement a fancy scroll list. In this particular application case the list should show any number of items with the special aspect of the items lying in the center area of the list to appear bigger. All remaining items have their regular size. The implementation is demonstrated on the example of a horizontal list.

Mosaic class library provides various list and outline components. Unfortunatly none of them is sufficiently sophisticated to directly provide the necessary functionality. We need thus to implement it by ourselves.

Let analyze the application case:

  • The list consists of items arranged horizontally side by side.
  • Most of the items have the same (regular) size.
  • Only the item lying in the center area can appear bigger.
  • When the user scrolls the list, the item which enters the center area is enlarged.
  • Accordingly, the item which leaves the center area shrinks to its regular size.
  • Therefore there are max. 2 items with size diferent to the regular size.
  • All items lying to the left of the bigger (center) item have regular size.
  • All items lying to the right of the center item have also the regular size.
The list can thus be composed of three areas:
  • A list containing regular items lying to the left of the center item.
  • A list also with regular items lying to the right of the center area.
  • A group component managing the items in the center area. These items can appaer bigger.

The following image demonstrates the implementation idea:

The blue area covers the items shown and managed by the left list. The green area in turn covers the items managed by the right list. The red color determines the center area where items may appear bigger. In the above image the Item N+5 was placed exactly in the center of the list. Accordingly the item appeared with the max. possible size. All remaining items have their regular size.

This changes when the user scrolls the list. The item which enters the center area becomes bigger while the item which leavs the area restores its regular size. The next image demonstrates it:

Thus the both lists (left and right) show always items with their regular size. Both lists are also scrolled simultanously. Here we can use one of the ready-to-use Mosaic list components. For example the HorizontalList.

The handling of the items lying in the center area, in turn, requires more effort. Primarily we need a group component to accommodate these items. The group will ensure that items leaving the center area are correctly clipped. Otherwise the items would overlay the items from the let/right list. Having the group we need to calculate the position and the size of the items within the center area.

All calculation is based on a ScrollOffset property implemented in the list component. Every alternation of the property changes accordingly the scroll-offset of the left and right list, and, recalculates the position/size of items in the center area.

This article includes an example project demonstrating this approach. This implementation is inline documented. For more details see inside the example:

http://ask.embedded-wizard.de/?qa=blob&qa_blobid=16719120764619354066

by
As I implement an infinite list (Endless) in the example.
by

Hello,

if you are looking for endless list functionality, with Embedded Wizard 8.20 we have enhanced the list components by the property Endless. Please see the following documentation:

Vertical List : Configure an endless list

Horizontal List : Configure an endless list

Does it help you further?

Best regards

Paul Banach

by
Hello, thanks for answering.
I want to implement an endless list with the largest central element, and HorizontalList does not have that functionality, I found the example: http://ask.embedded-wizard.de/?qa=blob&qa_blobid=16719120764619354066. but this one does not have infinite list functionality. How can I implement it?

Thank you, Daniel
by

Hello Daniel,

To achieve the desired endless behavior you can modify the provided example. Following are the necessary steps:

Step 1: Navigate to the class Application::List. There you see two Horizontal List views: ListR and ListL. Select the views and change their properties Endless to the value true as shown in the screenshot below:

Step 2: In the class Application::List open the method UpdateViewState and replace its code with the following version. This enhances the original implementation by special handling of the overflow when the list scrolls endless:

super( aState );

if ( ItemClass == null )
  return;

// Calculate the size of the center area and the of the list lying to the left of it.
var point bounds      = Bounds.size;
var int32 widthCenter = CenteredItemSize.x + RegularItemSize.x * 2;
var int32 widthListL  = ( bounds.x - widthCenter ) / 2;

// Calculate the scroll-offsets for the both lists.
ListL.ScrollOffset = ScrollOffset + widthListL + RegularItemSize.x;
ListR.ScrollOffset = ScrollOffset - RegularItemSize.x * 2;

// Calculate the difference to maximaly enlarge the item in the center compared to the
// size of a regular item. Calculate also the scroll offset expressed within the range
// of a single item. This means, 'offset' will lie in 0 .. (RegularItemSize.x - 1).
var point maxDelta = CenteredItemSize - RegularItemSize;
var int32 offset   = 0;

if   ( ScrollOffset >= 0 ) offset =  RegularItemSize.x - ( ScrollOffset % RegularItemSize.x );
else                       offset = -ScrollOffset % RegularItemSize.x;

// Knowing the scroll offset within a single item, the resulting enlargement of the
// item in the center area.
var   int32 deltaX = ( offset * maxDelta.x ) / RegularItemSize.x;
var   int32 deltaY = ( offset * maxDelta.y ) / RegularItemSize.x;
array point size[4];

// Now calculate the size of the items in the center area. To simplify the application
// case we work with up to 4 items within the center area.
size[0] = RegularItemSize;
size[1] = point( RegularItemSize.x + maxDelta.x - deltaX,
                 RegularItemSize.y + maxDelta.y - deltaY );
size[2] = point( RegularItemSize.x + deltaX, RegularItemSize.y + deltaY );
size[3] = RegularItemSize;

// Now get the number of the item at the left edge of the center area.
var int32 firstItem = 0;
var int32 i;

if ( ScrollOffset >= 0 ) firstItem = -2 - ( ScrollOffset / RegularItemSize.x );
else                     firstItem = -1 - ( ScrollOffset / RegularItemSize.x );

// Process the items in the center area. Show/hide the items if there is no content
// assocuated to them. Move and resize the itmes.
for ( i = 0; i < centerItems.size; i = i + 1 )
{
  // Derive the number of the item and determine the view used in the center area to
  // represent the item.
  var int32          item = firstItem + i;
  var Core::RectView view = (Core::RectView)Center.GetViewAtIndex( i );

  if ( item < 0 )
    item = NoOfItems - ( -item % NoOfItems );

  item = ( item + NoOfItems ) % NoOfItems;

  // Is there a content for this item available?
  if (( item >= 0 ) && ( item < NoOfItems ))
  {
    // The view is not valid. Reload the view.
    if ( item != centerItems[i])
    {
      Item = item;
      View = view;
      signal OnLoadItem;
      Item = -1;
      View = null;

      // Remember that the 'i' view has been loaded with the content of the item
      // 'item'. In this manner avoid the views to reload its content permanently.
      centerItems[i] = item;
    }

    // Ensure that the view is visible.
    view.ChangeViewState( Core::ViewState[ Visible ], Core::ViewState[]);
  }

  // No associated content - hide the view.
  else
    view.ChangeViewState( Core::ViewState[], Core::ViewState[ Visible ]);

  // The vertical position to arrange the item centered.
  var int32 vertPos = ( bounds.y - size[i].y ) / 2;
  
  // Arrange the item at the calculated offset position. Assign the item its new
  // size.
  view.Bounds = rect( -offset, vertPos, -offset + size[i].x, vertPos + size[i].y );

  // The position for the next item. It should follow immediately.
  offset = offset - size[i].x;
}

Step 3:  In the class Application::List open the method onStartSlideSlot and replace its code with the following version. This changes the original implementation to provide an 'endless' (in fact 32k Pixel large) scroll area:

// Allow the user to scroll ~32 k pixel left/right
var int32 offset = 32000 - ( 32000 % pure RegularItemSize.x );

// Initialize the slide handler
SlideHandler.Offset    = point( pure ScrollOffset, 0 );
SlideHandler.MinOffset = point( pure ScrollOffset - offset, 0 );
SlideHandler.MaxOffset = point( pure ScrollOffset + offset, 0 );

That is sufficient to enhance the fancy list with the endless functionality.

Nevertheless, the referenced example demonstrates just one possible application case. In practice, the behavior of such fancy list is always very individual to the expected UI design. With this I want to say, that with Embedded Wizard you get the framework with many components to assemble the GUI application. Individual desires expect however individual adaptations.

I hope it helps you further,

Bets regards

Paul Banach

by
Hello Paul,

Thank you very much for your help. the list worked correctly.
Unfortunately I do not master the Embedded Wizard.

Greetings Daniel.

Embedded Wizard Website | Privacy Policy | Imprint

...