Onionizing Xamarin Part 4

For those who just want code: https://github.com/SuavePirate/Xamarin.Onion 

Don’t forget:

  1. Part 1 on the general project structure: Onionizing Xamarin Part 1
  2. Part 2 on our Domain and Application layers: Onionizing Xamarin Part 2
  3. Part 3 on our Infrastructure layer: Onionizing Xamarin Part 3

A strong and scale-able architecture is important in applications, especially in Mobile Apps. APIs and SDKs are constantly changing, new technology is constantly released, and team sizes are always changing. A solid Onion Architecture can save a development team a lot of time by making it simple to change service implementations, restrict access to certain areas, making logic flow easy to follow, and making testing isolated blocks of code easier.

Some of the important topics this will cover:

  • Separation of Concerns
  • Inversion of Control
  • Dependency Injection
  • Model-View-ViewModel
  • Testability
  • Why all these things are important

Part 4

In this section, we will look at the code for our actual Xamarin.Forms client implementation along with talking about building other Non-Xamarin clients into our solution, and sharing as much code between them as possible. This are our Client layer, and will include setting up our Views, ViewModels, IoC container, and start up process.

Client Layer

First thing is first, let’s build our ViewModels. These ViewModels are going to interface with our Application layer by making calls to our defined Service Interfaces that will be injected into the constructors of our ViewModels.

Some things to note: We are using MVVM Light in this example to make our MVVM and IoC easier to get going. So things such as the ViewModelBase class and the Set() method are coming from that library. You can choose to utilize a different library, or roll your own pretty easily. In either case, the principles are the same.

Let’s first abstract some universal properties into a BasePageViewModel.cs

public class BasePageViewModel : ViewModelBase
{
    private bool _isLoading;
    private bool _isEnabled;
    private string _title;
    private ObservableCollection<string> _errors;

    public bool IsLoading
    {
        get
        {
            return _isLoading;
        }
        set
        {
            Set(() => IsLoading, ref _isLoading, value);
        }
    }
    public bool IsEnabled
    {
        get
        {
            return _isEnabled;
        }
        set
        {
            Set(() => IsEnabled, ref _isEnabled, value);
        }
    }
    public ObservableCollection<string> Errors
    {
        get
        {
            return _errors;
        }
        set
        {
            Set(() => Errors, ref _errors, value);
        }
    }

    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            Set(() => Title, ref _title, value);
        }
    }
    public BasePageViewModel()
    {
        IsEnabled = true;
        IsLoading = false;
    }

    public override void Cleanup()
    {
        base.Cleanup();
        Errors = null;
    }
}

 

From here let’s make a ViewModel for each of our pages (in this example, we will just look at one “MainPage”)

MainPageViewModel.cs

public class MainPageViewModel : BaseViewModel
{
    private readonly IUserService _userService;
    private string _bodyTitle;
    private string _bodyText;
    public string BodyTitle
    {
        get
        {
            return _bodyTitle;
        }
        set
        {
            Set(() => BodyTitle, ref _bodyTitle, value);
        }
    }

    public string BodyText
    {
        get
        {
            return _bodyText;
        }
        set
        {
            Set(() => BodyText, ref _bodyText, value);
        }
    }

    private async void Initialize()
    {
        IsLoading = true;
        await Task.Delay(2000); // simulate load time
        var users = await _userService.GetValidUsers();
        if(users?.Data == null || users.Data.Count() == 0)
        {
            var user = await _userService.CreateUserAsync(new NewUser
            {
                FullName = "Felipe Fancybottom",
                Email = "feffancy@fancybottoms.com"
            });

            BodyText = user.Data.Email;
            BodyTitle = user.Data.FullName;
        }
        else
        {
            BodyText = users.Data.First().Email;
            BodyTitle = users.Data.First().FullName;
        }
        IsLoading = false;
    }

    public MainPageViewModel(IUserService userService)
    {
        _userService = userService;

        Title = "Onion Template";
        BodyTitle = "Loading Name";
        BodyText = "Loading Email";
        Initialize();
    }
}

