Auto Layout, Beer Drinkin, iOS, Uncategorized

Stretchy UITableView Headers with Xamarin

The Yahoo News Digest app includes a couple of interesting user interface elements that I wanted to use within my own apps. The feature that I was most keen to recreate was the stretching UITableViewHeader. Its an effect seen in lots of iOS (sometimes referred to as a parallax header). As Beer Drinkin is going to support multi-tasking on iOS, I needed to ensure my implementation continues to support Storyboards and Auto Layout. Fortunately it proved very simple to get everything setup. In this blog post I’ll be sharing how I went about implementing it

beerdrinkinStretchy

Setting up the Storyboard

Adding a header view

To get started I opened my existing Storyboard and selected the UIViewController that requires the tableview header. In my case the scene (or view controller) isn’t a UITableViewController because I require a floating ‘Check in’ button to be visible at all times. Its worth noting that all the steps in the tutorial work with both UITableViewControllers and UIViewControllers.

Screen Shot 2016-02-01 at 11.36.06

Once I had the storyboard loaded, I dragged a UIView from the toolbox and made sure to insert it above the UITableViewCells as a the header view for the table. I then added a UIImageView to the new UIView and set its constraints to be 0,0,0,0. This way when the parent view (the UIView) resizes, the UIImageView will resize as well. I also made sure to set the UIImageView view mode property to Aspect Fit, which makes sure the image looks great no matter what size the view.

Screen Shot 2016-02-01 at 11.39.13

Adding some C#

Adding the resize code

If I were to have run this now, the table header would be displayed but wouldn’t resize with scroll events. To add scaling, I needed to add a code into my ViewController to setup the stretchy goodness that I wanted.

Because I use the header views height in a number of locations throughout the beer description view controller, I went ahead and created a variable rather than scattering magic numbers over my class.

private nfloat headerViewHeight = 200;

Managing the header view

To allow me to manage the table header, I needed to remove it from the UITableView and keep it as a variable for use later. To do this I created a variable in the beer description view controller.

private UIView headerView;

When we load the view controller, we’ll want to set our headerView variable and then set the UITableViews header property to null. This means the tableview has no header view to manage anymore, instead I’ve taken control of the view which allows me to ensure it resizes correctly as the table view scrolls.Despite having just removed the header view from the UITableView, I actually want to go ahead and add it to the table view hierarchy (but not as the header view property of the UITableView)

 headerView = tableView.TableHeaderView;
 tableView.TableHeaderView = null;
 tableView.AddSubview (headerView);
 tableView.ContentInset = new UIEdgeInsets (headerViewHeight, 0, 0, 0);
 tableView.BackgroundColor = UIColor.Clear;

Listening to TableViewDidScroll

In order to successfully respond to the DidScroll event of the UITableViewSource, I’ll need to create an event in the table views delegate. This is because of an issue with the UITableView DidScroll event not firing when a delegate has been set.

public override void Scrolled (UIScrollView scrollView)
{
    DidScroll ();
}

public event DidScrollEventHandler DidScroll;

We can now hook up the table DidScroll event with a small piece of logic for resizing the view.

//Update Tableview
tableView.Source = new BeerDescriptionDataSource(ref cells);
var deleg = new DescriptionDelegate (ref cells);
deleg.DidScroll += UpdateHeaderView;
tableView.Delegate = deleg;

tableView.ReloadData ();
View.SetNeedsDisplay ();
//...
void UpdateHeaderView ()
{
    var headerRect = new CGRect (0, -headerViewHeight, tableView.Frame.Width, headerViewHeight);
    if (tableView.ContentOffset.Y < -headerViewHeight)
    {
        headerRect.Location = new CGPoint (headerRect.Location.X, tableView.ContentOffset.Y);
        headerRect.Size = new CGSize (headerRect.Size.Width, -tableView.ContentOffset.Y);
    }
    headerView.Frame = headerRect;
}

Conclusion

Its very easy to use this approach to add resizing animations to any number of controls within your UITableView. My favourite part of this solution is that it works perfectly across all iOS devices and doesn’t force me to drop support of Autolayout.

Uncategorized

Adding Parse to your Xamarin.Forms solution

I’ve recently been developing a Xamarin.Forms app which required a cloud service for data persistence and syncing across multiple devices and platforms. Normally when I’m developing Xamarin.Forms apps, it tends to be because I’m either writing a proof of concept or a tech demo. Both these types of projects focus of speed of development and code reuse rather than crafting delightful user experiences (it’s 100% possible to create delightful experiences in forms, its just not the primary objective of a Xamarin.Forms app in most situations).

The app I’m developing requires both user signup and the ability of the user to sign in, which is where the Parse .NET client API shines. Although Parse may be one of the more unknown cloud service providers (especially in .NET circles), it’s my favourite for a number of reasons. It’s incredibly easy to get started with, the API is concise, and the documentation is fantastic. Not to mention a generous free plan makes it a no brainer for apps I want to deploy quickly, while being unsure how much traffic they’ll bring. My only complaint when using Parse is the lack of PCL for Xamarin.Forms. I have spoken with Parse about this and they assure me this issue will be resolved.

