Post
The blog is a work-in-progress started on Oct 8 '25, expected to last a few weeks

OSA Demo: TableView Implementation Guide

Learn how to implement a TableView using OSA. This guide covers the TableView demo scene, showing you how to create efficient table-based UIs in Unity.

Contents

  1. Description
  2. Quick start
  3. Scene
  4. Code
  5. Summary
  6. Common scenarios

  7. Description

Although this manual refers to the demo scene in the title, this is also the place where you’ll find general information about how to set up tables, and how OSA TableView works.

[In progress] - you may find some additional info in changelog, although not exhaustive.

  1. Quick start

After you imported the TableView package, create a TableView template through OSA Wizard

[Screenshot - see Unity Asset Store documentation for visual guide]

The default options should work out of the box. Now enter play mode and see some sample data:

[Screenshot - see Unity Asset Store documentation for visual guide]

At the current time (18 Nov 2019), by default, the ResizingMode of rows is set to MANUAL, meaning you can resize any of them manually. A more informative notice is displayed in the console regarding resizing modes, especially useful if you don’t need them.

All of the game objects created were instantiated from prefabs located in /Resources/Com.TheFallenGames/OSA/Templates/ScrollViews/TableView. Notably, the TableView itself, the header prefab, the header’s cells prefab, the row prefab and the row’s cells prefab. You can customize them however you want, as long as the base functionality and layout isn’t affected.

The BasicTableAdapter implementation was generated for us, which extends TableAdapter, and internally is just a vertical OSA ListView.

[Screenshot - see Unity Asset Store documentation for visual guide]

TuplePrefab has the BasicTupleAdapter script attached, while the ColumnsTuplePrefab has the ColumnsTuplePrefab attached - both being implementations of a TupleAdapter, which internally are horizontal OSA ListViews:

[Screenshot - see Unity Asset Store documentation for visual guide]

Now let’s look at how that data is generated.

Open BasicTableAdapter and look inside Start(). You can see it has 3 loading types exemplified, from which it uses the second, LoadBufferedDataSync (at least ATM, 18 Nov 2019), but let’s focus on the LoadDataSync, which is the easiest case. If you change the code so that LoadDataSync is called instead, you’ll see no noticeable difference, but of course there is. We’ll discuss that later. So here’s LoadDataSync:

1
public void LoadDataSync(){	Columns = RetrieveColumns();	int tuplesCount = 500;	var tuples = new ITuple\[tuplesCount\];	ReadRandomTuples(tuples, 0, tuplesCount);	Tuples = new BasicTableData(Columns, tuples, true */*allow column sorting*/*);	ResetTableWithCurrentData();}

As you can see, we specify the columns and the data, and then reset the TableAdapter to visualize the changes.

If you want a simplified, self-contained version of LoadDataSync, here’s an example:

1
public void LoadDataSync(){	Columns = new BasicTableColumns(		new List<BasicColumnInfo>		{			new BasicColumnInfo("Col 1", TableValueType.STRING),			new BasicColumnInfo("Col 2", TableValueType.STRING),			new BasicColumnInfo("Col 3", TableValueType.STRING),			new BasicColumnInfo("Col 4", TableValueType.STRING),		}	);	var tuples = new ITuple\[500\];	for (int i = 0; i < tuples.Length; i++)	{		tuples\[i\] = TableViewUtil.CreateTupleWithEmptyValues<BasicTuple>(Columns.ColumnsCount);		*// Alternatively, you can use new BasicTuple(<list or array of values>)*		for (int j = 0; j < Columns.ColumnsCount; j++)			tuples\[i\].SetValue(j, "Value of R"\+i+"C" \+ j);	}	Tuples = new BasicTableData(Columns, tuples, true */*allow column sorting*/*);	ResetTableWithCurrentData();}

Try it and see what you get.

Now back to the generated code. Of course, RetrieveColumns and ReadRandomTuples are our custom methods. We could’ve populated Columns and Tuples inline, directly in LoadDataSync, but why not separate concerns?:

1
ITableColumns RetrieveColumns(){	var columnInfos = new List<BasicColumnInfo>();	for (int i = 0; i < 25; i++)	{		*// For simplicity, we only create integers, bool and string columns, consecutively.*		var columnType = i % 3 == 0 ? TableValueType.INT : (i % 3 == 1 ? TableValueType.BOOL : TableValueType.STRING);		columnInfos.Add(new BasicColumnInfo("Col " \+ i, columnType));				*// If you want to use TableValueType.ENUMERATION, pass the enum's System.Type to* 		*// the 3rd parameter of BasicColumnInfo's constructor* 	} 	return new BasicTableColumns(columnInfos);}

As you can see, we sampled from 3 types of columns, just for some variety.

Reading the actual rows is also done by generating some random data:

1
void ReadRandomTuples(ITuple\[\] into, int firstItemIndex, int numTuples){	... 	var columns = Columns;	for (int i = 0; i < numTuples; i++)	{		var tuple = TableViewUtil.CreateTupleWithEmptyValues<BasicTuple>(columns.ColumnsCount);		ReadRandomValueIntoTuple(columns, firstItemIndex \+ i, tuple, random);		into\[i\] = tuple;	}}

Of course, you’ll probably set values for tuples by parsing a list of data that you retrieved from somewhere, instead of using ReadRandomValueIntoTuple. An ITuple implementation will have the SetValue(int, object) method, which you’ll use to populate each column in that row with a value, using the column’s index.

ATM, 18 Nov 2019, if you want to dynamically add/remove rows, keep a reference to the List you pass to the BasicTableData and insert/remove items to it, then call ResetTableWithCurrentData. You can also extend BasicTableData and add your own helper methods there for easier access. This will be added in the next version. But you may also want to check BufferredTableData and AsyncBufferredTableData which specifically handle data loading in chunks instead of all at once

  1. Scene

[Screenshot - see Unity Asset Store documentation for visual guide]

The structure is different from a ListView:

[Screenshot - see Unity Asset Store documentation for visual guide]

The content consists of a list of tuples (rows), which are themselves ListViews of single values (cells).

The header is represented by a single tuple that contains the column names, types, sorting arrow. The header’s implementation is based on TupleAdapter, but has custom code that allows it to have the additional functionality needed in a header.

Here we have 2 Scrollbars. The vertical one is tied to the vertical ListView of rows, while the horizontal one is tied to the horizontal ListView of values in the header. The header’s horizontal position influences the horizontal position in the ListView of every row, and vice-versa, thus their positions are always in sync, the end-result being a seamless scroll in each direction, whether you drag the scrollbar, a row or a column (horizontally).

The OptionsPanel contains a basic interface initially with a Delete/Undelete cell button, and a “Loading” indicator (used when data is loaded asynchronously). You can, of course, add your own buttons here and use them however you want.

The prefabs are of 2 kinds:

  • TupleValue: A “cell” - it represents a single value (which can be of any of the supported types)
  • Tuple: A “row” - is a TupleAdapter implementation, which is a horizontal ListView of TupleValue elements

These prefabs are used to represent the table’s rows. The header also has the same 2 prefabs, because it itself has the appearance of a row, so why not reuse the same concept with some minor modifications?

  1. Code

  2. Summary

  3. Common Scenarios

  4. Have a custom view instead of the Index text displayed

    **[Screenshot - see Unity Asset Store documentation for visual guide]**

Assuming you’ve created the TableView via OSA Wizard, you’ll get the following class:

1
public class BasicTableAdapter : TableAdapter<TableParams, TupleViewsHolder, TupleViewsHolder>

The second TupleViewsHolder refers to the ViewsHolder for each individual row, and we will change it to use our own implementation:

1
public class BasicTableAdapter : TableAdapter<TableParams, MyRowVH, TupleViewsHolder>

You’ll also need to change the the UpdateViewsHolder method to use your new MyRowVH instead of TupleViewsHolder.

Now create the custom ViewsHolder (it’s fine to create it in the same file, if it’s not too bloated):

1
public class MyRowVH : TupleViewsHolder{	UnityEngine.UI.Text _Text1;	UnityEngine.UI.Text _Text2;	public override void CollectViews()	{		base.CollectViews();		if (\!_IndexText)			*// We can also move the IndexText to another path, or remove it altogether*			root.GetComponentAtPath("CustomPanel/IndexText", out _IndexText);		root.GetComponentAtPath("CustomPanel/Text1", out _Text1);		root.GetComponentAtPath("CustomPanel/Text2", out _Text2);	}	public override void UpdateViews(ITuple tuple, ITableColumns columns)	{		base.UpdateViews(tuple, columns);		if (_Text1)			_Text1.text = tuple.GetValue(0).ToString();		if (_Text2)			_Text2.text = tuple.GetValue(1).ToString();	}}

Now let’s modify the row prefab (TuplePrefab). We’ll create a new empty child CustomPanel and add the 2 new text fields to it, and also (just to keep it all under the same parent) reparent the IndexText to the same parent. You should already have a similar structure for a TableView (left) when it was created via OSA Wizard:

[Screenshot - see Unity Asset Store documentation for visual guide]

If you set a non-default size the CustomPanel, you’ll also have to adjust the Left padding for the TuplePrefab and ColumnTuplePrefab (found at TableView/Prefabs-Hidden/ColumnsTuple in hierarchy).
In our case, CustomPanel has a width of 190, so we set the Left padding for both prefabs to 200. This is done under the Params->ContentPadding->Left in Inspector.

Also, make sure all of your additional UI elements don’t have the Raycast Target property enabled if it’s not absolutely necessary, because it impacts performance.

  1. Modify the appearance of a single cell based on the data it contains. For example, color a cell as red if it satisfies some conditions, or interpolate a color for it based on an integer value it contains

[Screenshot - see Unity Asset Store documentation for visual guide]

This is done by creating your own TupleAdapter and replacing the BasicTupleAdapter on the TupleValuePrefab game object with it (found at TableView/Prefabs-Hidden/Tuple in hierarchy):

1
using UnityEngine;using Com.TheFallenGames.OSA.CustomAdapters.TableView.Tuple;using Com.TheFallenGames.OSA.CustomAdapters.TableView.Tuple.Basic;namespace Your.Namespace.Here.UniqueStringHereToAvoidNamespaceConflicts.Tables{	public class MyRowAdapter : TupleAdapter<TupleParams, BasicTupleValueViewsHolder>	{		protected override void UpdateViewsHolder(BasicTupleValueViewsHolder newOrRecycled)		{			base.UpdateViewsHolder(newOrRecycled);			var value = _CurrentTuple.GetValue(newOrRecycled.ItemIndex).ToString();			Color color;			if (value.Contains("R3C0"))			{				*// Make a specific cell red*				color = Color.red;			}			else			{				*// Gradient effect: first items more visible than last ones*				float visibility = 1f - (float)(newOrRecycled.ItemIndex \+ 1)/_CurrentTuple.Length;				color = Color.black * visibility;			}			newOrRecycled.TextComponent.color = color;		}	}}

Tip: if you don’t want to manually re-assign all properties in Inspector after replacing the BasicTupleAdapter with MyRowAdapter, right-click on the Inspector tab, select Debug mode, and then you’ll be able to drag-and-drop the MyRowAdapter script onto the existing BasicTupleAdapter’s Script field (save your scene before this in case something goes wrong):

[Screenshot - see Unity Asset Store documentation for visual guide]

You can further replace BasicTupleValueViewsHolder with your own implementation, if you need more customizability. Either extend BasicTupleValueViewsHolder or TupleValueViewsHolder directly.

For pre-v5.1 users, you’ll need to add the following code to TableViewText.cs, just after the fontSize property:

1
		*/// <summary>*		*/// Keeping the same property name as the Unity's Text component*		*/// </summary>*		public Color color		{			get { return _Text.color; }			set { _Text.color = value; }		}
  1. Remove the column type (STRING, INTEGER etc.) or change the column text

Simply use a custom class that extends IColumnInfo instead of the built-in BasicColumnInfo when creating your column definition. You can decide your own format in the DisplayName property.

  1. Resizing a column’s width

Resize the column value prefab to the desired size

[Screenshot - see Unity Asset Store documentation for visual guide]

this post is licensed under cc by 4.0 by the author.

© Forbidden Byte. some rights reserved.

other searches include optimised scrollview adapter, optimized scroll view adapter, optimized scrollvew adapter, optimzed scrollview adapter, optmized scrollview adapter, optimized scrolview adapter, optimized scrollview adaptor, optimized scrollveiw adapter, optimized scrollview adpater, osa unity, mediaplayer8, media player 8, mediaplayer8 unity, media player unity, scene objects query, sceneobjectsquery, scene object query, soq unity, unity video player plugin, unity scene query tool, scroll rect optimizer, unity list view, unity grid view