Notice how we injected the IUserService in the constructor, and use that to lazy load some data into our bindable properties. When we create our view and set the BindingContext to this ViewModel, we will see the UI automatically update when those do. This example does it async right from the constructor, but you can load your data and set up your initial properties any way you’d like.

The next step is to initialize our Inversion of Control, Dependency Injection, and ViewModelLocator to tie all our layers together and allow us to automatically set the BindingContext of our Page.

If it makes sense to you, you can break the IoC set up into a separate project that references all the previous layers. For the sake of simplicity, we are going to do it in the same project as our Xamarin.Forms project.

IoCConfig.cs

public class IoCConfig
{
    public IoCConfig()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    }

    public void RegisterViewModels()
    {
        SimpleIoc.Default.Register<MainViewModel>();
    }

    public void RegisterRepositories()
    {
        SimpleIoc.Default.Register<IUserRepository, UserRepository>(); // this is where you would change the registration to use a different repository
    }

    public void RegisterServices()
    {
        SimpleIoc.Default.Register<IUserService, UserService>();
    }

    public void RegisterProviders()
    {
        SimpleIoc.Default.Register<IUserDataProvider, UserDataProvider>();
        SimpleIoc.Default.Register<ICloudStorageProvider, AzureStorageDataProvider>(); // this is where you would change the registration to use a different provider
    }

    public void RegisterStores()
    {
        SimpleIoc.Default.Register<IUserStore, UserStore>();
        SimpleIoc.Default.Register<IStoreManager, StoreManager>();
    }
}

The purpose of this class is to wire up our dependencies as well as our actual container for the ServiceLocator. This example is using SimpleIoc which is packaged with MVVM Light.

Now that we have our other layers glued together, we just need to create our ViewModelLocator to automatically handle our bindings, then make calls to the IoCConfig when the ViewModelLocator is initialized.

ViewModelLocator.cs

public class ViewModelLocator
{
    public MainPageViewModel MainPage
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainPageViewModel >();
        }
    }
    public ViewModelLocator()
    {
        var iocConfig = new IoCConfig();
        iocConfig.RegisterRepositories();
        iocConfig.RegisterProviders();
        iocConfig.RegisterServices();
        iocConfig.RegisterViewModels();
        iocConfig.RegisterStores();
    }
}

In our constructor, we initialize our IoC, and also provide properties for each of our ViewModels, so that we can bind it easily in our XAML.

The last two steps here are to add a Resource in our App.xaml to our ViewModelLocator, and create our Page.

App.xaml


<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="OnionTemplate.App">
    <Application.Resources>
        <!-- Application resource dictionary -->
        <ResourceDictionary>
                <vm:ViewModelLocator xmlns:vm="clr-namespace:NAMESPACEOF.VIEWMODELLOCATOR;assembly=YOURPACKAGENAME" x:Key="Locator" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

Now that we have our resource, let’s create our page and wire up the BindingContext in our XAML.

MainPage.xaml


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="NAMESPACE.MainPage" BindingContext="{Binding Source={StaticResource Locator}, Path=Main}" Title="{Binding Title}">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical" HorizontalOptions="Center" VerticalOptions="Center">
            <Label Text="{Binding BodyTitle}"/>
            <Label Text="{Binding BodyText}"/>
            <ActivityIndicator IsRunning="True" IsVisible="{Binding IsLoading}"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

There is nothing required to write in our code behind (MainPage.xaml.cs) since it is all automatically wired up.

Last but not least, set our page in our App.xaml.cs:

App.xaml.cs


public partial class App : Xamarin.Forms.Application
{
    public App()
    {
        InitializeComponent();

        MainPage = new NavigationPage(new MainPage());
    }
}

At this point, we should be able to run the application (assuming that the Xamarin.Forms app is started off in each platform the way the template sets it up).

So we have our Xamarin.Forms implementation. But what about other applications that can’t use Xamarin.Forms? Web apps? Xamarin.Mac apps? Cloud apps? WPF?

Here is one of the coolest parts of the entire Onion pattern. We can go ahead and add more projects into our Client layer. These layers can use the same models, interfaces, and in some cases, implementations! For projects where we would need completely different logic, such as a Web App for example, we can implement multiple versions of the Domain and Application layers.

In our web app, we could create another project in the Infrastructure layer (say Infrastructure.WebData) that uses Entity Framework and SQL. Then in our IoCConfig of our Web App, we call to register our Infrastructure.WebData implementations for our Domain.Interfaces.

As long as each project in the Client layer serves the same purpose of configuring Views, and starting up our application with our Inversion of Control, any type of application can live here and follow the same pattern.

The Client layer can also contain abstractions of controls or other utilities that can be referenced by the core Client projects.

What’s Next

In the next segment, we will look at how to integrate our individual mobile platforms, and how to inject custom platform-specific code with some examples using the HockeyApp SDK.

 

Next: Onionizing Xamarin Part 5

Advertisement

Onionizing Xamarin Part 3

For those who just want code: https://github.com/SuavePirate/Xamarin.Onion 

Don’t forget:

  1. Part 1 on the general project structure: Onionizing Xamarin Part 1
  2. Part 2 on our Domain and Application layers: Onionizing Xamarin Part 2

A strong and scale-able architecture is important in applications, especially in Mobile Apps. APIs and SDKs are constantly changing, new technology is constantly released, and team sizes are always changing. A solid Onion Architecture can save a development team a lot of time by making it simple to change service implementations, restrict access to certain areas, making logic flow easy to follow, and making testing isolated blocks of code easier.

Some of the important topics this will cover:

  • Separation of Concerns
  • Inversion of Control
  • Dependency Injection
  • Model-View-ViewModel
  • Testability
  • Why all these things are important

Part 3

In this section, we’ll start to dive into the code for our infrastructure layers (or at least what is important), including our business logic and data logic.

Let’s dive into the data layer.

Infrastructure.Data

This layer is our actual implementation of our Domain definitions, so we are going to implement things such as our Repositories, DataProviders, Stores, or anything else that interacts with our data directly.

From our previous post we defined our IGenericStore + IUserStore and our IGenericRepository + IUserRepository, so now let’s implement them.

GenericStore.cs and UserStore.cs

public class GenericStore<T> : IGenericStore<T>
{
    public List<T> Data { get; set; }
    public GenericStore()
    {
        Data = new List<T>();
    }
}

public class UserStore : GenericStore<User>, IUserStore
{
}

For the sake of just testing data, our store just contains a collection of data, however, this is where you could implement an observable collection, or more complex data types as well.

Now a look at the repositories – Our implementation of our repository is just going to use in-memory storage, but this is a place where you could implement SqlLite, Azure Mobile Tables, or local file storage instead. You could implement all of these easily and just switch out in your UserRepository which one it inherits! That’s one of the biggest bonuses of our Onion Architecture. The github repository demonstrates this well: https://github.com/SuavePirate/Xamarin.Onion/blob/master/src/OnionTemplate/OnionTemplate.Infrastructure.Data/Repositories/UserRepository.cs

GenericMemoryRepository.cs and UserRepository.cs

public class GenericMemoryRepository<T> : IGenericRepository<T>
{
    private readonly IStoreManager _storeManager;
    public GenericMemoryRepository(IStoreManager storeManager)
    {
        _storeManager = storeManager;
    }
    public void Add(T entity)
    {
        _storeManager.Set<T>().Data.Add(entity);
    }

    public void AddRange(IEnumerable<T> entities)
    {
        _storeManager.Set<T>().Data.AddRange(entities);
    }

    public Task CommitAsync()
    {
        return Task.FromResult(false); // we don't need to explicitly save changes
    }

    public Task<T> FindAsync(Func<T, bool> predicate)
    {
        var entity = _storeManager.Set<T>().Data.Where(predicate).FirstOrDefault();
    return Task.FromResult(entity);
    }