Adding Parse to your Forms app

Because of the PCL issue for Xamarin.Forms, you’re going to need to select a Shared Code solution, rather than a PCL backed solution. Once you’ve done this, you’ll need to add the Parse Nuget package to the individual platform projects. This means, firing up the package manager and adding Parse to the iOS, Android, and Windows Phone projects.

Initialising Parse

Before getting started with Parse, you’re going to need to ensure it’s initialised. I tend to create a class called Keys in my forms solution, which is where I store all the keys to services such as Parse and Xamarin.Insights. Below is an example keys class which you can reuse in your Xamarin.Forms apps.

//Keys.cs
public class Keys
{
    public static readonly string XamarinInsightsKey = "0000";

    public static readonly string ParseAppKey = "0000";
    public static readonly string ParseDotNetKey = "0000";
}

You can then call the ParseClient.Initialize API.

public App()
{
    ParseClient.Initialize(Helpers.Keys.ParseAppKey,   Helpers.Keys.ParseDotNetKey);

    // The root page of your application
    MainPage = new ContentPage{BackgroundColor = Color.Red};
}

Signing up a user

Now that Parse is ready to use, lets go ahead and create a new user. The API for creating a user couldn’t be any simpler, it’s one of the reasons why I’ve fallen in love with using Parse.

private async Task ExecuteSignUpUserCommand ()
{
    if (IsBusy)
        return;
    IsBusy = true;

    try
    {
        var user = new ParseUser()
        {
            Username = username,
            Password = password,
            Email = email
        };

        user["firstName"] = firstName;
        user["lastName"] = lastName;

        var connected = CrossConnectivity.Current.IsConnected;
        if (connected)
        {
            UserDialogs.Instance.ShowLoading ("Creating Account");

            //The code that actually signs a user up!
            await user.SignUpAsync();

            //More UI stuff..
            UserDialogs.Instance.HideLoading ();
            await NavigateToMainUI ();
        } else {
            UserDialogs.Instance.ShowError ("No Internet Connection");
        }
    }
    catch (Exception ex)
    {
        UserDialogs.Instance.ShowError(ex.Message, 3);
        Xamarin.Insights.Report (ex);
    }
    IsBusy = false;
}

Lets save some data

