Skip to content
forked from dotnet-ad/GridView

A Xamarin.iOS helper layout view that uses C# operator override.

License

Notifications You must be signed in to change notification settings

t9mike/GridView

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grid layout

A Xamarin grid helper layout that uses C# operator override.

About this Fork

The fork by t9mike adds: TODO

Bugs are likely mine. Please don't blame aloisdeniel. I am so grateful that he published his well thought out and wonderful work. Grids and stacks are so much easier to layout a UI with than iOS constraint-based approach. Thank you aloisdeniel!

I plan to add more samples showing my new features once I am farther along with using GridView for my project.

The auto grid sizing algorithm when there are % sized rows or columns is very crude. The size of the view in the %-based cell is used to define the overall size for the row or column. For example, if a grid spec was:

var time = Make_Box(100, 50, UIColor.Blue); // 100w x 50h
var p = Make_Box(50, 15, UIColor.Yellow);   // 50w x 15h
var m = Make_Box(50, 15, UIColor.Red);      // 50w x 15h

var layout = new Grid.Layout()
   .WithRows(0.5f, 0.5f)
   .WithColumns(-1, -1)
   + time.At(0, 0).RowSpan(2)
   + p.At(0, 1).Vertically(Layout.Alignment.Start)
   + m.At(1, 1).Vertically(Layout.Alignment.End);

This is a grid like:

+----------+-----+
|          |  p  |
|   time   +-----+
|          |  m  |
+----------+-----+

Then we could summize that the grid height should be 50 based on the 100wx50h. And that is achieved because the p and m cells only have 15 high height. But if they were instead each 30 high, the simple grid sizer algorithm in TODO would set the grid height to 60, when it should probably keep it 50.

WPF grid reference code for Grid would be a good start to a new sizing algo. See MeasureOverride().

Getting started

Let's start with a common example with a simple layout that changes while in landscape.

Vertical

Horizontal

var red = new UIView { BackgroundColor = UIColor.Red };
var blue = new UIView { BackgroundColor = UIColor.Blue, Frame = new CGRect(0,0,50,50) };
var cyan = new UIView { BackgroundColor = UIColor.Cyan };
var yellow = new UIView { BackgroundColor = UIColor.Yellow };

var portrait = new Grid.Layout() 
                     { 
                        Spacing = 10, 
                        Padding = new Grid.Insets(10) 
                     }
                     .WithRows(0.75f, 0.25f, 200f)
                     .WithColumns(0.75f, 0.25f)
                     + red.At(0, 0).Span(2, 1) 
                       + blue.At(2, 0).Span(1, 2) 
                     + cyan.At(0, 1) 
                     + yellow.At(1,1);

var landscape = new Grid.Layout() 
                     { 
                         Spacing = 20, 
                        Padding = new Grid.Insets(20), 
                     }
                     .WithRows(1.00f)
                     .WithColumns(0.50f, 0.25f, 0.25f)
                     + red.At(0, 0)
                     + blue.At(0, 1)
                           .Vertically(Grid.Layout.Alignment.End)
                           .Horizontally(Grid.Layout.Alignment.Center)
                     + cyan.At(0, 2);

var grid = new Grid();

grid.AddLayout(portrait);
grid.AddLayout(landscape, (g) => (g.Frame.Width > g.Frame.Height));

this.View = grid;

Usage

The getting started example should be self-explanatory but find here a more in-depth presentation.

Grid

A grid is the root UIView that displays its subviews thanks to its current layout. Each of its layout has a Trigger property : the grid will choose the first declared layout that match when update.

By default, the layout update is triggered when the grid size change, but you can force a new layout (for example if your triggers depends on other factors) by calling UpdateLayout().

Layout

A layout contains row and column definitions (number, size), but also the position of each subview (Cell).

Padding

A global padding space inside your grid could be defined.

Example:

// left, top, right, bottom
layout.Padding = new Grid.Insets(10,20,10,5);

Spacing

The spacing property defines the spacing between each row or column.

Example:

layout.Spacing = 10;

Column and row definitions

To define the columns and rows, use the WithRows/WithColumns(params float[] rows) method. Each entry adds a row/column with the value as size.

If size > 1, the value is considered as an absolute size.

If size <= 1, the value will use the amount of the remaining space (after removing other absolute row/column sizes and spacings).

Example:

layout.WithRows(0.5f,100.0f,0.25f,0.25f);

Creating cells

For adding cells, extension methods are available for UIView.

At(int row, int column)

Must be the first declaration and indicates the top-left position of the cell.

Span(int rows, int columns)

Indicates the size of the cell (default : (1,1)).

Vertically(Grid.Layout.Alignment alignment)

Indicates the vertical position of the view in the cell (default : Stretched).

Horizontally(Grid.Layout.Alignment alignment)

Indicates the horizontal position of the view in the cell (default : Stretched).

Example:

var cell = subview.At(0, 1)
       .Span(1,2)
       .Vertically(Grid.Layout.Alignment.End)
       .Horizontally(Grid.Layout.Alignment.Center)

Adding cells to the layout

The easiest and recommanded way is to use the + operator override onto your layout to append new cells.

Example:

layout = layout + cell1 + cell2;

Adding default layout

To add your layout to your grid, use the Grid.AddLayout(Grid.Layout layout) method.

Example:

grid.AddLayout(layout)

Adding triggered layouts

The current selected layout of your grid can dynamically changed if you have more than one layout. In this case, you have to associate triggers to each other layout, to allow the view to be able to choose the right layout at a given time.

To achieve this, add the other layouts with the Grid.AddLayout(Grid.Layout layout, Func<Grid,bool> trigger) method.

Example:

grid.AddLayout(layout2, (grid) => grid.Frame.Width > grid.Frame.Height);

Q&A

What if I want different spacing between rows/columns ?

Simply use a spacing of 0 and add empty rows/columns with a fixed size.

About

This layout system is vastly inspired by Windows (WPF, WinRT) and Xamarin.Forms Grid components.

You might be wondering why I'm doing this while there's already existing layout mecanisms :

  • IMO UIStackView, contraints, autoresizing masks are too verbose for creating common layouts from code, in particular with purely dynamic layouts. I'm not a real fan of Storyboard constraints too to be honest. Just wonder of the number of lines of code/storyboard declarations needed to implement the simple getting started example that takes just a few lines of code ...
  • I also wanted to have fluent apis and to take advantage of C# operator override to have concise layout declarations.
  • Having a simple unified layout API on all platforms is also a motivation.

Roadmap

  • - [ ] Android Implementation
  • Optimize and benchmarking

Contributions

Contributions are welcome! If you find a bug please report it and if you want a feature please report it.

If you want to contribute code please file an issue and create a branch off of the current dev branch and file a pull request.

License

MIT © Aloïs Deniel

About

A Xamarin.iOS helper layout view that uses C# operator override.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 100.0%