    public Task<IEnumerable<T>> GetAsync(Func<T, bool> predicate)
    {
        var entities = _storeManager.Set<T>()?.Data?.Where(predicate);
        return Task.FromResult(entities);
    }

    public void Remove(T entity)
    {
        _storeManager.Set<T>().Data.Remove(entity);
    }

    public void RemoveRange(T entities)
    {

    }
}

public class UserRepository : GenericMemoryRepository<User>, IUserRepository
{
    public UserRepository(IStoreManager manager)
    : base(manager)
    {
    }
}

That’s all we need to define for our data  layer for now. Next let’s look at our business logic layer and how it interacts with the data layer through references to our domain interfaces.

Infrastructure.Business

Our business layer is our implementation of our Application layer. So we are going to implement the IBaseService and IUserService we defined in the previous segment:

IBaseService.cs and IUserService.cs

public class BaseService : IBaseService
{
    public BaseService()
    {
    }

    public IEnumerable<string> Validate(object model)
    {
        if(model == null)
            return new List<string> { "Empty model received" };
        return null;
    }
}

public class UserService : BaseService, IUserService
{
    private readonly IUserRepository _userRepository;
    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }
    public async Task<Result<UserTransferObject>> CreateUserAsync(NewUser model)
    {
        var errors = Validate(model);
        if (errors == null)
        {
            var entity = model.ToUser();
            _userRepository.Add(entity);
            await _userRepository.CommitAsync();

            return new Result<UserTransferObject>(new UserTransferObject(entity));
        }
        return new Result<UserTransferObject>(ResultType.Invalid, errors);
    }

    public async Task<Result<UserTransferObject>> FindByIdAsync(int userId)
    {
        var entity = await _userRepository.FindAsync(user => user.Id == userId);
        if (entity == null)
        {
            return new Result<UserTransferObject>(ResultType.Failed, "Could not find user with this Id");
        }
        return new Result<UserTransferObject>(new UserTransferObject(entity));
    }

    public async Task<Result<UserTransferObject>> RemoveByIdAsync(int userId)
    {
        var entity = await _userRepository.FindAsync(user => user?.Id == userId);
        if (entity == null)
        {
            return new Result<UserTransferObject>(ResultType.Failed, "Could not find user with this Id");
        }
        _userRepository.Remove(entity);
        await _userRepository.CommitAsync();
        return new Result<UserTransferObject>(new UserTransferObject(entity));
    }

    public async Task<Result<IEnumerable<UserTransferObject>>> GetValidUsers()
    {
        var entities = await _userRepository.GetAsync(user =>         !string.IsNullOrEmpty(user?.Email));
        return new Result<IEnumerable<UserTransferObject>>(entities?.Select(entity => new UserTransferObject(entity)));
    }
}

The biggest thing to point out is how the constructor for our UserService takes in an IUserRepository. Later we will set up our IoC container and inject our actual UserService so that the logic ties together. Doing this allows us to avoid referencing the Infrastructure.Data layer in our Infrastructure.Business layer which gives us full Separation of Concerns in our layers.

What’s Next

In the next segment, we’ll talk about implementing our Xamarin.Forms application, setting up our Inversion of Control and Dependency Injection, and tying it all together.

We’ll also look at each of our different platforms and talk about how we can utilize them without using Xamarin.Forms.

Finally, in the last segment, we will talk about how to truly utilize the Onion Architecture to test, pull, and change important pieces of our application without having to touch anything else.

 

Check out Part 4 to look at the Client Layer

Onionizing Xamarin Part 1

For those who just want code: https://github.com/SuavePirate/Xamarin.Onion 

A strong and scale-able architecture is important in applications, especially in Mobile Apps. APIs and SDKs are constantly changing, new technology is constantly released, and team sizes are always changing. A solid Onion Architecture can save a development team a lot of time by making it simple to change service implementations, restrict access to certain areas, making logic flow easy to follow, and making testing isolated blocks of code easier.