The not so pretty way
We have two options for saving data with Parse. We can use the dictionary-initialization syntax or we can subclass from ParseObject. I much prefer to subclass the ParseObject as this allows for type-safety and IntelliSense (which are two of the many reasons I use C#). Below we will save an object to Parse using both approaches.

Dictionary-Initialization

var sampleData = new ParseObject("Planet");
sampleData["name"] = "Earth";
sampleData["distanceFromSun"] = 100;
await sampleData.SaveAsync();

Subclassing ParseObject

// Planet.cs
using Parse;

[ParseClassName("Planet")]
public class Planet : ParseObject
{
    [ParseFieldName("name")]
    public string Name
    {
        get { return GetProperty(); }
        set { SetProperty(value); }
    }

    [ParseFieldName("distanceFromSun")]
    public int DistanceFromSun
    {
        get { return GetProperty(); }
        set { SetProperty(value); }
    }
}

Registering Subclasses objects

You’ll need to call ParseObject.RegisterSubclass() in your apps initialisation before calling ParseClient.Initialize(). If you don’t don’t do this, your app will crash!

ParseObject.RegisterSubclass();

The final initialisation method

public App()
{
    ParseObject.RegisterSubclass();
    ParseClient.Initialize(Helpers.Keys.ParseAppKey,         Helpers.Keys.ParseDotNetKey);

    // The root page of your application
    MainPage = new YourAmazingContentPage();
}

Using our subclasses ParseObject

var planet = new Models.Planet()
{
    Name = "Mars",
    DistanceFromSun = 227900000
};
await planet.SaveAsync();

Conclusion

You can download a sample project from GitHub which demonstrates how to sign up, sign in, save and most importantly, retrieve data.

If you’ve any questions then please feel free to comment or get in touch via Twitter

Uncategorized

Watch out, we support WatchKit!

Screen-Shot-2015-01-17-at-22.25.41-e1421668170621

Xamarin have just announced preview support for Apple Watch and I can’t express how excited I was over the weekend playing with our internal preview build. At this moment time, getting started with Apple Watch can be little confusing, what with the need for 3 different project types to get a hello world sample running! You can see this in the below screenshot of Xamarin Studio. This complexity increases the learning curve so I’ve done my best to try and help.

I’ve created a simple Hello World Apple Watch sample solution which you can download from my GitHub.

One Solution – Three Projects – One Watch App!

Even a basic Apple Watch app requires 1 part App Extension, 1 part Watch App and finally 1 part Unified iOS App. When combined with the correct Bundle Identifiers, you’ve got yourself the beginnings of Apple Watch support. At this moment in time, you’ll need to be editing your storyboard in Xcode rather than Xamarin Studio or Visual Studio. I believe our engineers are hard at work on integrating Apple Watch UI storyboard support in VS and XS much like we have for iPhone and iPad.

Screen-Shot-2015-01-19-at-16.37.23

 Learn more with some awesome documentation!

Xamarin has some excellent documentation on Apple Watch which I highly recommend you thoroughly read.

Uncategorized

Cross-Platform Desktop UIs with C#

xplatDesktop

I’ve spent the last 4 weeks traveling Europe for the Xamarin European roadshow, and have had the opportunity to meet a few thousand C# developers who share a passion for cross-platform development.

In almost every city, I’ve been asked to recommend a Xamarin.Forms style library for developing desktop applications. In this blog post I’m going to give an overview of the different options available to desktop developers who wish to target Windows, Mac and Linux.

Traditional Approach

The first approach is what we’ve named at Xamarin the ‘traditional’ approach. You’ve probably seen this approach, but for mobile. The general idea is that you should implement your user interface uniquely for each platform you wish to target. This means on Mac, you would use Cocoa (Xamarin.Mac), Windows would use WPF and Linux would use Gtk (Gtk#). This approach will guarantee that your desktop application looks and behaves as the platform users expect. It also means that your application looks great if Apple, Microsoft or the OpenSource community decide to update the look and feel of the underlying OS. It’s also worth noting that with this approach you gain 100% access to every UI control and API available in the UI libraries, and won’t be limited in your ability to create beautiful experiences for your users.

In case you’re in any doubt, this is the approach I recommend you take when developing your apps. This is actually the approach Xamarin has started to use for our new products. You can see this in action with our Profiler and Android Simulator; both of these use WPF on Windows, and Xamarin.Mac (Cocoa) on OS X.

XWT

Much like Xamarin.Forms, Xwt allows you to use one API that maps to the native widgets of the platform. This means your application when running on Windows will be using WPF widgets, on Mac its Cocoa, and Linux is Gtk. This results in a 100% native user interface on three platforms from one codebase. Much like Xamarin.Forms, because its aim is to create a unified API for all desktop platforms, it only maps to a subset of widgets and properties. It’s worth noting that with Xwt you still have the ability to implement a native widget which isn’t mapped as part of the API.

For all platforms you can use the native engine, or the Gtk engine. If you’re wondering what a Gtk app looks like on Windows and Mac, then I recommend downloading Xamarin Studio. This is primarily built using Gtk, and in areas actually uses Xwt. On Windows the native engine is WPF, on OS X its Cocoa, and on Linux it remains Gtk (using Gtk#).

Webview

One other option you might want to consider, is using a WebView for your user interface whilst maintaining a C# backend. This is the approach that Rdio has taken for their OS X client, and to a novice it’s difficult to spot that it’s not a native app. This approach can produce some great looking applications which can even run in the Cloud, but it would be difficult to claim you’ve created an application when the reality is you’ve packaged up a website.

QtSharp

Although this approach is not yet ready for consumption, I thought I would mention it as it’s a project on GitHub that excites me. Much like Xamarin.Mac is a binding to the Cocoa framework, a group of enterprising .Net developers are aiming to create a .Net binding to the Qt library. Having used Qt in a previous life, I can confirm that the UIs can often be a little hit or miss (because it’s a lowest common denominator approach). That said, if you’re developing an internal application, or willing to take the time to craft the UI for each platform (different layouts for each platform) then it can work really well.

The project is still in its infancy, and many developers have tried and failed at this approach. Its not ready for production as yet (it doesn’t appear to even be close) but its a great start. My fingers are crossed that the developers continue to invest their time in the project, and the .Net community gains access to one of the most widely used cross-platform user interfaces frameworks in existence.

Uncategorized

Renaming your Xamarin.Mac App

Apple has a number of guidelines and rules for developers looking to publish their Apps to Apple’s app ecosystem. One of these rules relates to the name of your app. To give you a quick overview of how some developers can have issues with theses rules, I’ve gone ahead and listed a few of them below:

  • Apps with names, descriptions, screenshots, or previews that are not relevant to the content and functionality of the App will be rejected.
  • App names in iTunes Connect and as displayed on a device should be similar, so as to not cause confusion
  • Apps that misspell Apple product names in their App name (i.e., GPS for Iphone, iTunz) will be rejected.

If your App has any of the following issues then Apple will reject your binary and ask you to change the app name. In this tutorial, I will show you the properties you need to change your app name.

Menubar & About dialog

To update the name in the Finder menu bar and the About dialog, you will need to update the Bundle Name which can be found in your projects Info.plist (you will need to select the ‘Source’ tab).

xamMacRenameInfo

Dock

To update the name displayed in the Dock (on hovering over the app icon), you will need to change the “Assembly name.” To do this, you will need to navigate to the project options (right click the project and select “Options”). You will find the Assembly name property under the “Output” tab.

xamMacProperties

Installer Package

If you’re producing an installer package for your App, you will need to edit the project name in order for the generated package to have your new name. To do this, simply right click on the project and select “Rename”.