Windows
Windows
In of the series, we created a simple to-do list app in Xcode and used the iOS bridge to bring it over to Windows 10. In of the series, we went on a tour of Visual Studio for iOS developers. In , we used the Windows Bridge for iOS to convert an iOS calculator app created using Storyboards and Auto Layout to a Universal Windows Platform app that adjusts to various form factors on Windows 10. In , we discussed how to mix and match UIKit with XAML controls in a bridged UWP app.
Today, we explain how to customize the Surface Dial Experience for bridged UWP apps using Objective-C projections.
Getting Started
For today’s tutorial, you will need:
If you don’t have a Windows 10 PC, you can download one of our pre-built evaluation virtual machines . Download the package for your preferred virtualization environment and you’ll be up and running in no time.
Understanding the Project Structure
With the radial control sample initial code downloaded and unzipped on your Mac development environment, open the Xcode project and briefly explore the application. The application consists of:
Build and run the application in the simulator and move the slider to make sure everything is properly set up.
Using vsimporter
You are now ready to run the app through the vsimporter tool. To do so, you’ll need to copy your Xcode project files to your Windows Machine (or VM). With the files copied, follow the steps under the Using vsimporter section of of the blog series. Once you’re done, return to your radial control project directory, which should now contain a brand new Visual Studio solution file.
Open the Visual Studio solution by double-clicking on the RadialControlSample-WinStore10.sln file and build and run the application on your local machine by clicking on the Run button on the top menu. You’ll notice the same UI we saw running in the Xcode Simulator — you now have a native iOS app running on Windows. Try moving the slider and you’ll see its value label change.
Adding a New Menu Item to the Radial Controller Tool
You will now update this app to add a custom menu item to the radial controller tool that will respond to rotate and click actions by changing the slider value and toggling the switch.
To implement radial controller features in your app, you will need the public headers for the relevant UWP frameworks. In the bridge SDK you downloaded, go to the directory and take a look at what you find. Each header file represents a different namespace within the . For our purposes, you will need APIs from since the radial controller is an input device and all of its classes are contained in that namespace.
To include this framework – and make sure it’s only included when the code is being run on Windows – start by adding an #ifdef and the #import macros to the top of the view controller implementation file:
#import "ViewController.h"
#ifdef WINOBJC
#import <UWP/WindowsUIInput.h>
#endif
To interact with the radial controller, you will need to add a property to the view controller of your app that will allow you to access it. In C++, wheel input devices are represented by the class. However, as you build using Objective-C projections, you will notice that the standard naming scheme for these objects has been modified to match Objective-C conventions, where classes are prefixed with the letters that constitute their containing namespace:
As a result, add a WUIRadialController property to the @interface section of the view controller implementation file:
@interface ViewController()
@property UILabel *demoTitle;
@property UILabel *demoInfo;
@property UISlider *slider;
@property UILabel *sliderLabel;
@property UISwitch *switchControl;
#ifdef WINOBJC
@property WUIRadialController* radialController;
#endif
@end
Next, you need to get a reference to the WUIRadialController object with the method as explained in the class documentation. Looking at the header you’ll find the equivalent Objective-C projection under the WUIRadialController class interface:
@interface WUIRadialController : RTObject
[...]
+ (WUIRadialController*)createForCurrentView;
Call this method at the end of the viewDidLoad method of the view controller file to instantiate the WUIRadialController property:
- (void)viewDidLoad {
[...]
#ifdef WINOBJC
// Create a reference to the radial controller
self.radialController = [WUIRadialController createForCurrentView];
#endif
}
Now you need to get a reference to the radial controller menu and its items. This is done via the property of the class that returns a object. Looking back at the header, you’ll find the equivalent Objective-C property under the WUIRadialController class interface that returns a WUIRadialControllerMenu object:
@interface WUIRadialController : RTObject
[...]
@property (readonly) WUIRadialControllerMenu* menu;
Call this property to get a reference to the radial controller menu:
- (void)viewDidLoad {
[...]
#ifdef WINOBJC
// Create a reference to the radial controller
self.radialController = [WUIRadialController createForCurrentView];
// Get the radial controller menu
WUIRadialControllerMenu* menu = self.radialController.menu;
#endif
}
The menu items are accessible via the property of the class. As before, the interface of the WUIRadialControllerMenu class in the header gives you the equivalent Objective-C property:
@interface WUIRadialControllerMenu : RTObject
[...]
@property (readonly) NSMutableArray* /* WUIRadialControllerMenuItem* */ items;
Call this property to get a reference to the menu items:
- (void)viewDidLoad {
[...]
// Get the radial controller menu
WUIRadialControllerMenu* menu = self.radialController.menu;
// Get the menu items
NSMutableArray* menuItems = menu.items;
#endif
}
Next, you need to create a new object to add to the menu with the projection of the class method:
@interface WUIRadialControllerMenuItem : RTObject
+ (WUIRadialControllerMenuItem*)createFromIconNSString *)displayText iconWSSRandomAccessStreamReference*)icon;
Call this method to create the new menu item:
- (void)viewDidLoad {
[...]
// Get the menu items
NSMutableArray* menuItems = menu.items;
// Create a new menu item
// To use your own custom icon for the menu item, use the createFromIcon method instead
WUIRadialControllerMenuItem* newMenuItem = [WUIRadialControllerMenuItem createFromKnownIcon"Custom Tool" value:WUIRadialControllerMenuKnownIconRuler];
#endif
}
Note that we reused an existing icon for our tool from the enumeration, but you can create your own and use the method instead.
Finally, add your new menu item to the menu items array:
- (void)viewDidLoad {
[...]
// Create a new menu item
// To use your own custom icon for the menu item, use the createFromIcon method instead
WUIRadialControllerMenuItem* newMenuItem = [WUIRadialControllerMenuItem createFromKnownIcon"Custom Tool" value:WUIRadialControllerMenuKnownIconRuler];
#endif
// Add a new menu item
[menuItems addObject:newMenuItem];
}
That’s it! Now build and run your application and press and hold the Surface Dial to see the new menu item appear.
Adding a Handler for Click Input
In this section, you will add a handler for click input that will toggle the application switch control if the radial controller is clicked when the new tool you added to the menu is selected. Taking a look at the header, you’ll see you need the addButtonClickedEvent: method:
@interface WUIRadialController : RTObject
[...]
- (EventRegistrationToken)addButtonClickedEventvoid(^)(WUIRadialController*, WUIRadialControllerButtonClickedEventArgs
Since the callback relies on Objective-C blocks, you need to mark the self reference with the __block keyword before using it to access the switch to avoid creating a retain cycle. Add the following code at the end of the viewDidLoad method to do this:
- (void)viewDidLoad {
[...]
// Add a new menu item
[menuItems addObject:newMenuItem];
__weak ViewController* weakSelf = self; // Ensures self will not be retained
}
Now you can safely toggle the switch in the radial controller click callback:
- (void)viewDidLoad {
[...]
__weak ViewController* weakSelf = self; // Ensures self will not be retained
// Add a handler for click input from the radial controller
[self.radialController addButtonClickedEvent:^(WUIRadialController* controller, WUIRadialControllerButtonClickedEventArgs* args)
{
[weakSelf.switchControl setOn:!(weakSelf.switchControl.on) animated:YES];
}];
}
You can now build and run your application, select the new menu item, and click on the radial controller to see the switch toggle.
Adding a Handler for Rotation Input
In this section, you will add a handler for rotation input that will move the application slider control if the radial controller is rotated when the new tool you added to the menu is selected. Taking a look at the header, you’ll see that you need the addRotationChangedEvent: method:
@interface WUIRadialController : RTObject
[...]
- (EventRegistrationToken)addRotationChangedEventvoid(^)(WUIRadialController*, WUIRadialControllerRotationChangedEventArgs
As for the click event handler, simply call the method and update the slider value in the callback block:
- (void)viewDidLoad {
[...]
__weak ViewController* weakSelf = self; // Ensures self will not be retained
[...]
// Add a handler for rotation input from the radial controller
[self.radialController addRotationChangedEvent:^(WUIRadialController* controller, WUIRadialControllerRotationChangedEventArgs* args)
{
[weakSelf.slider setValueweakSelf.slider.value + ([args rotationDeltaInDegrees]/360.0f)) animated:YES];
}];
}
That’s it! Now build and run your application, select the new menu item and rotate the radial controller to see the slider value change.
Wrapping Up
Thanks for following along! You can download the complete for the final project. Take a look at the following resources for more information:
Also, be sure to check out the other posts in our series:
Today, we explain how to customize the Surface Dial Experience for bridged UWP apps using Objective-C projections.
Getting Started
For today’s tutorial, you will need:
- A PC running Windows 10 with and the installed.
- A Mac running Mac OS X 10.11 with Xcode 7 installed.
- A copy of the .
If you don’t have a Windows 10 PC, you can download one of our pre-built evaluation virtual machines . Download the package for your preferred virtualization environment and you’ll be up and running in no time.
Understanding the Project Structure
With the radial control sample initial code downloaded and unzipped on your Mac development environment, open the Xcode project and briefly explore the application. The application consists of:
- AppDelegate – contains the UIApplicationInitialStartupMode Category that ensures the app scales properly on Windows 10 for a variety of form factors.
- ViewController – provides the view management infrastructure for the app’s user interface, which consists of a slider, a label that is updated with the value of the slider and a switch.
Build and run the application in the simulator and move the slider to make sure everything is properly set up.
Using vsimporter
You are now ready to run the app through the vsimporter tool. To do so, you’ll need to copy your Xcode project files to your Windows Machine (or VM). With the files copied, follow the steps under the Using vsimporter section of of the blog series. Once you’re done, return to your radial control project directory, which should now contain a brand new Visual Studio solution file.
Open the Visual Studio solution by double-clicking on the RadialControlSample-WinStore10.sln file and build and run the application on your local machine by clicking on the Run button on the top menu. You’ll notice the same UI we saw running in the Xcode Simulator — you now have a native iOS app running on Windows. Try moving the slider and you’ll see its value label change.
Adding a New Menu Item to the Radial Controller Tool
You will now update this app to add a custom menu item to the radial controller tool that will respond to rotate and click actions by changing the slider value and toggling the switch.
To implement radial controller features in your app, you will need the public headers for the relevant UWP frameworks. In the bridge SDK you downloaded, go to the directory and take a look at what you find. Each header file represents a different namespace within the . For our purposes, you will need APIs from since the radial controller is an input device and all of its classes are contained in that namespace.
To include this framework – and make sure it’s only included when the code is being run on Windows – start by adding an #ifdef and the #import macros to the top of the view controller implementation file:
#import "ViewController.h"
#ifdef WINOBJC
#import <UWP/WindowsUIInput.h>
#endif
To interact with the radial controller, you will need to add a property to the view controller of your app that will allow you to access it. In C++, wheel input devices are represented by the class. However, as you build using Objective-C projections, you will notice that the standard naming scheme for these objects has been modified to match Objective-C conventions, where classes are prefixed with the letters that constitute their containing namespace:
- Windows.UI.Input.RadialController becomes WUIRadialController
As a result, add a WUIRadialController property to the @interface section of the view controller implementation file:
@interface ViewController()
@property UILabel *demoTitle;
@property UILabel *demoInfo;
@property UISlider *slider;
@property UILabel *sliderLabel;
@property UISwitch *switchControl;
#ifdef WINOBJC
@property WUIRadialController* radialController;
#endif
@end
Next, you need to get a reference to the WUIRadialController object with the method as explained in the class documentation. Looking at the header you’ll find the equivalent Objective-C projection under the WUIRadialController class interface:
@interface WUIRadialController : RTObject
[...]
+ (WUIRadialController*)createForCurrentView;
Call this method at the end of the viewDidLoad method of the view controller file to instantiate the WUIRadialController property:
- (void)viewDidLoad {
[...]
#ifdef WINOBJC
// Create a reference to the radial controller
self.radialController = [WUIRadialController createForCurrentView];
#endif
}
Now you need to get a reference to the radial controller menu and its items. This is done via the property of the class that returns a object. Looking back at the header, you’ll find the equivalent Objective-C property under the WUIRadialController class interface that returns a WUIRadialControllerMenu object:
@interface WUIRadialController : RTObject
[...]
@property (readonly) WUIRadialControllerMenu* menu;
Call this property to get a reference to the radial controller menu:
- (void)viewDidLoad {
[...]
#ifdef WINOBJC
// Create a reference to the radial controller
self.radialController = [WUIRadialController createForCurrentView];
// Get the radial controller menu
WUIRadialControllerMenu* menu = self.radialController.menu;
#endif
}
The menu items are accessible via the property of the class. As before, the interface of the WUIRadialControllerMenu class in the header gives you the equivalent Objective-C property:
@interface WUIRadialControllerMenu : RTObject
[...]
@property (readonly) NSMutableArray* /* WUIRadialControllerMenuItem* */ items;
Call this property to get a reference to the menu items:
- (void)viewDidLoad {
[...]
// Get the radial controller menu
WUIRadialControllerMenu* menu = self.radialController.menu;
// Get the menu items
NSMutableArray* menuItems = menu.items;
#endif
}
Next, you need to create a new object to add to the menu with the projection of the class method:
@interface WUIRadialControllerMenuItem : RTObject
+ (WUIRadialControllerMenuItem*)createFromIconNSString *)displayText iconWSSRandomAccessStreamReference*)icon;
Call this method to create the new menu item:
- (void)viewDidLoad {
[...]
// Get the menu items
NSMutableArray* menuItems = menu.items;
// Create a new menu item
// To use your own custom icon for the menu item, use the createFromIcon method instead
WUIRadialControllerMenuItem* newMenuItem = [WUIRadialControllerMenuItem createFromKnownIcon"Custom Tool" value:WUIRadialControllerMenuKnownIconRuler];
#endif
}
Note that we reused an existing icon for our tool from the enumeration, but you can create your own and use the method instead.
Finally, add your new menu item to the menu items array:
- (void)viewDidLoad {
[...]
// Create a new menu item
// To use your own custom icon for the menu item, use the createFromIcon method instead
WUIRadialControllerMenuItem* newMenuItem = [WUIRadialControllerMenuItem createFromKnownIcon"Custom Tool" value:WUIRadialControllerMenuKnownIconRuler];
#endif
// Add a new menu item
[menuItems addObject:newMenuItem];
}
That’s it! Now build and run your application and press and hold the Surface Dial to see the new menu item appear.
Adding a Handler for Click Input
In this section, you will add a handler for click input that will toggle the application switch control if the radial controller is clicked when the new tool you added to the menu is selected. Taking a look at the header, you’ll see you need the addButtonClickedEvent: method:
@interface WUIRadialController : RTObject
[...]
- (EventRegistrationToken)addButtonClickedEventvoid(^)(WUIRadialController*, WUIRadialControllerButtonClickedEventArgs
Since the callback relies on Objective-C blocks, you need to mark the self reference with the __block keyword before using it to access the switch to avoid creating a retain cycle. Add the following code at the end of the viewDidLoad method to do this:
- (void)viewDidLoad {
[...]
// Add a new menu item
[menuItems addObject:newMenuItem];
__weak ViewController* weakSelf = self; // Ensures self will not be retained
}
Now you can safely toggle the switch in the radial controller click callback:
- (void)viewDidLoad {
[...]
__weak ViewController* weakSelf = self; // Ensures self will not be retained
// Add a handler for click input from the radial controller
[self.radialController addButtonClickedEvent:^(WUIRadialController* controller, WUIRadialControllerButtonClickedEventArgs* args)
{
[weakSelf.switchControl setOn:!(weakSelf.switchControl.on) animated:YES];
}];
}
You can now build and run your application, select the new menu item, and click on the radial controller to see the switch toggle.
Adding a Handler for Rotation Input
In this section, you will add a handler for rotation input that will move the application slider control if the radial controller is rotated when the new tool you added to the menu is selected. Taking a look at the header, you’ll see that you need the addRotationChangedEvent: method:
@interface WUIRadialController : RTObject
[...]
- (EventRegistrationToken)addRotationChangedEventvoid(^)(WUIRadialController*, WUIRadialControllerRotationChangedEventArgs
As for the click event handler, simply call the method and update the slider value in the callback block:
- (void)viewDidLoad {
[...]
__weak ViewController* weakSelf = self; // Ensures self will not be retained
[...]
// Add a handler for rotation input from the radial controller
[self.radialController addRotationChangedEvent:^(WUIRadialController* controller, WUIRadialControllerRotationChangedEventArgs* args)
{
[weakSelf.slider setValueweakSelf.slider.value + ([args rotationDeltaInDegrees]/360.0f)) animated:YES];
}];
}
That’s it! Now build and run your application, select the new menu item and rotate the radial controller to see the slider value change.
Wrapping Up
Thanks for following along! You can download the complete for the final project. Take a look at the following resources for more information:
- For the latest release of the Windows Bridge for iOS, see the
- For documentation and tutorials, visit the Windows Bridge for iOS
- To evaluate the compatibility of your app with the bridge and evaluation virtual machines, go to the
- For sample apps and code using the bridge, check the
- For an overview of Windows wheel devices and UX and developer guidance, see on MSDN.
- For developer documentation on the Windows input system and classes, go to the namespace documentation on MSDN.
- To find the iOS bridge API, check the .
Also, be sure to check out the other posts in our series: