Expand Minimize Picture-in-picture Power Device Status Voice Recognition Skip Back Skip Forward Minus Plus Play Search
Internet Explorer alert
This browser is not recommended for use with smartdevicelink.com, and may not function properly. Upgrade to a different browser to guarantee support of all features.
close alert
To Top Created with Sketch. To Top
To Bottom Created with Sketch. To Bottom
iOS Guides
Main Screen Templates

Main Screen Templates

Each head unit manufacturer supports a set of user interface templates. These templates determine the position and size of the text, images, and buttons on the screen. Once the app has connected successfully with an SDL enabled head unit, a list of supported templates is available on SDLManager.systemCapabilityManager.defaultMainWindowCapability.templatesAvailable.

Change the Template

To change a template at any time, use [SDLScreenManager changeLayout:]. This guide requires SDL iOS version 7.0. If using an older version, use the SetDisplayLayout RPC.

Note

When changing the layout, you may get an error or failure if the update is "superseded." This isn't technically a failure, because changing the layout has not yet been attempted. The layout or batched operation was cancelled before it could be completed because another operation was requested. The layout change will then be inserted into the future operation and completed then.

[self.sdlManager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithTemplate:SDLPredefinedLayoutGraphicWithText] withCompletionHandler:^(NSError * _Nullable error) {
    if (error != nil) {
        // Print out the error if there is one and return early
        return;
    }
    // The template has been set successfully
}];
sdlManager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .graphicWithText)) { err in
    if let error = err {
        // Print out the error if there is one and return early
        return
    }
    // The template has been set successfully
}

Template changes can also be batched with text and graphics updates:

[self.sdlManager.screenManager beginUpdates];
self.sdlManager.screenManager.textField1 = "Line of Text";
[self.sdlManager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithTemplate:SDLPredefinedLayoutGraphicWithText] withCompletionHandler:^(NSError * _Nullable error) {
    // This listener will be ignored, and will use the handler sent in endUpdatesWithCompletionHandler.
}];
self.sdlManager.screenManager.primaryGraphic = <#SDLArtwork#>;
[self.sdlManager.screenManager endUpdatesWithCompletionHandler:^(NSError * _Nullable error) {
    if (error != nil) {
        // Print out the error if there is one and return early
        return
    }
    // The data and template has been set successfully
}];
sdlManager.screenManager.beginUpdates()
sdlManager.screenManager.textField1 = "Line of Text"
sdlManager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .graphicWithText)) { err in
    // This listener will be ignored, and will use the handler set in the endUpdates call.
}
sdlManager.screenManager.primaryGraphic = <#SDLArtwork#>
sdlManager.screenManager.endUpdates { err in
    if let error = err {
        // Print out the error if there is one and return early
        return
    }
    // The data and template has been set successfully
}

When changing screen layouts and template data (for example, to show a weather hourly data screen vs. a daily weather screen), it is recommended to encapsulate these updates into a class or method. Doing so is a good way to keep SDL UI changes organized. A fully-formed example of this can be seen in the example weather app. Below is a generic example.

Screen Change Example Code

This example code creates an interface that can be implemented by various "screens" of your SDL app. This is a recommended design pattern so that you can separate your code to only involve the data models you need. This is just a simple example and your own needs may be different.

Screen Change Example Interface

All screens will need to have access to the SDLScreenManager object and a function to display the screen. Therefore, it is recommended to create a generic interface for all screens to follow. For the example below, the CustomSDLScreen protocol requires an initializer with the parameters SDLManager and a showScreen method.

// CustomSDLScreen.h
@class SDLManager;

@protocol CustomSDLScreen <NSObject>

@required
- (instancetype)initWithManager:(SDLManager *)sdlManager;
- (void)showScreen;

@end
protocol CustomSDLScreen {
    init(sdlManager: SDLManager)
    func showScreen()
}

Screen Change Example Implementations

The following example code shows a few implementations of the example screen changing protocol. A good practice for screen classes is to keep screen data in a view model. Doing so will add a layer of abstraction for exposing public properties and commands to the screen.

For the example below, the HomeScreen class will inherit the CustomSDLScreen interface and will have a property of type HomeDataViewModel. The screen manager will change its text fields based on the view model's data. In addition, the home screen will also create a navigation button to open the ButtonSDLScreen when pressed.

// HomeSDLScreen.h
#import <Foundation/Foundation.h>
#import "CustomSDLScreen.h"

@class HomeDataViewModel;
@class SDLManager;
@class SDLScreenManager;
@class SDLSoftButtonObject;

NS_ASSUME_NONNULL_BEGIN

@interface HomeSDLScreen : NSObject<CustomSDLScreen>

@end

NS_ASSUME_NONNULL_END

/************************************************************************/
// HomeSDLScreen.m
#import "HomeSDLScreen.h"

#import "ButtonSDLScreen.h"
#import "CustomSDLScreen.h"
#import "HomeDataViewModel.h"
#import "SmartDeviceLink.h"

@interface HomeSDLScreen()

@property (weak, nonatomic) SDLManager *sdlManager;
// A button to navigate to the ButtonSDLScreen
@property (strong, nonatomic) ButtonSDLScreen *buttonScreen;
// An example of your data model that will feed data to the SDL screen's UI
@property (strong, nonatomic) HomeDataViewModel *homeDataViewModel;

@end

@implementation HomeSDLScreen

- (instancetype)initWithManager:(SDLManager *)sdlManager {
    self = [super init];
    if (!self) { return nil; }

    _sdlManager = sdlManager;
    _buttonScreen = [[ButtonSDLScreen alloc] initWithManager:sdlManager];
    _homeDataViewModel = [[HomeDataViewModel alloc] init];

    return self;
}

- (void)showScreen {
    // Batch updates
    [self.sdlManager.screenManager beginUpdates];
    // Change template to Graphics With Text and SoftButtons
    [self.sdlManager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithTemplate:SDLPredefinedLayoutGraphicWithTextAndSoftButtons] withCompletionHandler:nil];
    // Assign text fields to view model data
    self.sdlManager.screenManager.textField1 = self.homeDataViewModel.text1;
    self.sdlManager.screenManager.textField2 = self.homeDataViewModel.text2;
    self.sdlManager.screenManager.textField3 = self.homeDataViewModel.text3;
    self.sdlManager.screenManager.textField4 = self.homeDataViewModel.text4;
    // Create and assign a button to navigate to the ButtonSDLScreen
    SDLSoftButtonObject *navigationButton = [[SDLSoftButtonObject alloc] initWithName:@"ButtonSDLScreen" text:@"Button Screen" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
        if (buttonPress == nil) { return; }
        [self.buttonScreen showScreen];
    }];
    self.sdlManager.screenManager.softButtonObjects = @[navigationButton];
    // Change Primary Graphic
    self.sdlManager.screenManager.primaryGraphic = <#SDLArtwork#>;
    [self.sdlManager.screenManager endUpdates];
}

@end
struct HomeSDLScreen: CustomSDLScreen {
    let sdlManager: SDLManager
    let buttonScreen: ButtonSDLScreen
    // An example of your data model that will feed data to the SDL screen's UI
    let homeDataViewModel = HomeDataViewModel()

    init(sdlManager: SDLManager) {
        self.sdlManager = sdlManager
        self.buttonScreen = ButtonSDLScreen(sdlManager: sdlManager)
    }

    func showScreen() {
        // Batch updates
        self.sdlManager.screenManager.beginUpdates()
        // Change template to Graphics With Text and Soft Buttons
        self.sdlManager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .graphicWithTextAndSoftButtons))
        // Assign text fields to view model data
        self.sdlManager.screenManager.textField1 = self.homeDataViewModel.text1
        self.sdlManager.screenManager.textField2 = self.homeDataViewModel.text2
        self.sdlManager.screenManager.textField3 = self.homeDataViewModel.text3
        self.sdlManager.screenManager.textField4 = self.homeDataViewModel.text4
        // Create and assign a button to navigate to the ButtonSDLScreen
        let navigationButton = SDLSoftButtonObject(name: "ButtonSDLScreen", text: "Button Screen", artwork: nil) { (buttonPress, buttonEvent) in
            guard buttonPress != nil else { return }
            self.buttonScreen.showScreen()
        }
        self.sdlManager.screenManager.softButtonObjects = [navigationButton]
        self.sdlManager.screenManager.endUpdates()
    }
}

