Using JSON to create a user interface in Xamarin.iOS

MonoTouch.Dialog (MT.D) includes support for dynamic UI generation via JSON data. In this tutorial, we’ll walk through how to use a JSONElement to create a user interface from JSON that is either included with an application, or loaded from a remote Url.

MT.D supports creating user interfaces declared in JSON. When elements are declared using JSON, MT.D will create the associated elements for you automatically. The JSON can be loaded either from a local file, a parsed JsonObject instance, or even a remote Url.

MT.D supports the full range of features that are available in the Elements API when using JSON. For example, the application in the following screenshot is completely declared using JSON:

For example, the application in this screenshot is completely declared using JSON For example, the application in this screenshot is completely declared using JSON

Let’s revisit the example from the Elements API Walkthrough tutorial, showing how to add a task detail screen using JSON.

Setting up MT.D

MT.D is distributed with Xamarin.iOS. To use it, right-click on the References node of a Xamarin.iOS project in Visual Studio 2017 or Visual Studio for Mac and add a reference to the MonoTouch.Dialog-1 assembly. Then, add using MonoTouch.Dialog statements in your source code as necessary.

JSON walkthrough

The example for this walkthrough allows tasks to be created. When a task is selected on the first screen, a detail screen is presented as shown:

When a task is selected on the first screen, a detail screen is presented as shown

Creating the JSON

For this example, we’ll load the JSON from a file in the project named task.json. MT.D expects the JSON to conform to a syntax that mirrors the Elements API. Just like using the Elements API from code, when using JSON, we declare sections and within those sections we add elements. To declare sections and elements in JSON, we use the strings “sections” and “elements” respectively as the keys. For each element, the associated element type is set using the type key. Every other elements property is set with the property name as the key.

For example, the following JSON describes the sections and elements for the task details:

{
    "title": "Task",
    "sections": [
        {
            "elements" : [
                {
                    "id" : "task-description",
                    "type": "entry",
                    "placeholder": "Enter task description"
                },
                {
                    "id" : "task-duedate",
                    "type": "date",
                    "caption": "Due Date",
                    "value": "00:00"
                }
            ]
        }
    ]
}

Notice the JSON above includes an id for each element. Any element can include an id, to reference it at runtime. We’ll see how this is used in a moment when we show how to load the JSON in code.

Loading the JSON in code

Once the JSON has been defined, we need to load it into MT.D using the JsonElement class. Assuming a file with the JSON we created above has been added to the project with the name sample.json and given a build action of content, loading the JsonElement is as simple as calling the following line of code:

var taskElement = JsonElement.FromFile ("task.json");

Since we are adding this on demand each time a task is created, we can modify the button clicked from the earlier Elements API example as follows:

_addButton.Clicked += (sender, e) => {
    ++n;

    var task = new Task{Name = "task " + n, DueDate = DateTime.Now};

    var taskElement = JsonElement.FromFile ("task.json");

    _rootElement [0].Add (taskElement);
};

Accessing elements at runtime

Recall we added an id to both elements when we declared them in the JSON file. We can use the id property to access each element at runtime to modify their properties in code. For example, the following code references the entry and date elements to set the values from the task object:

_addButton.Clicked += (sender, e) => {
    ++n;

    var task = new Task{Name = "task " + n, DueDate = DateTime.Now};

    var taskElement = JsonElement.FromFile ("task.json");

    taskElement.Caption = task.Name;

    var description = taskElement ["task-description"] as EntryElement;

    if (description != null) {
        description.Caption = task.Name;
        description.Value = task.Description;       
    }

    var duedate = taskElement ["task-duedate"] as DateElement;

    if (duedate != null) {                
        duedate.DateValue = task.DueDate;
    }
    _rootElement [0].Add (taskElement);
};

Loading JSON from a url

MT.D also supports dynamically loading JSON from an external Url by simply passing the Url to the constructor of the JsonElement. MT.D will expand the hierarchy declared in the JSON on demand as you navigate between screens. For example, consider a JSON file such as the one below located at the root of the local web server:

{
    "type": "root",
    "title": "home",
    "sections": [
        {
            "header": "Nested view!",
            "elements": [
                {
                    "type": "boolean",
                    "caption": "Just a boolean",
                    "id": "first-boolean",
                    "value": false
                },
                {
                    "type": "string",
                    "caption": "Welcome to the nested controller"
                }
            ]
        }
    ]
}

We can load this using the JsonElement as in the following code:

_rootElement = new RootElement ("Json Example") {
    new Section ("") {
        new JsonElement ("Load from url", "http://localhost/sample.json")
    }
};

At runtime, the file will be retrieved and parsed by MT.D when the user navigates to the second view, as shown in the screenshot below:

The file will be retrieved and parsed by MT.D when the user navigates to the second view

Summary

This article showed how to create a using interface with MT.D from JSON. It showed how to load JSON included in a file with the application as well as from a remote Url. It also showed how to access elements described in JSON at runtime.