Xamarin – Placing Static Content Over A Scrolling View

Hello all,

I have recently started learning Xamarin, my approach to Xamarin is building lots of demo apps that do things that I have been using in iOS. Something I do a lot in iOS is nest scrolling views (UIScrollView, UITableView) inside a main view so that I can display static content over the scrolling view.

This already sounds complicated & difficult so lets have a look at a sample app that I have whipped together in Xcode…. (View the storyboard file here) 

scrollviewgif.gif

As you can see we have a scroll view & a label, the label is fixed to the centre of the screen whilst the scroll view can slide around to your hearts content. Lets have a look at the storyboard implementation in Xcode.

Screen Shot 2018-02-05 at 09.35.00.png
The label is not embedded within the UIScrollView!

As seen below we have a UIScrollView and a UILabel. The label has been constrained to the centre of the view. The scroll view is constrained to the view’s boundaries & has content that leaves the screen. The user of this app can swipe up and down to move the scroll view. However, notice that our label is not embedded within the scroll view. This means that it’s location will not be affected by the scroll view, it will always appear in the middle of the screen independent of the scroll view.

Scroll View Storyboard.png
The different UI elements on the same view.

For this example we have used storyboards, this approach will not work in Xamarin as we don’t have storyboards. Instead we use C# or XAML to create our UI, lets have a look at recreating this example in Xamarin!

When using Xamarin Forms there are 2 ways that you can create your UI, Code or XML. Deciding which to use is largely up to the developer, I would argue writing the UI in code adds unnecessary density to your view controller. However I believe it is easier to conceptualise UI through code and will generally convert my UI code into XAML (if I need to create a complex UI). So first lets look at creating our UI in code!

Project Setup

First things first we need to create a Blank Xamarin Forms project. Open up visual studio (I’m using VS Mac) and create a new solution (project). Navigate to Multiplatform and select Blank Forms App.

Screen Shot 2018-02-05 at 11.06.54.png

Name your project however you want but make sure you select “Use XAML for user interface files”.

Screen Shot 2018-02-05 at 11.07.26.png