The ButtonSDLScreen follows the same patterns as the HomeSDLScreen but has minor implementation differences. The screen's view model ButtonDataViewModel contains properties unique to the ButtonSDLScreen such as text fields and an array of soft button objects. It also changes the template configuration to tiles only.

// ButtonSDLScreen.h
#import <Foundation/Foundation.h>
#import "CustomSDLScreen.h"

@class ButtonDataViewModel;
@class SDLManager;
@class SDLScreenManager;

NS_ASSUME_NONNULL_BEGIN

@interface ButtonSDLScreen : NSObject<CustomSDLScreen>

@end

NS_ASSUME_NONNULL_END

/************************************************************************/
// ButtonSDLScreen.m
#import "ButtonSDLScreen.h"

#import "ButtonDataViewModel.h"
#import "CustomSDLScreen.h"
#import "SmartDeviceLink.h"

@interface ButtonSDLScreen()

@property (strong, nonatomic) SDLManager *sdlManager;
// An example of your data model that will feed data to the SDL screen's UI
@property (strong, nonatomic) ButtonDataViewModel *buttonDataViewModel;

@end

@implementation ButtonSDLScreen

- (instancetype)initWithManager:(SDLManager *)sdlManager {
    self = [super init];
    if (!self) { return nil; }

    _sdlManager = sdlManager;
    _buttonDataViewModel = [[ButtonDataViewModel alloc] init];

    return self;
}

- (void)showScreen {
    // Batch Updates
    [self.sdlManager.screenManager beginUpdates];
    // Change template to Tiles Only
    [self.sdlManager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithTemplate:SDLPredefinedLayoutTilesOnly] withCompletionHandler:nil];
    // Assign soft button objects to view model buttons array
    self.sdlManager.screenManager.softButtonObjects = self.buttonDataViewModel.buttons;
    [self.sdlManager.screenManager endUpdates];
}

@end
struct ButtonSDLScreen: CustomSDLScreen {
    let sdlManager: SDLManager
    // An example of your data model that will feed data to the SDL screen's UI
    let buttonDataViewModel = ButtonDataViewModel()

    init(sdlManager: SDLManager) {
        self.sdlManager = sdlManager
    }

    func showScreen() {
        // Batch Updates
        self.sdlManager.screenManager.beginUpdates()
        // Change template to Tiles Only
        self.sdlManager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .tilesOnly))
        // Assign soft button objects to view model buttons array
        self.sdlManager.screenManager.softButtonObjects = buttonDataViewModel.buttons
        self.sdlManager.screenManager.endUpdates()
    }
}

Available Templates

There are fifteen standard templates to choose from, however some head units may only support a subset of these templates. The following examples show how templates will appear on the Generic HMI and Ford's SYNC® 3 HMI.

Media

Generic - Media without progress bar

Media (with a Progress Bar)

Generic - Media with progress bar

Non-Media

Generic - Non-Media

Graphic with Text

Generic - Graphic with Text

Text with Graphic

Generic - Text with Graphic

Tiles Only

Generic - Tiles Only

Graphic with Tiles

SYNC® 3 - Graphic with Tiles

Tiles with Graphic

SYNC® 3 - Tiles with Graphic

Graphic with Text and Soft Buttons

SYNC® 3 - Graphic with Text and Soft Buttons

Text and Soft Buttons with Graphic

SYNC® 3 Text and Soft Buttons with Graphic

Graphic with Text Buttons

Generic - Graphic with Text Buttons

Double Graphic with Soft Buttons

Generic - Double Graphic with Softbuttons

Text Buttons with Graphic

Generic - Text Buttons with Graphic

Text Buttons Only

Generic - Text Buttons Only

Large Graphic with Soft Buttons

Generic - Large Graphic with Softbuttons

Large Graphic Only

Generic - Large Graphic Only

View on GitHub.com
Previous Section Next Section