In my previous topic, I covered the background and why you should create adaptive, or responsive, apps using the new Universal Windows Platform (UWP). In this topic I will cover some specific tips and techniques to accomplish it.

The goal of an adaptive UI as it relates to UWP is to build as close to a single UI as possible that is adaptive for all devices.

Visual Studio 2015 Improvements for Adaptive UI

The tooling in Visual Studio 2015 now makes it easier to design layouts that will adapt nicely. When you install the Windows 10 Developer tools you get a new Universal Project template. And you also get a variety of simulators and emulators to debug your app. That’s pretty much the same as from Windows 8.1. The major difference being now that a single project can be debugged on all devices.

But what’s really neat is that now you can preview your XAML UI screens in the designer for a variety of resolutions and orientations. It’s just part of how Visual studio 2015 is making development easier and easier, and we’re becoming less dependent on Expression Blend (remember that thing?) for these types of tasks.

Visual_Studio_2015_UWP_Designer_Preview

Adaptive UI Techniques for XAML

Now let's look at some adaptive UI techniques for code and XAML. I've broken it up into 3 main sections.

  • Use best practices with primitive layout controls to design our UI so it can be easily adapted to various resolutions.

  • Use the SizeChanged event and the Visual State Manager class to provide UI changes for different device sizes and orientations (portrait vs landscape vs phone).

  • Use conditional code against device family APIs to provide UI changes for different device types (PC vs phone).


Use Best Practices with Primitive Layout Controls

The most important technique for adaptive UIs is understanding the primitive layout controls available and using them to the best of their abilities. You can’t have an adaptive UI without following best practices with these controls. Some of these you may very well be familiar with, but if not, they are a key building block here that need to be understood.

  • Grid

  • StackPanel

  • ListView

  • GridView

  • ViewBox

  • ScrollViewer

  • RelativePanel *New in UWP

  • SplitView *New in UWP


The #1 best practice with primitive layout controls:
Don't use explicit widths and heights - let children fill the space of their parent.

This can't be said enough. XAML is a beautiful application layout. When Microsoft wrote it they took the best from HTML and combined it with new ideas focused on building application UI’s to really make a great. If you can avoid using explicit heights and widths your app will automatically adjust and display properly on any sized device.

Grid vs StackPanel

The Grid and StackPanel are the two most common layout controls, and with them you can do so much. With a Grid layout, you specifically position all of its children. You set which row they go in, and how many columns they span. Then, based on the size you set for each row or column, the children will fill the space. That means we don’t normally set Height and Width explicitly on the children. Again, this is the #1 rule. We’re dealing with apps that need to render on a variety of devices, so we will let the primitive layout controls do a lot of the automatic layout for us.

ListView vs GridView

With ListView and GridView we are looking at the modern versions of the list and data grid controls. These are bound ItemsControls, but with such simple UI’s these days, many of the app pages you create will just be a header and then one of these guys. So it’s important to consider them when designing your UI. They both provide item selection which is a common use case. These controls are easily interchangeable.

It's typical to use a GridView for the PC/tablet UI and use a ListView in its place for the phone UI.

ViewBox vs ScrollViewer

Most of the time you don’t even need to think about these controls. But they do come in very handy for many cross-device scenarios, so it’s good to know about them and how to use them. Let’s say you have a block of content that you need to display on all devices, and it’s not really something that can be chopped up and rearranged. You have a couple options with these primitive controls. The ViewBox is not one you hear of much. It’s used for creating resolution dependent views. It will stretch and scale its child items to fit the available space. So that means on a large monitor the content will stretch from end to end, and on a screen it will show the exact same content shrunken down. This is not normally ideal, but it’s good to know this control exists.

If this were an actual battle there’s a clear winner with the ScrollViewer. ScrollViewers are used in all controls that have scrolling. So if you’re using a ListView or GridView, you are using ScrollViewer baked into it. But don’t forget that the ScrollViewer can be used on its own. It’s especially useful if you have a block of UI that you want to support on any size device. The scrollViewer can be seen as a safety line. Worst case scenario the content is cut off the screen, but hey the user can scroll it into view. No big problem.

ScrollViewer_ViewBox_UWP

New Adaptive Layout Controls

Along with the new Universal Windows App Platform comes a few new controls to help build adaptive apps: SplitView and RelativePanel.

