NickN
Topic Author
Posts: 12
Joined: 23 Jan 2015, 13:51

Best way to scale a multi-panel UI?

01 Jul 2015, 19:15

This is for an iOS and Android app.

The image below shows the approximate layout. There is a top panel, a bottom panel, and the middle area is transparent (gameplay is seen in this area).

Each panel has an outline on three sides, and contains a number of static and dynamic elements e.g. circular buttons, text boxes, progress bars etc.

The panels should stretch to fit whatever device we are running on. The space between the top and bottom panels should maintain its current aspect ratio. The contents of each panel should also maintain their aspect ratio. i.e. the panels should fill the width of the screen, the circles should stay circular and the boxes remain square.
UISample-state01.png
Illustrative UI Sample / default state
Question 1: What is the best way to code this in XAML so it scales correctly?
I understand that a Viewbox will scale to fill, but how do I make sure that the border of the panel stays a constant width (not fatter in whichever direction the panel has been scaled), and the components keep their aspect ratio?

This is an example of what we don't want:
UISample-broken.png
Sample UI / What we don't want
Question 2: Both the top and bottom panels can be expanded vertically by the player (they drag down on the edge of the panel). They would do this to see additional information. When the panel is expanded, new components appear and existing ones move to a new position (they don't scale).

What is the best way to scale the panel so that the outline remains a constant width and the components stay the same size? For the outline, would it be best to form it as two pieces with the vertical lines as one piece and the bottom as a second piece and scale the vertical lines but move the horizontal line?

Please keep in mind how things are set up as per Question 1.
UISample-state02.png
Illustrative UI Sample / State 2
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: Best way to scale a multi-panel UI?

03 Jul 2015, 21:39

Take a look to the following XAML, it could inspire you to achieve what you need:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.RowDefinitions>
        <RowDefinition Height="3*"/>
        <RowDefinition Height="7*"/>
        <RowDefinition Height="2*"/>
    </Grid.RowDefinitions>
    <Border Grid.Row="0" Background="Cyan"/>
    <Viewbox Grid.Row="0" Stretch="Uniform" HorizontalAlignment="Left">
        <StackPanel Orientation="Horizontal" Margin="20">
            <Rectangle Width="100" Height="100" Fill="Gold"/>
            <Rectangle Width="10" Height="100" Fill="Red" Margin="10,0,0,0" VerticalAlignment="Bottom"/>
            <Rectangle Width="10" Height="60" Fill="Blue" Margin="2,0,0,0" VerticalAlignment="Bottom"/>
        </StackPanel>
    </Viewbox>
    <Border Grid.Row="1" Background="Black"/>
    <Border x:Name="BottomRow" Grid.Row="2"/>
    <Canvas Grid.Row="2">
        <StackPanel x:Name="BottomPanel" Grid.Row="2" VerticalAlignment="Top" Width="{Binding ActualWidth, ElementName=BottomRow}">
            <StackPanel.RenderTransform>
                <TranslateTransform Y="0"/>
            </StackPanel.RenderTransform>
            <Border Background="Cyan">
                <Viewbox Stretch="Uniform" Height="{Binding ActualHeight, ElementName=BottomRow}">
                    <Grid Margin="10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Ellipse Grid.Column="0" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                        <Ellipse Grid.Column="1" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                        <Ellipse Grid.Column="2" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                        <Ellipse Grid.Column="3" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                        <Ellipse Grid.Column="4" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                        <Ellipse Grid.Column="5" Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Grid>
                </Viewbox>
            </Border>
            <Border Background="Cyan">
                <Viewbox Stretch="Uniform">
                    <Rectangle Width="200" Height="100" Fill="White" Margin="10,10,10,400"/>
                </Viewbox>
            </Border>
        </StackPanel>
    </Canvas>
    <StackPanel Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button Content="Up">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation To="-200"
                                    Storyboard.TargetName="BottomPanel"
                                    Storyboard.TargetProperty="RenderTransform.Y"/>
                            </Storyboard>
                        </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
        <Button Content="Dn">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation To="0"
                                    Storyboard.TargetName="BottomPanel"
                                    Storyboard.TargetProperty="RenderTransform.Y"/>
                            </Storyboard>
                        </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
   </StackPanel>
</Grid> 
But I have to say that if screen aspect ratio changes it will be impossible to keep height of top and bottom rows, and margins of elements inside top and bottom panels at the same time. You have to decide which are your constraints.

If you want that elements inside panel always have the same margins, you have to let the panel grow or shrink in height to fill the width of the screen.

If you want to keep the size of the panel relative to the height of the screen, then the margins of elements inside the panel can't be the same when aspect ratio changes.
 
NickN
Topic Author
Posts: 12
Joined: 23 Jan 2015, 13:51

Re: Best way to scale a multi-panel UI?

04 Jul 2015, 06:24

Thanks for the help.

Just to clarify, I'd like to keep the vertical proportions of the transparent area (the black box) and the panels the same on all devices. e.g. top panel 10% of vertical screen height, bottom panel 25%, middle area 65%.

The width of the top and bottom panels can change as needed. The components within the panels should always maintain their aspect ratio, but can otherwise scale to fit within the panel. The spacing/margin between components can also change as needed based on the panel size.

For example, on a wider screen the panels would remain the same vertical height but increase in width. The components within the panels would spread out across the wider panels. On a narrower screen, the components would get closer together, possibly scaling down in size if necessary to avoid overlap.
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: Best way to scale a multi-panel UI?

06 Jul 2015, 11:29

If you want to keep the vertical proportions, then my sample does what you need. Just adjust the percentages in the rows:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.RowDefinitions>
        <RowDefinition Height="10*"/>
        <RowDefinition Height="65*"/>
        <RowDefinition Height="25*"/>
    </Grid.RowDefinitions>
    ... 
To evenly distribute elements in bottom panel, then you have to divide it horizontally using a Grid too, and wrap each element in the cell with a Viewbox:
    ...
    <Border x:Name="BottomRow" Grid.Row="2"/>
    <Canvas Grid.Row="2">
        <StackPanel x:Name="BottomPanel" Grid.Row="2" VerticalAlignment="Top" Width="{Binding ActualWidth, ElementName=BottomRow}">
            <StackPanel.RenderTransform>
                <TranslateTransform Y="0"/>
            </StackPanel.RenderTransform>
            <Border Background="Cyan" Height="{Binding ActualHeight, ElementName=BottomRow}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Viewbox Grid.Column="0" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                    <Viewbox Grid.Column="1" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                    <Viewbox Grid.Column="2" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                    <Viewbox Grid.Column="3" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                    <Viewbox Grid.Column="4" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                    <Viewbox Grid.Column="5" Stretch="Uniform">
                        <Ellipse Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="4" Margin="10"/>
                    </Viewbox>
                </Grid>
            </Border>
            <Border Background="Cyan">
                <Viewbox Stretch="Uniform">
                    <Rectangle Width="200" Height="100" Fill="White" Margin="10,10,10,400"/>
                </Viewbox>
            </Border>
        </StackPanel>
    </Canvas>
    ... 
 
NickN
Topic Author
Posts: 12
Joined: 23 Jan 2015, 13:51

Re: Best way to scale a multi-panel UI?

10 Jul 2015, 04:22

Just adjust the percentages in the rows:
Quick question: do the percentages have to be integers?
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: Best way to scale a multi-panel UI?

10 Jul 2015, 09:57

No, you can use a decimal number. I just put integer values to match your numbers, but that it is equivalent to:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.RowDefinitions>
        <RowDefinition Height="0.10*"/>
        <RowDefinition Height="0.65*"/>
        <RowDefinition Height="0.25*"/>
    </Grid.RowDefinitions>
    ... 

Who is online

Users browsing this forum: Bing [Bot] and 46 guests