Some of the important topics this will cover:

  • Separation of Concerns
  • Inversion of Control
  • Dependency Injection
  • Model-View-ViewModel
  • Testability
  • Why all these things are important

Part 1

This first post will talk about the general project structure and high level role of each layer in the solution. Later posts will touch on the individual projects’ code, why things are where they are, using the structure to build out tests, and ways to bend or change the structure to work for you.

Project Structure

For this example we will be talking about Xamarin.Forms, but the same patterns can be applied in the exact same way without it.
Lets just take a look at the high level structure and layers of the solution:

xamarinonionsolution

Domain

This is the lowest level. Projects within Domain should not reference any projects outside of this layer and should also avoid referencing any external libraries.

Domain.Models

These are our base data models. This project shouldn’t reference any other projects, even within Domain.

Domain.Interfaces

These are the definitions for our data access layer. Repositories, Stores, etc. There should be no implementation in this project and should only reference the Model project.

Application

This layer is what defines our Services and Business logic without implementing any of it. Projects in this layer can only reference Model layers of Domain.

Application.Models

These are our application models such as input models, data transfer objects, as well as any helpers for mapping Domain models to these. This project will only reference the Domain.Models to help map them to DTOs or other models. This, however, is also optional. You could opt to handle mapping externally when the models are needed in business logic rather than in the Application layer.

Application.Interfaces

These are the definitions for our business logic layer. Services, Managers, etc. There should be no implementation in this project and it should only reference the Application.Models project

Infrastructure

This is where we implement our data and business logic.

Infrastructure.Data

This is the implementation of our Data access layer. Communicate with 3rd party data providers, local storage, databases, etc. Domain.Interfaces should be implemented here.

Infrastructure.Business

This is the implementation of our Business logic layer. Communicate with the data layer through contracts from the Domain.Interfaces. This project should NOT reference the Data project. Application.Interfaces should be implemented here

Clients

This is where we implement client logic, set up IoC, create ViewModels, and controls. If we are using Xamarin.Forms, this is where the PCL or Shared Library with Xamarin.Forms is. This Layer can reference any of the above layers in order to wire up IoC. If you have multiple Xamarin.Forms projects in one solution, they can both be here.

Clients.Controls

This is where reusable controls within Xamarin.Forms exist. Pretty straightforward.

Platforms

This is the section where the Native Projects live. If you have too many native projects for things like wearables, or the different TV OS’s, then it might make sense to break this section into smaller sections for things like “Apple”, “Google”, “Windows”, or something similar. But for the sake of this demo, we are only working with one project for each platform, so they live together.

This layer should only reference the Client layer and Binding Layer

Droid

This is the Xamarin.Android project. If any native services need to be called from one of the shared layers, the IoC set up can be extended into this project and one of the interfaces could be implemented here and registered.

iOS

This is the Xamarin.iOS project. As stated above, native services can be set up and injected from here as well.

UWP

This is the UWP project. As stated above, native services can be set up and injected from here as well.

Binding

This is where Xamarin Binding projects should be if there is a need for binding to any native libraries. As with the Platforms layer, if there are many different binding projects, this layer could be split into different sections for each OS. This layer should be exclusive and not reference any other layer.

Tests

This is where UI and Unit tests are. This layer can reference any other level in order to test them. This layer can wire up a completely different IoC container, contain mock projects for simulating any other layer, or any other external reference.

 

Continue on:

Onionizing Xamarin Part 2

Xamarin Component Review: ModernHttpClient

These reviews consist of a Pros/Cons, some things developers might need to be aware of before using or during the use of a given component, and a quick code sample that might help people get started.

Links:
Component https://components.xamarin.com/view/modernhttpclient
Nuget – https://www.nuget.org/packages/modernhttpclient/
Github – https://github.com/paulcbetts/ModernHttpClient

