Skip to content

Fyne List Proposal

Stuart Scott edited this page Apr 4, 2020 · 8 revisions

Using the upcoming Data API/Bindings we can begin to create widgets that can take advantage.

The most requested/needed of these widgets is likely a List.

The list widget should be performant and to achieve that we have the following proposal:

  • The list widget will have a layout that contains a scroller
  • The list widget will use a layout that determines the visible viewport of the scroller and only creates/shows the visible list items +/- 3 items above and below the visible area. This calculation can be done by determining the total number of list items through the data api and then determining the size of a list item. For instance - if the list has 100 items, and each item has a height of 20, which will be determined from the height of the first item since items will expand horizontally and not vertically, the total height of the list will be 2000 pixels. If the visible viewport of the scroller is y = 100 and h = 200, we know the visible items that will be 100 / 20 (the item height) - which will be item 5, through 300 / 20 - (300 being y + height) will be item 15. +/- 3 items above and below tells us that we will need to create list items 2 through 18.
  • As the scroller scrolls this math can be redone and the objects can be reused and updated with the new list item content that we get from the data api.
  • The items can be reused because list will assume all items are the same layout/widget/etc... I.e. all are labels, or all are an hbox with an icon and label, etc... This information will be determined from the first item. This will keep the list performant and allow it to easily handle large lists.

One question that remains - how should we determine a minimum width for the list items. Should it be:

  • Explicitly set by the developer?
  • Maths based off of finding the largest list item and using it's width? Either on the fly or as data is set
  • Be ignored and allow the parent of the list to control? I.e. a max width layout would just expand it but being in a border on a border layout would make it unviewable?
  • Based off the width of the first item?
  • And for any of the above, Should the scroller have the ability to disable scroll directions so that we truncate rather than expand items horizontally?

Architecture

There are four main components involved with displaying a list of items;

  • SliceBinding - provides access to the underlying data slice and triggers listeners when it changes.
  • CellAdapter - configures a canvasobject to display the data item.
  • ListWidget - renders a range of items from the data slice and receives events.
  • CellPool - maintains a collection of canvasobjects to be reused rather than allocating a new one.

SliceBinding

type SliceBinding interface {
    // Returns the number of items in the data slice.
    Length() int
    // Returns the item at the given index.
    Get(int) Binding
    // Adds the given listener to the binding to be notified whenever length changes. TODO what if an element of the slice is replaced?
    AddListener(func(SliceBinding))
    // TODO should there also be RemoveListener?
}

CellAdapter

type CellAdapter interface {
    // Return the number of different types of cells.
    Types() int
    // Returns the type of the cell at the given index.
    TypeOf(index int) int
    // Creates a cell of the given type.
    Create(type int) CanvasObject
    // Binds the given canvas object to the binding.
    Bind(CanvasObject, Binding)
    // TODO should there also be an unbind to detach the canvasobject listener from the binding?
}

ListWidget

list := &widget.List{}
list.BindItems(SliceBinding, CellAdapter)
list.OnSelected = func(index int) {
    log.Println("Selected:", index)
}

CellPool

type CellPool interface {
    Obtain() CanvasObject
    Release(CanvasObject)
}

Welcome to the Fyne wiki.

Project documentation

Getting involved

Platform details

Clone this wiki locally