When creating iOS apps, developers typically turn to the languages and IDE provided by Apple: Objective-C / Swift and Xcode. However, this isn’t the only option—you can create iOS apps using a variety of languages and frameworks.
One of the most popular options is Xamarin, a cross-platform framework that allows you to develop iOS, Android, OS X and Windows apps using C# and Visual Studio. The major benefit here is Xamarin can allow you to share code between your iOS and Android app.
Xamarin has a big advantage over other cross-platform frameworks: with Xamarin, your project compiles to native code, and can use native APIs under the hood. This means a well written Xamarin app should be indistinguishable from an app made with Xcode. For more details, check out this great Xamarin vs. Native App Development article.
Xamarin had a big disadvantage too in the past too: its price. Because of the steep licensing cost of $1,000 per platform per year, you’d have to give up your daily latte or frappuccino to even think about affording it … and programming without coffee can get dangerous. Because of this steep price, until recently Xamarin appealed mostly to enterprise projects with big budgets.
However, this recently changed when Microsoft purchased Xamarin and announced that it would be included in all new versions of Visual Studio, including the free Community Edition that’s available to individual developers and small organizations.
Free? Now that’s a price to celebrate!
Besides cost (or lack thereof), Xamarin’s other virtues include allowing programmers to:
- Leverage existing C# libraries and tools to create mobile apps.
- Reuse code between apps on different platforms.
- Share code between ASP.Net backends and customer-facing apps.
Xamarin also offers a choice of tools, depending on your needs. To maximize cross-platform code reuse, use Xamarin Forms. This works especially well for apps that don’t need platform-specific functionality or a particularly custom interface.
If your app does require platform-specific features or designs, use Xamarin.iOS, Xamarin.Android and other platform-specific modules to get direct interaction with native APIs and frameworks. These modules provide the flexibility to create very custom user interfaces, yet still allow sharing of common code across platforms.
In this tutorial, you’ll use Xamarin.iOS to create an iPhone app that displays a user’s photo library.
This tutorial doesn’t require any prior iOS or Xamarin development experience, but to get the most from it you’ll need a basic understanding of C#.
Getting Started
To develop an iOS app with Xamarin and Visual Studio, you’ll ideally need two machines:
- A Windows machine to run Visual Studio and write your project’s code.
- A Mac machine with Xcode installed to act as a build host. This doesn’t have to be a dedicated computer for building, but it must be network accessible during development and testing from your Windows computer.
It greatly helps if your machines are physically near each other, since when you build and run on Windows, the iOS Simulator will load on your Mac.
I can hear some of you saying, “What if I don’t have both machines?!”
-
For Mac-only users, Xamarin does provide an IDE for OS X, but in this tutorial we will be focusing on the shiny new Visual Studio support. So if you’d like to follow along, you can run Windows as a virtual machine on your Mac. Tools such as VMWare Fusion or the free, open-source VirtualBox make this an effective way to use a single computer.
If using Windows as a virtual machine, you’ll need to ensure that Windows has network access to your Mac. In general, if you can
ping
your Mac’s IP address from inside Windows, you should be good to go. - For Windows-only users, go buy a Mac right now. I’ll wait! :] If that’s not an option, hosted services such as MacinCloud or Macminicolo provide remote Mac access for building.
This tutorial assumes you’re using separate Mac and Windows computers, but don’t worry—the instructions are basically the same if you’re using Windows inside a virtual machine on your Mac.
Installing Xcode and Xamarin
If you don’t have it already, download and install Xcode on your Mac. This is just like installing any other app from the App Store, but since it’s several gigabytes of data, it may take a while.
After Xcode is installed, download Xamarin Studio onto your Mac. You’ll need to provide your email, but the download is otherwise free. Optional: do a happy dance for all the coffees you can still afford.
Once the download is complete, open the installer package and double click Install Xamarin.app. Accept the terms and conditions and continue.
The installer will search for already-installed tools and check for current platform versions. It will then show you a list of development environments. Make sure Xamarin.iOS is checked, then click Continue.
Next you’ll see a confirmation list summarizing the items to be installed. Click Continue to proceed. You will be given a summary and an option to launch Xamarin Studio. Instead, click Quit to complete the installation.
Installing Visual Studio and Xamarin
For this tutorial you can use any version of Visual Studio, including the free Community Edition. Some features are absent in the Community Edition, but nothing that will prevent you from developing complex apps.
Your Windows computer should meet the Visual Studio minimum system requirements. For a smooth development experience, you’ll want at least 3 GB of RAM.
If you don’t already have Visual Studio installed, download the Community Edition installer by clicking the green Download Community 2015 button on the Community Edition web site.
Run the installer to begin the installation process, and choose the Custom installation option. In the features list, expand Cross Platform Mobile Development, and select C#/.NET (Xamarin v4.0.3) (where v4.0.3 is the current version when this tutorial was written, but will likely be different in the future).
Click Next and wait for the installation to complete. This will likely take a while; go take a walk to burn off all the cookies you ate while installing Xcode. :]
If you already have Visual Studio installed but don’t have the Xamarin tools, go to Programs and Features on your Windows computer and find Visual Studio 2015. Select it, click Change to access its setup, then select Modify.
You’ll find Xamarin under Cross Platform Mobile Development as C#/.NET (Xamarin v4.0.3). Select it and click Update to install.
Whew—that’s a lot of installations, but now you’ve got everything you need!
Creating the App
Open Visual Studio and select File\New\Project. Under Visual C# expand iOS, select iPhone and pick the Single View App template. This template creates an app with a single view controller, which is simply a class that manages a view in an iOS app.
For both the Name and the Solution Name, enter ImageLocation. Choose a location on your computer for your app and click OK to create the project.
Visual Studio will prompt you to prepare your Mac to be the Xamarin build host:
- On the Mac, open System Preferences and select Sharing.
- Turn on Remote Login.
- Change Allow access to Only these users and add a user that has access to Xamarin and Xcode on the Mac.
- Dismiss the instructions and return to your Windows computer.
Back in Visual Studio, you will be asked to select the Mac as the build host. Select your Mac and click Connect. Enter the username and password, then click Login.
You can verify you’re connected by checking the toolbar.
Select iPhone Simulator from the Solution Platform dropdown—this will automatically pick a simulator from the build host. You can also change the device simulator by clicking the small arrow next to the current simulator device.
Build and run by pressing the green Debug arrow or the shortcut key F5.
Your app will compile and execute, but you won’t see it running on Windows. Instead, you’ll see it on your Mac build host. This is why it helps to have your two machines nearby :]
At the recent Evolve conference, Xamarin announced iOS Simulator Remoting that will soon allow you to interact with apps running in Apple’s iOS Simulator as though the simulator were running on your Windows PC. For now, however, you’ll need to interact with the simulator on your Mac.
You should see a splash screen appear on the simulator and then an empty view. Congratulations! Your Xamarin setup is working.
Stop the app by pressing the red stop button (shortcut Shift + F5).
Creating the Collection View
The app will display thumbnails of the user’s photos in a Collection View, which is an iOS control for displaying several items in a grid.
To edit the app’s storyboard, which contains the “scenes” for the app, open Main.storyboard from the Solution Explorer.
Open the Toolbox and type collection into the text box to filter the list of items. Under the Data Views section, drag the Collection View object from the toolbox into the middle of the empty view.
Select the collection view; you should see hollow circles on each side of the view. If instead you see T shapes on each side, click it again to switch to the circles.
Click and drag each circle to the edge of the view until blue lines appear. The edge should snap to this location when you release the mouse button.
Now you’ll set up Auto Layout Constraints for the collection view; these tell the app how the view should be resized when the device rotates. In the toolbar at the top of the storyboard, click on the green plus sign next to the CONSTRAINTS label. This will automatically add constraints for the collection view.
The generated constraints are almost correct, but you’ll need to modify some of them. On the Properties window, switch to the Layout tab and scroll down to the Constraints section.
The two constraints defined from the edges are correct, but the height and width constraints are not. Delete the Width and Height constraints by clicking the X next to each.
Notice how the collection view changes to an orange tint. This is an indicator that the constraints need to be fixed.
Click on the collection view to select it. If you see the circles as before, click again to change the icons to green T shapes. Click and drag the T on the top edge of the collection view up to the green rectangle named Top Layout Guide. Release to create a constraint relative to the top of the view.
Lastly, click and drag the T on the left side of the collection view to the left until you see a blue dotted line. Release to create a constraint relative to the left edge of the view.
At this point, your constraints should look like this:
Configuring the Collection View Cell
You may have noticed the outlined square inside the collection view, inside of which is a red circle containing an exclamation point. This is a collection view cell, which represents a single item in the collection view.
To configure this cell’s size, which is done on the collection view, select the collection view and scroll to the top of the Layout tab. Under Cell Size, set the Width and Height to 100.
Next, click the red circle on the collection view cell. A pop-up will inform you that you haven’t set a reuse identifier for the cell, so select the cell and go to the Widget tab. Scroll down to the Collection Reusable View section and enter ImageCellIdentifier for the Identifier. The error indicator should vanish.
Continue scrolling down to the Interaction Section. Set the Background Color by selecting Predefined and blue.
The scene should look like the following:
Scroll to the top of the Widget section and set the Class as PhotoCollectionImageCell.
Visual Studio will automatically create a class with this name, inheriting from UICollectionViewCell
, and create PhotoCollectionImageCell.cs
for you. Sweet, I wish Xcode did that! :]
Creating the Collection View Data Source
You’ll need to manually create a class to act as the UICollectionViewDataSource
, which will provide data for the collection view.
Right-click on ImageLocation in the Solution Explorer. Select Add \ Class, name the class PhotoCollectionDataSource.cs and click Add.
Open the newly added PhotoCollectionDataSource.cs
and add the following at the top of the file:
using UIKit; |
This gives you access to the iOS UIKit
framework.
Change the definition of the class to the following:
public class PhotoCollectionDataSource : UICollectionViewDataSource { } |
Remember the reuse identifier you defined on the collection view cell earlier? You’ll use that in this class. Add the following right inside the class definition:
private static readonly string photoCellIdentifier = "ImageCellIdentifier"; |
The UICollectionViewDataSource
class contains two abstract members you must implement. Add the following right inside the class:
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) { var imageCell = collectionView.DequeueReusableCell(photoCellIdentifier, indexPath) as PhotoCollectionImageCell; return imageCell; } public override nint GetItemsCount(UICollectionView collectionView, nint section) { return 7; } |
GetCell()
is responsible for providing a cell to be displayed within the collection view.
DequeueReusableCell
reuses any cells that are no longer needed, for example if they’re offscreen, which you then simply return. If no reusable cell is available, a new one is created automatically.
GetItemsCount
tells the collection view to display seven items.
Next you’ll add a reference to the collection view to the ViewController
class, which is the view controller that manages the scene containing the collection view. Switch back to Main.storyboard, select the collection view, then select the Widget tab. Enter collectionView for the Name.
Visual Studio will automatically create an instance variable with this name on the ViewController
class.
collectionView
instance variable automatically generated by Visual Studio.Open ViewController.cs from the Solution Explorer and add the following field right inside the class:
private PhotoCollectionDataSource photoDataSource; |
At the end of ViewDidLoad()
, add these lines to instantiate the data source and connect it to the collection view.
photoDataSource = new PhotoCollectionDataSource(); collectionView.DataSource = photoDataSource; |
This way the photoDataSource
will provide the data for the collection view.
Build and run. You should see the collection view with seven blue squares.
Nice – the app is really coming along!
Showing Photos
While blue squares are cool, you’ll next update the data source to actually retrieve photos from the device and display them on the collection view. You’ll use the Photos
framework to access photo and video assets managed by the Photos app.
To start, you’ll add a view to display an image on the collection view cell. Open Main.storyboard again and select the collection view cell. On the Widget tab, scroll down and change the Background color back to the default.
Open the Toolbox, search for Image View, then drag an Image View onto the collection view Cell.
The image view will initially be much larger than the cell; to resize it, select the image view and go to the Properties \ Layout tab. Under the View section, set both the X and Y values to 0 and the Width and Height values to 100.
Switch to the Widget tab for the image view and set the Name as cellImageView. Visual Studio will automatically create a field named cellImageView
for you.
Scroll to the View section and change the Mode to Aspect Fill. This keeps the images from becoming stretched.
partial
, which indicates that the field is in another file.
In the Solution Explorer, select the arrow to the left of PhotoCollectionImageCell.cs
to expand the files. Open PhotoCollectionImageCell.designer.cs
to see cellImageView
declared there.
This file is automatically generated; do not not make any changes to it. If you do, they may be overwritten without warning or break links between the class and storyboard, resulting in runtime errors.
Since this field isn’t public, other classes cannot access it. Instead, you’ll need to provide a method to be able to set the image.
Open PhotoCollectionImageCell.cs
and add the following method to the class:
public void SetImage(UIImage image) { cellImageView.Image = image; } |
Now you’ll update PhotoCollectionDataSource
to actually retrieve photos.
Add the following at the top of PhotoCollectionDataSource.cs:
using Photos; |
Add the following fields to the PhotoCollectionDataSource
:
private PHFetchResult imageFetchResult; private PHImageManager imageManager; |
The imageFetchResult
field will hold an ordered list of photo entity objects, and you’ll get this photos list from the imageManager
.
Right above GetCell()
, add the following constructor:
public PhotoCollectionDataSource() { imageFetchResult = PHAsset.FetchAssets(PHAssetMediaType.Image, null); imageManager = new PHImageManager(); } |
This constructor gets a list of all image assets in the Photos app and stores the result in the imageFetchResult
field. It then sets the imageManager
, which the app will query for more information about each image.
Dispose of the imageManager
object when the class finishes by adding this destructor below the constructor.
~PhotoCollectionDataSource() { imageManager.Dispose(); } |
To make the GetItemsCount
and GetCell
methods use these resources and return images instead of empty cells, change GetItemsCount()
to the following:
public override nint GetItemsCount(UICollectionView collectionView, nint section) { return imageFetchResult.Count; } |
Then replace GetCell
with the following:
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) { var imageCell = collectionView.DequeueReusableCell(photoCellIdentifier, indexPath) as PhotoCollectionImageCell; // 1 var imageAsset = imageFetchResult[indexPath.Item] as PHAsset; // 2 imageManager.RequestImageForAsset(imageAsset, new CoreGraphics.CGSize(100.0, 100.0), PHImageContentMode.AspectFill, new PHImageRequestOptions(), // 3 (UIImage image, NSDictionary info) => { // 4 imageCell.SetImage(image); }); return imageCell; } |
Here’s a breakdown of the changes above:
- The
indexPath
contains a reference to which item in the collection view to return. TheItem
property is a simple index. Here you get the asset at this index and cast it to aPHAsset
. - You use
imageManager
to request the image for the asset with a desired size and content mode. - Many iOS framework methods use deferred execution for requests that can take time to complete, such as
RequestImageForAsset
, and take a delegate to be called upon completion. When the request completes, the delegate will be called with the image and information about it. - Lastly, the image is set on the cell.
Build and run. You’ll see a prompt requesting permission access.
If you select OK, however, the app … doesn’t do anything. So disappointing!
iOS considers access to users’ photos to be sensitive information, and prompts the user for permission. However, the app must also register to be notified when the user has granted this permission, so it can reload its views. You’ll do this next.
Registering for Photo Permission Changes
First, you’ll add a method to the PhotoCollectionDataSource
class to inform it to re-query for photo changes. Add the following to the end of the class:
public void ReloadPhotos() { imageFetchResult = PHAsset.FetchAssets(PHAssetMediaType.Image, null); } |
Next, open ViewController.cs and add the following framework to the top of the file:
using Photos; |
Then add this code to the end of ViewDidLoad()
:
// 1 PHPhotoLibrary.SharedPhotoLibrary.RegisterChangeObserver((changeObserver) => { //2 InvokeOnMainThread(() => { // 3 photoDataSource.ReloadPhotos(); collectionView.ReloadData(); }); }); |
Here’s what this does:
- The app registers a delegate on the shared photo library to be called whenever the photo library changes.
InvokeOnMainThread()
ensures that UI changes are always processed on the main thread; otherwise a crash may result.- You call
photoDataSource.ReloadPhotos()
to reload the photos andcollectionView.ReloadData()
to tell the collection view to redraw.
Finally, you’ll handle the initial case, in which the app has not yet been given access to photos, and request permission.
In ViewDidLoad()
, add the following code right before setting photoDataSource
:
if (PHPhotoLibrary.AuthorizationStatus == PHAuthorizationStatus.NotDetermined) { PHPhotoLibrary.RequestAuthorization((PHAuthorizationStatus newStatus) => { }); } |
This checks the current authorization status, and if it’s NotDetermined
, explicitly requests permission to access photos.
In order to trigger the photos permission prompt again, reset the iPhone simulator by going to Simulator \ Reset Content and Settings.
Build and run the app. You’ll be prompted for photo permission, and after you press Ok the app will show the collection view with thumbnails for all the device’s photos!
Where to Go From Here?
You can download the completed Visual Studio project from here.
In this tutorial, you learned a bit about how Xamarin works and how to use it to create iOS apps.
The Xamarin Guides Site provides several good resources to learn more about the Xamarin platform. To better understand building cross-platforms apps, view the Xamarin tutorials on building the same app for iOS and Android.
Microsoft’s purchase of Xamarin introduced many exciting changes. The announcements at Microsoft’s Build conference and Xamarin Evolve can give you guidance on Xamarin’s new direction. Xamarin also released videos of the sessions from the recent Evolve Conference that provide more information on working with Xamarin and the future direction of the product.
Do you think you’ll try Xamarin when building apps? If you have any questions or comments about this tutorial, please feel free to post in the comments section below.
The post Building iOS Apps with Xamarin and Visual Studio appeared first on Ray Wenderlich.