How-To: Reorder Rows and Columns

This how-to guide will show you how to add row and column reordering to your ShinobiGridView.

In order to create a grid where row and columns can be reordered you need to do the following:

  1. Construct a ShinobiGridView, defining a set of columns and providing some backing data.
  2. Create a RowReorderDetector.OnRowReorderListener to handle the updating of the backing data.
  3. Instantiate a RowColumnReorderManager and pass it to the grid’s GridRecyclerViews.

For the purposes of this how-to guide it is assumed that you already know how to render basic tabular data within the ShinobiGridView, if not, it is suggested that you follow the Quick Start Guide.

In the majority of cases, row and column reordering will be performed via user gestures, which typically comprise a long press, followed by a drag and release. shinobigrids makes use of a series of helper classes to interpret a user gesture and translate it into a reorder event. Advanced users may prefer to use some (or all) of these classes to implement their own custom reordering logic. For those interested, a good place to start is by reading the API docs here.

To make things easier we provide a convenience class which will do most of the work during a reorder event. By default this class provides gesture based reordering for both rows and columns. For the majority of users the default behavior will suffice. This how-to guide will focus on the use of this class.

Define Row Reorder Behavior for the Backing Data Store

shinobigrids has been designed to be as flexible as possible and as such we make no assumptions on the data that will be used with it. As such, the responsibility of updating the backing data, following a row reorder lies with the user. We do of course provide the tools to allow this task to quickly and easily be achieved.

The tool in question is the RowReorderDetector.OnRowReorderListener interface. An example implementation of this can be seen below:

Java

RowReorderDetector.OnRowReorderListener listener = new RowReorderDetector.OnRowReorderListener() {
  @Override
  public void onRowReorderStarted(int rowIndex, GridRecyclerView gridRecyclerView) {

  }

  @Override
  public void onRowIndexChanged(int rowIndex, int fromRowIndex, int toRowIndex, GridRecyclerView gridRecyclerView) {

  }

  @Override
  public void onRowReorderEnded(int rowIndex, int endRowIndex, GridRecyclerView gridRecyclerView) {
    Person person = people.get(rowIndex);
    people.remove(person);
    people.add(endRowIndex, person);
  }

  @Override
  public void onRowReorderCancelled(int rowIndex, GridRecyclerView gridRecyclerView) {

  }
};

C#

class Listener : Java.Lang.Object, RowReorderDetector.IOnRowReorderListener
{
    readonly List<Person> people;

    public Listener(List<Person> people)
    {
        this.people = people;
    }

    public void OnRowReorderStarted(int rowIndex, GridRecyclerView gridRecyclerView)
    {

    }

    public void OnRowIndexChanged(int rowIndex, int fromRowIndex, int toRowIndex, GridRecyclerView gridRecyclerView)
    {

    }

    public void OnRowReorderEnded(int rowIndex, int endRowIndex, GridRecyclerView gridRecyclerView)
    {
        Person person = people[rowIndex];
        people.Remove(person);
        people.Insert(endRowIndex, person);
    }

    public void OnRowReorderCancelled(int rowIndex, GridRecyclerView gridRecyclerView)
    {

    }
};

As you can see this is a fairly simple example that performs work when a valid row reorder gesture has been completed. The onRowReorderEnded method provides some useful parameters such as the initial index of the row which was reordered, along with its new index at the end of the reorder event. In this simple example a reference to the appropriate Person object is used to remove the Person from the backing data store and re-add it at the new position.

This example is intentionally simple but you can of course implement this interface in any way you wish. You might for example have the need to take custom action at the start of a row reorder event using the onRowReorderStarted method.

Whilst the user is responsible for ensuring the backing data store is updated following a row reorder, the RowColumnReorderManager fully handles column reorder events.

Instantiate an Instance of the Convenience Class

To create an instance of the convenience class, very few lines of code are needed:

Java

RowColumnReorderManager rowColumnReorderManager = new RowColumnReorderManager(shinobiGridView, listener);
shinobiGridView.getHeaderRecyclerView().addOnItemTouchListener(rowColumnReorderManager);
shinobiGridView.getDataRecyclerView().addOnItemTouchListener(rowColumnReorderManager);

C#

Listener listener = new Listener(people);
RowColumnReorderManager rowColumnReorderManager = new RowColumnReorderManager(shinobiGridView, listener);
shinobiGridView.HeaderRecyclerView.AddOnItemTouchListener(rowColumnReorderManager);
shinobiGridView.DataRecyclerView.AddOnItemTouchListener(rowColumnReorderManager);

As this simple code snippet shows, we create an instance of the RowColumnReorderManager, passing to its constructor our ShinobiGridView object and also our RowReorderDetector.OnRowReorderListener which we created earlier. Once created we simply add this object to the header and data RecyclerView objects within our ShinobiGridView, using the addOnItemTouchListener method of each RecyclerView.

By now if you long press a data item on your ShinobiGridView and drag vertically you should see a visual representation of the row reorder event. Similarly if you long press a header item and drag horizontally you will visually see a column reorder. Specifically the row or column will appear to be ‘pulled out’ upon a long press gesture being detected upon it. This row or column will appear to follow the user’s finger until it is released. At this point it will visually ‘snap back’ into its new position, following the reorder.

Enable or Disable Row or Column Reordering

As we have seen, you can enable gesture based row and column reordering on your header and data RecyclerViews by simply adding an instance of a RowColumnReorderManager. You can of course add this instance to only the data RecyclerView, only the header RecyclerView or, as we have seen above, to both. This of course is dependent upon your particular needs.

Whilst the above is a simple way of switching row or column reordering on or off, this can alternatively be achieved using the API of the RowColumnReorderManager. The RowColumnReorderManager offers two simple methods which allow row and column reordering to be enabled or disabled independently: setShouldManageColumnReorder and setShouldManageRowReorder. In both cases a simple true or false parameter is all that is needed.

Control How the Nearest Item to a Gesture is Found

When a long press is detected, the RowColumnReorderManager must find the item (within the RecyclerView on which it is set) on which the reorder event will occur. By default, the nearest item to the long press gesture will be chosen. In some cases, this may be undesirable behavior. An example of this might be if a RecyclerView within the ShinobiGridView has had its items decorated such that it has thick grid lines. In this case the user may want any gesture which is not directly on top of an item to be ignored.

This behavior can be controlled by setting an appropriate implementation of the ChildViewFinder interface on the RowColumnReorderManager using its setChildViewFinder method. To swap the behavior from the default, you could pass an instance of the DirectlyUnderChildViewFinder class, or your own implementation of the ChildViewFinder interface. Of course to revert back to the default behavior, where the nearest item to the gesture is chosen, simply pass in an instance of the NearestInTouchBoundsChildViewFinder class.

Row and Column Reordering

See the related code sample: Row And Column Reordering Sample in the samples/row-and-column-reordering folder of your product download.