Continue through the project creation (you don’t have to create a git repo for this project) and create your project. Open up the shared project folder and open up the Main Page (it should be named “YOUR_PROJECT.Xaml”, open up this file and navigate to the “YOUR_PROJECT.Xaml.cs” file, we are ready to begin!

Writing the UI in Code

We will be using C# to write our user interface you can find the complete code for this example (in C#) is available here!

The first thing we want to do is initialise some UI objects for us to use. In my Xamarin example I have gone a little further than the iOS example and have used a stackview to recreate the appearance of a list view.

AbsoluteLayout absoluteLayout = new AbsoluteLayout();
RelativeLayout relativeLayout = new RelativeLayout();
ScrollView scrollView = new ScrollView();
BoxView scrollBox = new BoxView();
StackLayout stackView = new StackLayout();
Button myButton = new Button();

So in the above code we have created some UI objects, as well as an Absolute & Relative layout. We are going to use the Absolute layout as our Content Page’s ‘master’ view & embed our ScrollView within the Relative layout (which acts as a container). You might wonder why we would need to embed the Scroll View within another layout. This is because if we added the scroll view to the absolute layout, it would not be correctly laid out with respect to the absolute layout and would be unable to scroll correctly (we can come back to this later).

Lets format the scroll view, I have given mine a whacky background colour (you don’t need to do this, but using colours is a good way to test if your code is working properly). What is important here is that you set the height of the Scroll View to be larger than the view height of a mobile device. Once the Scroll View is too large for the screen it’s being displayed on, it will be able to scroll. You must also set the width of the Scroll View to fill the space available to it.

scrollBox.BackgroundColor = Color.Yellow;
scrollBox.HeightRequest = 2000;
scrollBox.HorizontalOptions = LayoutOptions.Fill;

Now lets go on a little tangent and create some content to display on the scroll view. Rather than bothering to create a List View, I used a Stack Layout to display a large number of Labels. I created the following method to quickly create Labels to be displayed in the Scrolling View.

public Label CreateLabel() {

    Label localLabel = new Label();
    localLabel.Text = "Sample Text...";
    localLabel.TextColor = Color.Black;
    localLabel.BackgroundColor = Color.LimeGreen;

    return localLabel;
}

This method will create and return a unique label, lets use it to add 30 buttons to our Stack Layout. We can achieve this using a loop!

for (int i = 1; i < 30; i++) {
    stackView.Children.Add(CreateLabel());
}

Since the method we created returns a Label object, we can loop through the add children method of the Stack Layout to keep adding views. Finally lets format our Stack Layout and add it to our Scroll View:

stackView.Padding = new Thickness(10, 10, 10, 10);
stackView.Spacing = 20;

scrollView.Content = stackView;

Now we want to add our Scroll View to our Relative Layout (the layout that will contain the Scroll View).

relativeLayout.Children.Add(scrollView,
    xConstraint: Constraint.Constant(0),
    yConstraint: Constraint.Constant(0),
    widthConstraint: Constraint.RelativeToParent((parent) => { return parent.Width; }),
    heightConstraint: Constraint.RelativeToParent((parent) => { return parent.Height; }));

This code allows the Scroll View to resize dependant on the screen it is being displayed on!

Now we have created our scrolling content, lets create our fixed content. You can play about at this step with any UI element you want. You could add a label, button, box at this point… Or even create a more complicated view (a box with a button & label), but I will leave that up to you. I decided to create a simple button:

myButton.Text = "Press Me!";
myButton.BackgroundColor = Color.Black;
myButton.TextColor = Color.White;
myButton.HorizontalOptions = LayoutOptions.CenterAndExpand;
myButton.VerticalOptions = LayoutOptions.CenterAndExpand;
myButton.WidthRequest = 200;
AbsoluteLayout.SetLayoutBounds(myButton, new Rectangle(0.5, 0.95, 200, 50));
AbsoluteLayout.SetLayoutFlags(myButton, AbsoluteLayoutFlags.PositionProportional);

What is important about this step is telling the Absolute Layout where to place the Button.

The layout bounds tell the view where to position the view relative to the screen. The X,Y positions range from 0 (top/left) to 1 (bottom/right).

AbsoluteLayout.SetLayoutBounds(myButton, new Rectangle(0.5, 0.95, 200, 50));

You can read about Absolute Layout Flags here, for now all you need to know is that that they determine how the view is laid out.

AbsoluteLayout.SetLayoutFlags(myButton, AbsoluteLayoutFlags.PositionProportional);

At this point we have created our Scrolling View & our Static View. If you try and run your project, you won’t see anything yet, we haven’t set our Views Content Page yet! If you recall we wanted to use our Absolute Layout as the input view for our Content Page, so lets do that:

absoluteLayout.Children.Add(relativeLayout);
absoluteLayout.Children.Add(myButton);

Content = absoluteLayout;

And there we go, that is all of our code written, lets have a go at building and running this project. Since we have used Xamarin Forms to build this app, we should probably check the app on both iOS and Android!

Screen Shot 2018-02-05 at 11.03.23.png

Beautiful! With any luck your project should look something like the above screenshot. The appearance of the app will be localised to the platform you are running it on, but the functionality will be the same!

Rewriting our UI in XAML

We have now created our UI in code using C#, lets now convert this code into XAML so that we can keep our UI & Controller code separate. You can create a new project for this or do what I did and comment out all of the code you have just written (select all, cmd+/).

As with the previous example, you can find the code for this project on Github Gist.

The first thing we want to do is add some padding to our content page.

<ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness">
        <OnPlatform.iOS>0,20,0,0</OnPlatform.iOS>
    </OnPlatform>
</ContentPage.Padding>

Due to the implementation of the views in iOS, if you don’t padding to your content page the view will stretch behind the status bar. This won’t look very good so we can add some iOS specific padding to our view to make it look better for iOS users.

If you remember the layout of our previous example, it looked something like this:Screen Shot 2018-02-05 at 11.26.42.png

So we want to be creating this structure in our XAML. Since everything is nested inside an Absolute Layout we should add this first.

<AbsoluteLayout>

</AbsoluteLayout>

We can now create our Static & Scrolling Views, lets start with creating the general structure of the views. We need to create a Relative Layout & a Button.

<ContentPage.Content>

    <AbsoluteLayout>

        <RelativeLayout>

        </RelativeLayout>  

        <Button Text="Press Me!"
                TextColor="White"
                BackgroundColor="Black"
                AbsoluteLayout.LayoutBounds="0.5, 0.95, 200, 50"
                AbsoluteLayout.LayoutFlags="PositionProportional"
        />

    </AbsoluteLayout>

</ContentPage.Content>

As I previously stated, you can get creative with the content you chose to place over the Scroll View, I’ve simply opted for a simple button. Since XAML allows for us to preview our view, you should be able to see the view being rendered in the preview window.

Screen Shot 2018-02-05 at 11.41.07.png

Lets create our scroll view, this code will create what we have already made in the C# example:

<ScrollView BackgroundColor="Yellow"
                    RelativeLayout.XConstraint="0"
                    RelativeLayout.YConstraint="0"
                    RelativeLayout.WidthConstraint="{ConstraintExpression
            Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
                    RelativeLayout.HeightConstraint="{ConstraintExpression
            Type=RelativeToParent,Property=Height,Factor=1,Constant=0}"
                    >

    <StackLayout Padding="20,20,20,20"
                    Spacing="20"
                    >

        <Label Text="Dummy Text Here..."
                            TextColor="Black"
                            BackgroundColor="Lime" />

    </StackLayout>

</ScrollView>

Now when using XAML we have to use XAML Markup Extension to be able to perform calculations at run time. In this case we want the Scroll View to set it’s widths equal to its parent view (the relative view). If you place the above code within the Relative Layout, you should see the following preview.

Screen Shot 2018-02-05 at 11.49.19.png

At this point we only have 1 label & if you run this app, it will not scroll (because the contents of the scroll view is not larger than the screen height). In the C# example we utilised a for loop to create alot of labels. Unfortunately with XAML we cannot do this, to recreate the same example purely in XAML we would have to copy and paste the label a few dozen times (not ideal). A solution to this problem would be connecting the Stack Layout to our C# code and adding buttons to it (in the same way we did before) however I’ll leave you to figure that one out! Instead lets copy and paste the Label code a few times:

<Label Text="Dummy Text Here..."
    TextColor="Black"
    BackgroundColor="Lime" />

You should see more labels being created in the preview window. Keep adding labels until they start going off the screen, add a few more for safety and then run the app. Your app should look something like this at runtime:

ScrollingViewXam.gif

And there we are, we have created a static button that appears over a scrolling view. Hopefully this example gives you the skills to be able to go away and add a fixed view to any type of scrolling content (like a List View).

You can find the completed solution available on GitHub.

Thanks for reading, happy Xamarining!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s