A set of techniques and features that facilitate creating UI that adapts automatically to different resolutions or application window size. Some of these techniques can be used to adapt the UI to any arbitrary condition (see custom triggers).
Effective pixels vs. physical pixels
When you write in your XAML something like Width=”100″ that will not set a width of 100 physical pixels. Instead it will set a width of 100 “effective” pixels. All the sizes and margins specified in a XAML file are expressed in effective pixels. The OS will choose how many physical pixels an effective pixel has based on the device type and screen size.
For example on a 7″ tablet with a resolution of 1920 X 1200 the OS will apply a scaling factor of 1.4 and to your XAML code the screen will appear as having a resolution of 1371.429… X 857.143… On monitor of 23″ with a similar resolution of 1920 X 1080, the OS will apply a scaling factor of 1.0 and to your XAML code the screen will appear as having a resolution of 1920 X 1080.
The idea is to make an element who’s size is set in effective pixels look roughly the same on different devices considering that different devices are placed at different distances from the viewer depending on their type and size. The result is that in general, this will allow a developer to write the same XAML regardless of the type of device or the size of the window where the application will run.
The golden rule in UWP UI sizing
As you design your UI, the margins and sizes of the UI elements (expressed in effective pixels) must be divisible by 4. Not an absolute rule but a good rule of thumb.
You may not be able to rely on effective pixels when dealing with images. You may need to provide different assets for the same image and let the OS pick the appropriate one based on naming conventions where the scale name is embedded in the name.
UI transition points
In some cases you can design your UI so that it has a smooth, continuous transition based on changing the size of your window. That is not always possible however. In some cases you will prefer to rearrange the UI when the screen size crosses a certain value. That value is called a transition point. In that case pick 3 transition points. Common practical transition points for the screen size are 5″, 8″, 13″.
The 6 Rs
These are design techniques that can be used to achieve a responsive / adaptive UI behavior.
Guidelines are less prescriptive
From what I have read it seems that with UWP Microsoft decided they will be less prescriptive when it comes to UI/UX design guidelines. It is not clear to me in what degree will the rules be relaxed but there is a general tendency to allow developers to do “what is best” for their applications.
XAML Adaptive Techniques
You can trigger a visual state based on a new XAML syntax. This allows you to switch to a different visual state based on the window resolution (in effective pixels). You no longer need to write code behind and call VisualStateManager.GoToState.
<VisualStateGroup> <VisualState x:Name="wideState"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="641" /> </VisualState.StateTriggers> ... </VisualState> </VisualStateGroup>
Visual State Setters
The XAML syntax available in the context of Visual States was improved. You can now set properties of XAML elements in a more concise form. The same effect was achievable in the past but then you needed to create a storyboard and use some verbose animation elements.
<VisualState.Setters> <Setter Target="filter.Margin" Value="12,12,12,0" /> <Setter Target="filter.FontSize" Value="12" /> <Setter Target="results.Margin" Value="12,12,12,30" /> <Setter Target="noResults.Margin" Value="12,12,12,0" /> </VisualState.Setters>
Writing adaptive UI brings new challenges. The new RelativePannel was specifically designed to help write adaptive UI. If you set the children of a RelativePannel in the right way (you will have to learn about the RelativePannel attached properties) they will adjust their position automatically even without any help from Visual States. Combining a RelativePannel and Visual States can increase the “adaptive-ness” of your UI even further.
Here is an example of using both a RelativePannel and Visual States:
<VisualState> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="720" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="button.(RelativePanel.RightOf)" Value="inputLabel" /> <Setter Target="button.(RelativePanel.Below)" Value="title" /> <Setter Target="avatar.(RelativePanel.RightOf)" Value="avatarLabel" /> <Setter Target="avatar.(RelativePanel.Below)" Value="inputLabel" /> <Setter Target="list.(RelativePanel.Below)" Value="avatar" /> </VisualState.Setters> ...
XAML now allows for visual states to be triggered using a new syntax. For example:
<VisualState> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="720" /> </VisualState.StateTriggers> ...
You can also create your own custom state triggers by inheriting from StateTriggerBase and invoking SetActive at the appropriate moment. You can use such custom trigger in XAML:
<VisualState> <VisualState.StateTriggers> <WarningLevelTrigger WarningLevel="Critical" /> </VisualState.StateTriggers> ... <VisualState.StateTriggers> <WarningLevelTrigger WarningLevel="High" /> </VisualState.StateTriggers> ... <VisualState.StateTriggers> <WarningLevelTrigger WarningLevel="Low" /> </VisualState.StateTriggers> ...
Question: Is there a potential for creating memory leaks here? Note that when implementing the custom trigger you do not know when it is getting out of scope (that is when the page that uses the trigger is unloaded). For example if you need your trigger to subscribe to an event of a global or long lived object, will your trigger class leak in memory? You could try to use an event subscription based on weak references (like the ones in MvvMCross) but then you will still have the event called after your page is unloaded and before the trigger instance is garbage collected. That means you will call SetActivate on the trigger after the page where the trigger lives was unloaded. Would calling SetActivate at such time cause an error or crash?
Would be nice if the trigger had something like a Loaded / Unloaded event.
This is a new technique that allows you to provide alternate versions for your pages. These alternate versions will be used automatically by the framework based on the device type where your application is running. For example let’s say that you have a page called MainPage.xaml. Using XAML views you can create one or more alternate versions of this page. You will have the regular file <Root>\MainPage.xaml (this is the default xaml file). For the mobile version you will create another file <Root>\DeviceFamily-Mobile\MainPage.xaml. Note the naming convention of the folder.
When using views you will not be allowed to provide a separate code behind for the alternate versions of your view. The code behind that is used for all versions of the view is still the one in file <Root>\MainPage.xaml.cs. With this technique you will only be able to vary the XAML file.
Question: It is not clear how useful this is if you cannot vary the code behind. What if the xaml is fundamentally different? Won’t keeping one code behind file lead to dirty code?
Question: If the two versiond of the XAML are fundamentally different to the point where you would othervise use different view models, how would you handle that situation? There are techniques that can be used to set the view model in XAML but they cannot be applied in any situation.
Question: Can you use this technique for user controls or custom controls?