RelativePanel is like a grid but requires less markup to create certain layouts.

RelativePanel_UWP

SplitView is a very useful control to create master/detail page navigation or hamburger lists.

SplitView_UWP

SizeChanged Event & Visual State Manager Handles Different UI States

The second main technique for creating adaptive UIs is using the SizeChanged event or the Visual State Manager (VSM) to handle UI states for different scenarios such as different device sizes. In many cases you will need to create a different UI for the phone compared to the PC/tablet view. The SizeChanged event and Visual State Manager allow you to still share a single view for all layouts and just apply changes to it make it adapt as necessary.

What is the Visual State Manager?

The Visual State Manager manages visual states and the logic for transitions between visual states for controls. The code you saw me using in the SizeChanged event wasn’t too bad. But imagine a more complex UI. In the XAML development world, it’s just not natural to modify the UI in code-behind. We want to be able to control every UI aspect in XAML, so that’s where the VSM comes in. It’s basically a XAML-driven approach to handling UI state changes.

The way it works is that you define your default UI in XAML. And then you create any number of “states” in the VSM that modifies the default UI to fit a certain scenario. For instance, when you rotate the device into portrait mode, you may want to adjust the margins or padding a bit on some controls. This is something that is best handled in the VSM. Here's a sample VSM.

VisualStateManager_VSM

The SizeChanged event can do the same thing as the VSM, but it's handled entirely in code-behind. You typically subscribe to the SizeChanged event on your page. I prefer to use the VSM as much as possible because UI definitions are meant to be in XAML not code-behind. Try creating a Grid with 2 columns, 2 rows and position all of its children in code-behind and compare it to XAML to see what I mean.

Adaptive Triggers are a new feature in Windows 10 tooling for the VSM. It eliminates the need for some code to listen for size changes. You'll notice the XAML snippet above uses adaptive triggers.

And keep in mind that we’re not only interested in supporting tablet and phone device sizes, but these basic techniques help us provide UI changes for orientation changes - portrait vs landscape.

Conditional Code Let's You Distinguish Between PC and Phone

You can support different behaviors depending on the specific device the user is running. This must be written in code as no feature in XAML supports platform discrepencies. This is great for when you have a difference that is split – you want one way for Phones and another for tablets. This doesn’t take size into account at all, so you’ll always get the same tablet experience no matter what the size.

Tailoring your app for a particular device

New Windows 10 API contracts and the extension SDKs allow you to adapt your code at runtime to deliver user experiences that feel right on the device it’s being run on.

You can choose to tailor your app to light up additional device-specific capabilities using adaptive code patterns. You can reference an Extension SDK that supplies device specific APIs and write code that checks for the presence of the API when running on any device before code execution.

Read more about this here: http://blogs.windows.com/buildingapps/2015/04/30/whats-new-in-visual-studio-tools-for-universal-windows-apps/

Controls with Different Behaviors Per Device


There are a couple controls that have different behaviors whether you use them on the phone or a tablet/PC.

App Bars



  • App Bars provide users with easy access to navigation and common commands.

  • App Bars are a feature of the Page (which can be shared in Universal apps).

  • Typically used with CommandBar control

  • On a phone, only four primary commands will be displayed

  • Tip: use conditional code to move extra items to secondary menu


AppBar_UWP

 

Semantic Zoom


A great example of a shared control that behaves differently on each platform is the SemanticZoom control. This was originally just for Windows Apps, but with Universal it comes to Windows Phone.

On PC/tablet, it gives you a zoomed in and zoomed out view controller on pinch/stretch gestures. On Phone, it behaves like the LongListSelector and tapping grouped headers will zoom in and out. Tablets are two handed devices whereas phones are designed for one hand. So that’s why semantic zoom should not require pinching on a phone. It works the same by just tapping the group headers.

SemanticZoom_UWP


In Summary/Additional Tips



  • Use best practices with primitive layout controls to design our UI so it can be easily adapted to various resolutions.

  • Remember - primitive layout controls are adaptive by nature

  • Use the SizeChanged event and the Visual State Manager class to provide UI changes for different device sizes and orientations (portrait vs landscape vs phone).

  • If you ever find yourself rewriting or copying code from within the same project, it’s a sign that you should be sharing it. The VSM helps us avoid this redundancy in our XAML.

  • Use conditional code against device family APIs to provide UI changes for different device types (PC vs phone).