Added GridAdapter

This commit is contained in:
anoshenko 2024-06-06 16:20:15 +03:00
parent f9d7c77500
commit d0d81907eb
5 changed files with 207 additions and 5 deletions

View File

@ -1,6 +1,7 @@
# v0.16.0
* Can use ListAdapter as "content" property value of ListLayout
* The IsListItemEnabled method of the ListAdapter interface has been made optional
* Can use GridAdapter as "content" property value of GridLayout
* Bug fixing
# v0.15.0

View File

@ -2344,13 +2344,13 @@ ListAdapter используется для создания дочерних Vi
Соответственно функции этого интерфейса должны возвращать количество элементов и View i-го элемента.
ListAdapter создает дочерние View в момент установки свойства "content".
Для пересоздания дочерних элементов ListLayout имеет свойство UpdateContent().
Для пересоздания дочерних элементов ListLayout имеет метод UpdateContent().
Данный метод удаляет все дочерние View и создает их заново используя ListAdapter.
Внимание! При вызове метода UpdateContent() данные из старых View не переносятся в заново создаваемые.
Вы должны сделать это в ручную.
Если свойство "content" присвоен не ListAdapter, то метод UpdateContent() ничего не делает.
Если свойству "content" присвоен не ListAdapter, то метод UpdateContent() ничего не делает.
Вызвать метод UpdateContent можно также с помощью глобальной функции
@ -2435,6 +2435,50 @@ GridLayout является контейнером, реализующим ин
Все дочерние элементы располагаются в ячейках таблицы. Ячейка адресуется по номеру строки и
столбца. Номера строк и столбцов начинаются с 0.
### "content"
Свойство "content" (константа Content) определяет массив дочерних View.
Данное свойство унаследовано от ViewsContainer.
Также как и для ViewsContainer данному свойству можно присваивать следующие типы данных:
* View (преобразуется во []View содержащий один View);
* []View;
* string (преобразуется во []View содержащий один TextView);
* []string (преобразуется во []View содержащий TextView);
* []any - данный массив должен содержать только View и string (преобразуется в TextView).
Однако кроме этих типов данных свойству "content" GridLayout может быть назначена реализация интерфейса GridAdapter.
GridAdapter используется для создания дочерних View и объявлен как
type GridAdapter interface {
GridColumnCount() int
GridRowCount() int
GridCellContent(row, column int, session Session) View
}
Соответственно функции этого интерфейса должны возвращать количество столбцов и строк и View элемента в позиции (row, column).
Кроме этих трех обязательных методов, при реализации GridAdapter, могут быть заданы еще два опциональных:
GridCellColumnSpan(row, column int) int
GridCellRowSpan(row, column int) int
Первый метод задает сколько столбцов занимает View в позиции (row, column) а вторая - сколько строк.
GridAdapter создает дочерние View в момент установки свойства "content".
Для пересоздания дочерних элементов GridLayout имеет метод UpdateGridContent().
Данный метод удаляет все дочерние View и создает их заново используя GridAdapter.
Внимание! При вызове метода UpdateGridContent() данные из старых View не переносятся в заново создаваемые.
Вы должны сделать это в ручную.
Если свойству "content" присвоен не GridAdapter, то метод UpdateGridContent() ничего не делает.
Вызвать метод UpdateGridContent можно также с помощью глобальной функции
func UpdateContent(view View, subviewID ...string)
### "column" и "row"
Расположение View внутри GridLayout определяется с помощью свойств "column" и "row".

View File

@ -2410,6 +2410,51 @@ The container space of this container is split into cells in the form of a table
All children are located in the cells of the table. A cell is addressed by row and column number.
Row and column numbers start at 0.
### "content"
The "content" property (Content constant) defines an array of child Views.
This property is inherited from ViewsContainer.
Just like for ViewsContainer, this property can be assigned the following data types:
* View (converts to []View containing one View);
* []View;
* string (converts to []View containing one TextView);
* []string (converts to []View containing TextView);
* []any - this array must contain only View and string.
However, in addition to these data types, the "content" property of a GridLayout
can be assigned an implementation of the GridAdapter interface.
GridAdapter is used to create child Views and is declared as
type GridAdapter interface {
GridColumnCount() int
GridRowCount() int
GridCellContent(row, column int, session Session) View
}
Accordingly, the functions of this interface must return the number of columns and rows and the View of the element at position (row, column).
In addition to these three required methods, when implementing a GridAdapter, two more optional ones can be specified:
GridCellColumnSpan(row, column int) int
GridCellRowSpan(row, column int) int
The first method sets how many columns the View occupies in (row, column) position and the second sets how many rows.
GridAdapter creates child Views when the "content" property is set.
To recreate child elements, GridLayout has the UpdateGridContent() method.
This method deletes all child Views and creates them again using the GridAdapter.
Attention! When calling the UpdateGridContent() method, data from old Views is not transferred to newly created ones.
You must do this manually.
If the "content" property is not set to a GridAdapter then the UpdateGridContent() method does nothing.
You can also call the UpdateGridContent method using the global function
func UpdateContent(view View, subviewID ...string)
### "column" and "row" properties
The location of the View inside the GridLayout is determined using the "column" and "row" properties.

View File

@ -43,13 +43,43 @@ const (
CellHorizontalSelfAlign = "cell-horizontal-self-align"
)
type GridAdapter interface {
// GridColumnCount returns the number of columns in the grid
GridColumnCount() int
// GridRowCount returns the number of rows in the grid
GridRowCount() int
// GridCellContent creates a View at the given cell
GridCellContent(row, column int, session Session) View
}
// GridCellColumnSpanAdapter implements the optional method of GridAdapter interface
type GridCellColumnSpanAdapter interface {
// GridCellColumnSpan returns the number of columns that a cell spans.
// Values less than 1 are ignored.
GridCellColumnSpan(row, column int) int
}
// GridCellColumnSpanAdapter implements the optional method of GridAdapter interface
type GridCellRowSpanAdapter interface {
// GridCellRowSpan returns the number of rows that a cell spans
// Values less than 1 are ignored.
GridCellRowSpan(row, column int) int
}
// GridLayout - grid-container of View
type GridLayout interface {
ViewsContainer
// UpdateContent updates child Views if the "content" property value is set to GridAdapter,
// otherwise does nothing
UpdateGridContent()
}
type gridLayoutData struct {
viewsContainerData
adapter GridAdapter
}
// NewGridLayout create new GridLayout object and return it
@ -69,6 +99,7 @@ func (gridLayout *gridLayoutData) init(session Session) {
gridLayout.viewsContainerData.init(session)
gridLayout.tag = "GridLayout"
gridLayout.systemClass = "ruiGridLayout"
gridLayout.adapter = nil
}
func (gridLayout *gridLayoutData) String() string {
@ -257,14 +288,19 @@ func (gridLayout *gridLayoutData) Remove(tag string) {
}
func (gridLayout *gridLayoutData) remove(tag string) {
if tag == Gap {
switch tag {
case Gap:
gridLayout.remove(GridRowGap)
gridLayout.remove(GridColumnGap)
gridLayout.propertyChangedEvent(Gap)
return
case Content:
gridLayout.adapter = nil
}
gridLayout.viewsContainerData.remove(tag)
if gridLayout.created {
switch tag {
case CellWidth:
@ -289,8 +325,17 @@ func (gridLayout *gridLayoutData) set(tag string, value any) bool {
return true
}
if tag == Gap {
switch tag {
case Gap:
return gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value)
case Content:
if adapter, ok := value.(GridAdapter); ok {
gridLayout.adapter = adapter
gridLayout.UpdateGridContent()
return true
}
gridLayout.adapter = nil
}
if gridLayout.viewsContainerData.set(tag, value) {
@ -312,6 +357,70 @@ func (gridLayout *gridLayoutData) set(tag string, value any) bool {
return false
}
func (gridLayout *gridLayoutData) UpdateGridContent() {
if adapter := gridLayout.adapter; adapter != nil {
gridLayout.views = []View{}
session := gridLayout.session
htmlID := gridLayout.htmlID()
isDisabled := IsDisabled(gridLayout)
var columnSpan GridCellColumnSpanAdapter = nil
if span, ok := adapter.(GridCellColumnSpanAdapter); ok {
columnSpan = span
}
var rowSpan GridCellRowSpanAdapter = nil
if span, ok := adapter.(GridCellRowSpanAdapter); ok {
rowSpan = span
}
width := adapter.GridColumnCount()
height := adapter.GridRowCount()
for column := 0; column < width; column++ {
for row := 0; row < height; row++ {
if view := adapter.GridCellContent(row, column, session); view != nil {
view.setParentID(htmlID)
columnCount := 1
if columnSpan != nil {
columnCount = columnSpan.GridCellColumnSpan(row, column)
}
if columnCount > 1 {
view.Set(Column, Range{First: column, Last: column + columnCount - 1})
} else {
view.Set(Column, column)
}
rowCount := 1
if rowSpan != nil {
rowCount = rowSpan.GridCellRowSpan(row, column)
}
if rowCount > 1 {
view.Set(Row, Range{First: row, Last: row + rowCount - 1})
} else {
view.Set(Row, row)
}
if isDisabled {
view.Set(Disabled, true)
}
gridLayout.views = append(gridLayout.views, view)
}
}
}
if gridLayout.created {
updateInnerHTML(htmlID, session)
}
gridLayout.propertyChangedEvent(Content)
}
}
func gridCellSizes(properties Properties, tag string, session Session) []SizeUnit {
if value := properties.Get(tag); value != nil {
switch value := value.(type) {

View File

@ -245,7 +245,7 @@ func GetListColumnGap(view View, subviewID ...string) SizeUnit {
return sizeStyledProperty(view, subviewID, ListColumnGap, false)
}
// UpdateContent updates child Views of ListLayout subview if the "content" property value is set to ListAdapter,
// UpdateContent updates child Views of ListLayout/GridLayout subview if the "content" property value is set to ListAdapter/GridAdapter,
// otherwise does nothing.
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) updates.
func UpdateContent(view View, subviewID ...string) {
@ -255,6 +255,9 @@ func UpdateContent(view View, subviewID ...string) {
if view != nil {
switch view := view.(type) {
case GridLayout:
view.UpdateGridContent()
case ListLayout:
view.UpdateContent()