New UI Widgets

I am dynamically generating a Table in code. I want to dynamically include cells that contain images. Is this possible?

Not sure what you understand under dynamically.

But there are a few possible cases:

  1. Just a cell with the image, and the image is optional. You can disable an Image component (not a game object) if the sprite is not specified otherwise you will have a white rectangle.
    Code in the DefaultItem class can be like this:
public Image ImageCell;
protected void UpdateView()
{
	ImageCell.sprite = Item.Icon;
	ImageCell.enabled = Item.Icon != null;
}
  1. Cell can have either image or text (or some other data).
    In this case, create a separate component for the cell to control displayed data:
public class CellData
{
	public string Name;
	public Sprite Image;
}

public class CellView : MonoBehaviour
{
	public TextAdapter Text;
	public Image Image;

	public void SetData(CellData cell)
	{
		if (cell.Image != null)
		{
			Image.sprite = cell.Image;
			Image.gameObject.SetActive(true);
			Text.gameObject.SetActive(false);
		}
		else
		{
			Image.gameObject.SetActive(false);
			Text.text = cell.Name;
			Text.gameObject.SetActive(true);
		}
	}
}

Then the DefaultItem class can be like this:

public CellView Cell;

protected void UpdateView()
{
	Cell.SetData(Item.SomeCell);
	// ....
}

If the cells have a lot of different widgets and only one of them is needed at once then you may consider using ObjectPool to optimize performance.

Ok, I’ll think about it.

Worked perfectly!

How do I refresh/update an existing table with new and/or changed data? For example, the number of data rows might change, or the data for an existing cell might change.

There are two types of changes:

  1. Collection changes: add, remove, replace, sort items. ListView is automatically updated on those changes.
  2. Item changes: changing fields or properties of an item. ListView will be automatically updated if the data type implements the IObservable or INotifyPropertyChanged interface, more about it in the documentation and video.
    Or you can call the UpdateView() method in your code on item data change: ListView.UpdateView(forced: true, isNewData: true);.

Got it :slight_smile:

I see that the SteamSpyView demo table has sortable table columns for the “pre-built” columns.

I’m adding columns in code and want to be able to sort them when users click on the column header. I suppose I need to pass a new parameter when calling AddColumn(string columnName)? Not sure how to go about it.

To sort items, you need to add a Button component to the column header and a callback on click in the AddColumn() method.
For the TableListTest.cs it will be like this:

public void AddColumn(string columnName)
{
	foreach (var component in Table.GetComponentsEnumerator(PoolEnumeratorMode.All))
	{
		component.AddCell(RowCell);
	}

	var header_cell = Compatibility.Instantiate(HeaderCell);
	header_cell.TextAdapter.text = string.Format("{0} {1}", columnName, Table.DefaultItem.TextAdapterComponents.Count.ToString());
	Header.AddCell(header_cell.gameObject);

	Table.ComponentsColoring();

	// added callback
	var header_index = Header.transform.childCount - 1;
	header_cell.GetComponent<Button>().onClick.AddListener(() => SortByColumn(header_index));
}

int currentColumnSort = -1;

void SortByColumn(int columnIndex)
{
	// reverse sort if data already sorted by this column
	if (currentColumnSort == columnIndex)
	{
		Table.DataSource.Reverse();
		return;
	}

	currentColumnSort = columnIndex;

	// x and y are items to compare
	Table.DataSource.Sort((x, y) =>
	{
		var x_value = x.Count < columnIndex ? x[columnIndex] : int.MinValue;
		var y_value = y.Count < columnIndex ? y[columnIndex] : int.MinValue;

		return x_value.CompareTo(y_value);
	});
}

I have this sorting my column headers now :slight_smile:

However, when reverse sorting (Table.DataSource.Reverse), most of the rows disappear from the Viewport. When I use the scroll wheel, the rows appear again and are properly sorted.

To fix this issue, I added:

        if (Table.DataSource.Count > 0)
        {
            Table.ScrollTo(0);
        }

