Saturday, March 16, 2019

Building Responsive(ish) PowerApps

Providing users with the ability to access content on their mobile devices has become common place and somewhat of a necessity today.  In the best case, it would be good to have a single solution that can serve multiple devices and orientations.  This article discusses how you can achieve this for PowerApps.




App Settings

Screen size + orientation

Start with creating a PowerApp Canvas App using a Phone layout and orient it to landscape.  On the Screen size + orientation layout page, make sure you disable Scale to fit.  Disabling this setting will allow your app controls to remain the same size regardless of the resolution.  Also disable the Lock orientation so your app will work in both portrait and landscape orientation.  You will notice near the top of the page that the resolution of the app is set to 1136 x 640.   Remember this number as we'll get back to it soon.



Advanced Settings

Next, go to the Advanced Settings tab and enable the Try the enhanced Group control.  Not only does this control help with accessibility, but it also allows you to position your controls on the screen  as a group.


At this point, you will be able to build an app that will have consistent component sizes.  On to the fun part. 

Dealing with screen size and orientation

Each screen has two properties that can be used to determine its size and orientation - Width and Height

Determining how to deal with screen sizes

When you query the Width and Height, it's easy to determine what orientation you are in.  If the Height is greater than the Width, then the orientation is portrait.  Otherwise, it's landscape.  For simplicity, you can store the orientation in a context variable for reference.

If(Screen1.Width < Screen1.Height,
UpdateContext({orientation:"portrait"}),
UpdateContext({orientation:"landscape"}));

Now to the device and screen size.  Responsive design uses something called Break Points and Media Queries to determine how to render a web page based on the browser size.  We can do something similar in PowerApps.  In my example, I decided that anything with a Width or Height greater than 2000 should be considered a tablet while anything smaller is a phone.  The exception is that if the width is exactly 1136 and the height is 640 then it's a Desktop.  The reason for this last scenario is that PowerApps renders the app using these dimensions in the browser.  So, I determined the device type as follows:

If(Or(Screen1.Width > 2000,Screen1.Height > 2000),
UpdateContext({device:"tablet"}),
If(And(Screen1.Width = 1136,Screen1.Height = 640),UpdateContext({device:"Desktop"}),UpdateContext({device:"phone"}))


This approach is conceptual and you can define other rules to determine how the app should render. 

What happens when a device changes orientation

So far, I've discussed how to determine the orientation and device type.  But when are these determined?  One way is to set them using the OnVisible property for the screen.  This will work, but will not change when the phone or tablet is changing orientation.  What you can do to address this is add a timer to your screen and add these settings to the OnTimerEnd property.  Set the Duration to be short (e.g. 100 ms) and make sure the AutoStart and Repeat properties are set to true so that the timer will begin as soon as the screen is displayed and will continue to check these settings.

Organizing your controls on a screen

Group components

Earlier in the article, I mentioned that the experimental Group components control should be used.  This control is great for developing responsive apps as it allows you to easily move groups of controls around on the screen rather than treating each one separately.

Make everything relative

Every control has a number of properties that are used to determine where it is positioned on a screen and how big it is.  As well, some controls that are text based have settings to indicate the font family, size, and weight.   When you add controls to a screen, these settings have default fixed values.  In order to allow you to better control the overall layout of your app, its better to use relative values.  This way, when one control changes, all other controls relative to it will change.  For example, in the image below, I am forcing the left group control to be 10px from the top and left of the screen border.  Likewise, I'm setting the Device and Screen Width labels to be 10px from the top and left inside their Group components controls.  All other controls are set to be spaced 10px apart across and down the page.  

For the Group components control on the right, I'm determining its location based on the orientation.  If it's a landscape orientation, then I set the X positions to be 10px after the end of the right Group components control.  Otherwise, I set it at 10px and below the right group control.  


So, for the example above, the Group component on the left is grp1 and the one on the right is grp2.  The positions for grp2 are determined as follows:

  • X: If(orientation = "portrait",10,grp1.X+grp1.Width+10)
  • Y:  If(orientation = "portrait",grp1.Y+grp1.Height+10,10)
Building on this approach, I also defined context variables for the font size and control widths and heights so that smaller devices will have larger fonts and boxes to make them easier to read.  The full expressions for the resizing in my case are:

If(Screen1.Width < Screen1.Height,
UpdateContext({orientation:"portrait"}),
UpdateContext({orientation:"landscape"}));
If(Or(Screen1.Width > 2000,Screen1.Height > 2000),
UpdateContext({device:"tablet",fontsize:30,height:50,width:300,width2:200}),
UpdateContext({device:"phone",fontsize:40,height:70,width:400,width2:300}));
If(And(Screen1.Width = 1136,Screen1.Height = 640),
UpdateContext({device:"Desktop",fontsize:14,height:25,width:140,width2:100,orientation:"landscape"}))

Conclusion

Using the techniques discussed above can, you can build apps that will resize their controls based on the device used and the way it's oriented.  The approach can be further expanded on to show/hide certain controls.

0 comments:

Post a Comment