Skip to main content

Supporting different items

Let's make a virtualized list that combines different kinds of items, in this case categories of continents, and a list of countries underneath.

First, we're going to create a tagged union representing our items. That means we have one type that can refer to multiple things.

type Item =
{
type: "category",
name: string,
}
| {
type: "text",
text: string,
}

Next, we are going to prepare to use a getter dimension, since these items have different heights. Recall that a getter dimension is stateless, meaning you will only get the item you have. Therefore, let's create a second type that includes this information:

type ItemWithUDimRect = {
item: Item,
udimRect: UltimateList.UDimRect,
}

Now we'll prepare that list.

-- Assuming ITEMS is an array of Item...
local itemsWithUDimRects: { ItemWithUDimRect } = {}
local nextPosition = UDim2.new()

for _, item in ITEMS do
local height = if item.type == "category" then 32 else 24

table.insert(itemsWithUDimRects, {
item = item,
udimRect = {
size = UDim2.new(1, 0, 0, height),
position = nextPosition,
},
})

nextPosition += UDim2.fromOffset(0, height)
end

We use the type of the item to determine its height, and then use that information to prepare the position of the succeeding elements. Now, let's prepare the scrolling frame. We'll pass in itemsWithUDimRects to our ScrollingFrame, and use that data in getter.

ScrollingFrame = e(UltimateList.Components.ScrollingFrame, {
dataSource = UltimateList.DataSources.array(itemsWithUDimRects),
dimensions = UltimateList.Dimensions.getter(function(itemWithUDimRect: ItemWithUDimRect)
return itemWithUDimRect.udimRect
end),
renderer = UltimateList.Renderers.byState(function(itemWithUDimRect: ItemWithUDimRect)
-- soon...
end),

direction = "y",
}),

Finally, let's render different things based on the item we have. Once again, we check the type field to know what we are.

renderer = UltimateList.Renderers.byState(function(itemWithUDimRect: ItemWithUDimRect)
if itemWithUDimRect.item.type == "category" then
return e("TextLabel", {
BackgroundColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.BuilderSansBold,
Text = itemWithUDimRect.item.name,
TextColor3 = Color3.new(0, 0, 0),
TextSize = 30,
Size = UDim2.fromScale(1, 1),
})
else
return e("TextLabel", {
BackgroundColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.BuilderSans,
Text = itemWithUDimRect.item.text,
TextColor3 = Color3.new(0, 0, 0),
TextSize = 20,
Size = UDim2.fromScale(1, 1),
})
end
end),