Pros:

  • Increase HTTP request speeds.
    This really does make a noticeable difference from using the base
    HttpWebRequest,HttpClient, or WebClient. By using native libraries, it can skip through the Mono runtime bottleneck.
  • Ease of Use.
    Probably the easiest to use component you’re going to find, especially if you are already using HttpClient for your requests. It’s a simple one line drop on each instantiation of HttpClient.
new HttpClient(new NativeMessageHandler());
  • Lightweight.
    A common issue with components is that they increase the overall size of your app. Bigger apps get uninstalled quicker if they don’t do anything important for the user.

Cons:

  • Component conflict.
    Most people won’t run into this issue, and it is most prevalent on Android (at least it is the only place I’ve run into it). The problem arises because of ModernHttpClient’s use of OkHttp from SquareThe way they include this library is different from some others that are dependent on it. You’ll find components such as Picasso or Rounded Image View that also use OkHttp handle it differently, so that at build time, you’ll get a very deceiving error message.

Things to know:

The only things that I have been made aware of so far in my use of ModernHttpClient are a few out of place errors or bugs I’ve run across. Note that these are only found on Android.
1. The component conflict issue (as stated above): You can see an example from a thread here on this type of issue.
2. Android “crash” while debugging. This is an issue apparent with OkHttp that seems to cause crashes while debugging an Android app, while still maintaining the debugger. It is important to note that this does NOT cause this type of crash if the debugger is not attached. Also, after a crash, upon re-opening the app, the debugger remains attached and usable. Something along the lines of

F/libc( 1044): Fatal signal 5 (SIGTRAP), code -6 in tid 1131 (OkHttp Dispatch)

I haven’t tried the pro version, since the free license does exactly what I need, but if anyone has any insight into the pro license, let me know.

Sample:

...
using ModernHttpClient;
...

public class WebRequestUtils
{
    public async Task<string> GetResponseString(url)
    {
// Instantiate HttpClient with ModernHttpClient handler
using(var client = new HttpClient(new NativeMessageHandler())
        {
            var result = await client.GetAsync(url);
            return await result.Content.ReadAsStringAsync();
        }
    }
}

Make sure to keep an eye out for more component reviews as I get around to playing with more in real life situations.

Creating Google Hangouts Style Images in Xamarin iOS

If you haven’t seen it yet, there is this nifty style of thumbnail, icon, image, etc that Google does in their Hangouts app along with some of their others.

hangouts
Google Hangouts

Notice the second image and the last one where they take images from members of your hangout and lay  them together in an orderly fashion based on the number of people you have.

Here is the logic:

  1. One other person – Show the other user’s image
  2. Two other people – Show both other user’s images diagonally from each other
  3. Three other people – Show the three images in a triangle or pyramid shape
  4. Four or more people – Show 4 images in a square

This logic is straightforward with platforms like Windows and Android where you can create the layouts for each one and switch which one is visible based on the number of members. In this case, however, we are going to explore my favorite way to do it in iOS while still using the standard UITableViewCell.

This means rather than using multiple UIImageViews to display each one, we need to create the image in ONE UIImageView. Here is a simple method I use to do something like this:

  private UIImage GetHangoutImage(HangoutVM hangout, UIView container)
        {
            var members = hangout.Members
                    .Where(im => CurrentUser.FullName != im.Name)
                    .Where(im => !string.IsNullOrEmpty(im.ImageUrl))
                    .Take(4)
                    .ToList();
            if (!string.IsNullOrEmpty(hangout.ImageUrl))
            {
                //if the hangout has an image, use that url
                return Extensions.UIImageFromUrl(hangout.ImageUrl);
            }
            else if (members.Count == 0)
            {
                //if no other members, show self
                return Extensions.GetRoundImage(Extensions.UIImageFromUrl(CurrentUser.ImageUrl));
            }
            else if (members.Count == 1)
            {
                //show the one other member's image
                return Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
            }
            else if (members.Count == 2)
            {
                //if 2 other members, show both their images diagonally
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));
                UIImage image1;
                UIImage image2;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));

                image1.Draw(new RectangleF(22, 0, 22, 22));
                image2.Draw(new RectangleF(0, 22, 22, 22));
                combinedImage = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                return combinedImage;
            }
            else if (members.Count == 3)
            {
                //if 3 other members, show all three images in a triangle
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));

                UIImage image1;
                UIImage image2;
                UIImage image3;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));
                image3 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[2].ImageUrl));
                image1.Draw(new RectangleF(0, 0, 22, 22));
                image2.Draw(new RectangleF(22, 0, 22, 22));
                image3.Draw(new RectangleF(11, 22, 22, 22));
                combinedImage = UIGraphics.GetImageFromCurrentImageContext();

                UIGraphics.EndImageContext();
                return combinedImage;
            }
            else
            {
                //if 4 or more show first 4 in square
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));

                UIImage image1;
                UIImage image2;
                UIImage image3;
                UIImage image4;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));
                image3 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[2].ImageUrl));
                image4 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[3].ImageUrl));

                image1.Draw(new RectangleF(0, 0, 22, 22));
                image2.Draw(new RectangleF(22, 0, 22, 22));
                image3.Draw(new RectangleF(0, 22, 22, 22));
                image4.Draw(new RectangleF(22, 22, 22, 22));

                combinedImage = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                return combinedImage;
            }
        }

In this situation I’m using some hard coded values for the sake of readability. The height of my UITableViewCell is 44 (hence seeing the 22’s everywhere for splitting it in half).

Also, I use a static extensions class to get images from a url and also to create round images. I talked about these in previous blog posts here:

  1. Creating Round Images in Xamarin.iOS
  2. Creating a UIImage from a URL

So now that we have our means of getting the image, we can create it in our GetCell override method in our TableViewSource class we are using to populate our UITableView:

  public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var cellIdentifier = _hangouts[indexPath.Row].ID.ToString();
            var currentHangout = _hangouts[indexPath.Row];

            UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier);

            //// if there are no cells to reuse, create a new one
            if (cell == null)
                cell = new InstanceTableViewCell(currentInstance);
            cell = new UITableViewCell(UITableViewCellStyle.Subtitle, cellIdentifier);
            cell.TextLabel.Text = currentHangout.DisplayName;
            cell.DetailTextLabel.Text = string.Format("{0}{1}", currentHangout.LastMessageMember, currentHangout.LastMessage);
            cell.ImageView.Image = GetHangoutImage(currentHangout, cell.ImageView); // Get the Hangout Style Image
            return cell;
        }

That’s really as far as it goes! Now using that, you’ll get something looking like this:
instancesscreenshotioscropped

The lack of spacing may be misleading, but you’ll notice the first cell has 2 other members, the second has one, the third has 4+, the 4th has 3, etc.

Feel free to comment if you have any questions or want more advice on how to make something like this more appealing!

Xamarin iOS Creating Round Table Cell Images

One more freebie to be referenced in a later post. Here is how I create rounded images to be used in iOS table cells:

 public static UIImage GetRoundImage(UIImage im)
        {
            if (im == null)
                return null;
            UIGraphics.BeginImageContextWithOptions(new SizeF((float)im.Size.Width / 2, (float)im.Size.Height / 2), false, 0);
            UIBezierPath.FromRoundedRect(
                new RectangleF(0, 0, (float)im.Size.Width / 2, (float)im.Size.Height / 2),
                im.Size.Width / 2
            ).AddClip();
            im.Draw(new RectangleF(0, 0, (float)im.Size.Width / 2, (float)im.Size.Height / 2));
            UIImage im1 = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return im1;
        }

Creating a UIImage with a URL in Xamarin iOS

Here is another freebie that I’m going to reference in a later blog post. This is the way I create UIImages from web URLs:

public static UIImage UIImageFromUrl(string uri)
{
    using (var url = new NSUrl(uri))
    using (var data = NSData.FromUrl(url))
        return UIImage.LoadFromData(data);
}