Table View – Cells (Part 2 of 6)

A lot of the hard work performed by a table view is related to the reuse of its cells. We will need a component that will help ease the process of positioning those cells once they have been added to the table view. It will also need a way to animate into and out of the table view.

Table View Cell

You can open and review the completed “TableViewCell.cs” script from the project, but I will point out and comment on several code snippets here.

[RequireComponent(typeof(Panel))]
public class TableViewCell : MonoBehaviour 

Just above the class definition I have used a special tag, “RequireComponent”. Whenever you add this component to a GameObject in the Inspector, it will see this tag, and automatically add a “Panel” component for you. The “Panel” component is a special script I wrote to make it much easier to position any “RectTransform” relative to its parent “RectTransform” without needing to hurt your brain over things like anchor and pivot points. Additionally, this component is able to handle animations between special “Positions” which are built from a couple “TextAnchors” and a “Vector2” offset. Why a “TextAnchor” you ask? Well, because it was an already created enum which happened to have all the values I wanted such as “UpperLeft” and “LowerRight”.

public Panel panel { get; private set; }
public LayoutAnchor anchor { get; private set; }
public Panel.Position pinPosition { get; private set; }
public Panel.Position showPosition { get; private set; }
public Panel.Position hidePosition { get; private set; }

The “TableViewCell” component defines several properties. Note that these wont appear in the inspector (and aren’t intended to) because they are properties not fields. Each of them are just conveniently cached references for later use.

void Awake ()
{
	panel = GetComponent<Panel>();
	anchor = GetComponent<LayoutAnchor>();
}

The component is guaranteed to have a “Panel” and “LayoutAnchor” component because the “TableViewCell” requires the “Panel” and the “Panel” requires the “LayoutAnchor”. Therefore it is safe for me to grab and cache references to them in the “Awake” method to help keep everything easy to use.

Panel.Position GetPosition (string posName, TextAnchor ownAnchor, TextAnchor parentAnchor)
{
	Panel.Position position = panel[posName];
	if (position == null)
	{
		position = new Panel.Position(posName, ownAnchor, parentAnchor, Vector2.zero);
		panel.AddPosition(position);
	}
	return position;
}

This method is sort of like a lazy loader, with defaults. It looks to see if a “Position” has been configured on the “Panel” component which uses the indicated name. If so, then that already configured position is returned. If there isn’t an existing position, then one will be created using the parameters which were passed along.

public void SetShowAnchors (TextAnchor ownAnchor, TextAnchor parentAnchor)
{
	showPosition = GetPosition("Show", ownAnchor, parentAnchor);
	pinPosition = GetPosition("Pin", ownAnchor, parentAnchor);
}

public void SetHideAnchors (TextAnchor ownAnchor, TextAnchor parentAnchor)
{
	hidePosition = GetPosition("Hide", ownAnchor, parentAnchor);
}

When a TableView is configuring its cells, it can pass suggested default values for panel “positions” based on its orientation. When these methods are called I am able to create and or configure the three positions needed to make these cells function correctly.

public void Show (Vector2 offset)
{
	showPosition.offset = offset;
	panel.SetPosition(showPosition, false);
}

This method will be triggered by scrolling the tableview and causing new cells to come into view. When a “TableViewCell” is dequeued and added to the “TableView” it will need to do some initialization in order to make it appear in the correct place. The show method takes a position for the cell as a parameter which it uses to modify the “show position” of its panel component. Then it is told to snap into place without any animation.

public void Hide ()
{
	panel.SetPosition(hidePosition, false);
}

This method is also triggered by scrolling the tableview. When a cell scrolls off screen it is enqueued back into the pool. Before that happens I use a callback to let the cell know that it is now considered hidden.

public Tweener Insert (Vector2 offset)
{
	showPosition.offset = hidePosition.offset = offset;
	panel.SetPosition(hidePosition, false);
	return ApplyPosition(showPosition);
}

This method is triggered by the dynamic adding of cells to a table view. This would occur after the table view had already been loaded and displayed, but we are adding more. These inserted cells will slide into place with an animation, the endpoints of which are specified by the Panel’s positions.

public void Pin (Vector2 offset)
{
	if (panel.CurrentPosition == pinPosition)
		return;
	pinPosition.offset = offset;
	panel.SetPosition(pinPosition, false);
}

Whenever we insert or remove cells it can cause other cells around them to need to shift to make room or fill a void. I call this method to mark those cells at their current location so that they can animate to their new target.

public Tweener Shift (Vector2 offset)
{
	if (panel.CurrentPosition != pinPosition)
		return null;
	showPosition.offset = offset;
	return ApplyPosition(showPosition);
}

When I have determined that a visible cell needs to move (thanks to insertion or removal of cells around it) and have finished calculating its new location, I call this method to begin the animation. It will slide from the position it had been pinned at, to a new show position based on the parameter’s offset.

public Tweener Remove ()
{
	hidePosition.offset = showPosition.offset;
	panel.SetPosition(showPosition, false);
	return ApplyPosition(hidePosition);
}

This method is called whenever we are dynamically removing a cell(s) from a TableView. The cell will then slide off screen based on the configuration of the panel’s positions.

Tweener ApplyPosition (Panel.Position pos)
{
	Tweener tweener = panel.SetPosition(pos, true);
	tweener.duration = 0.5f;
	return tweener;
}

Anytime I trigger an animation for a cell through its Panel, I use this convenient method to make sure that the duration is consistent and set to the amount of time which feels right to me.

Summary

In Part 2 (of 6) we created a new component which will be important for positioning and animating cells in our TableView. These cells will be components attached to the “Poolable” object used by the TableView so that there are only as many of them as we need to fill the table view’s “visible” area. We broke the script down into small bits and discussed the implementation of each in turn.

Leave a Reply

Your email address will not be published. Required fields are marked *