It’s most probably caused by the enabled “Retain Scroll Position” option: the first visible item will be in the same position from the top border of ListView. This option prevents scroll jumps when new items are added or item sizes are changed.
Please try to disable it to fix the problem.

That fixed it. Thanks for your great support.

I’m adding columns using code. I want my columns to have different widths. How do I specify a different width for each column (and it’s column header width to match)?

Add LayoutElement to the cells, with specified MinWidth and PreferredWidth options
(cells in the same column should have the same options).


MinWidth is the minimal width of the cell.
PreferredWidth specifies how free space (table width minus total minimal width of all cells) is distributed between cells.
cell width = MinWidth + (PreferredWidth / TotalPreferredWidth) * FreeSpace
Example: Two cells, one with PreferredWidth = 1 and the other with PreferredWidth = 3, both with MinWidth = 100 and a table width is 400.
FreeSpace = 200 (400 - 100 - 100)
First cell width = 150 (100 + 1/4 * 200)
Second cell width = 250 (100 + 3/4 * 200)

Add the HorizontalLayoutGroup component to the Header and DefaultItem if not already added.

v1.17.16 is released

Changelog:

  • Effects: fixed bug with zero vertices (like Text component without any text)
  • ListView: added the KeepScrollAtBottom option, which keeps the scroll at the bottom on DataSource changes (only if the scroll is already at the bottom)
  • ObservableListFilter: Output now uses the same comparison as Input
  • Widgets Generator: added option to specify paths for the created scripts, prefabs, scenes, etc
  • Widgets Generator: added GeneratorPaths attribute to specify paths directly in the data type
  • Widgets Generator: added GeneratorNamespace attribute to specify namespaces for the created scripts directly in the data type
  • shaders: fixed bug related to HDR
  • shaders: fixed bug related to VR

Getting there :slight_smile:

1 Like

v1.18.0 is released

Changelog:

  • Dialog, Picker, Popup: added animations support, for the existing dialogs/pickers/popups you can add the WindowAnimations component or create a custom animation component with IWindowAnimations implementation
  • EasyLayout: removed incorrect warning in some cases
  • Notification: added the NotificationsAnimations component for open/close animations, it has more priority than ShowAnimation and HideAnimation fields and arguments, you can create a custom animation component with the IWindowAnimations implementation
  • TableHeader: added the FillContextMenu and ContextMenuNames options to automatically fill ContextMenu to enable/disable columns
  • UtilitiesTime static fields were replaced with WidgetsTime.Instance
  • Widgets Generator: added ContextMenu to enable/disable table columns
  • reduced amount of static fields
1 Like

@ilih

Hi,

Im using your widgets datetime picker, i will select a date from the widget and assign that date to the input field and update the same date to database, then when i come next day and open my application, the input field already has a value which was updated previous day, when i open date time picker it shows today’s or that instance date and time, As the default date and time is set as today, So how do i set or select the date in the date time picker to the value which is updated to the database.

Thanks

You need to specify the current DateTime when you open the picker:
var result = await DateTimePicker.ShowAsync(date_time_from_DB);
or
DateTimePicker.Show(date_time_from_DB, OnValueSelected, OnCancel);

v1.18.1 is released

Changelog:

  • ContextMenu: now the Visible and Interactable options of menu items are enabled by default
  • Notification: added the AnimateOnHideButton option, if enabled the hide animation will run on HideButton click
  • Notification Animations: the ShowDuration and HideDuration options are obsolete, use the ShowAnimationCurve and HideAnimationCurve options instead
  • Notification Animations: removed the ShowAnimateOthers and HideAnimateOthers options, you can use the EasLayout.MovementAnimation option instead
  • ScrollRectPaginator: now the ActivePage can work even if DefaultPage is not specified
  • UIThemes Support: added support for default/active icons for the TabsIcons
  • Widgets Generator: added support for the R3.SerializableReactiveProperty fields and properties