Click here to Skip to main content
12,761,780 members (42,760 online)
Click here to Skip to main content
Add your own
alternative version

Stats

2.2K views
2 bookmarked
Posted 19 Jan 2017

Introducing EasyLayout.Droid For Simpler Xamarin Android Layouts

, 19 Jan 2017 MIT
Rate this:
Please Sign up or sign in to vote.
If you've ever wanted the same type of functionality for Xamarin Android either for consistency or ease of cross platform code sharing, now you can with EasyLayout.Droid.

If you've done much Xamarin iOS work, you've probably run into Frank Krueger's awesome framework, EasyLayout, that makes manually coded auto layouts considerably easier to read and maintain.

If you've ever wanted the same type of functionality for Xamarin Android either for consistency or ease of cross platform code sharing, now you can with EasyLayout.Droid.

What Is EasyLayout?

The original EasyLayout takes Xamarin iOS code like this:

_passwordField.AddConstraint(NSLayoutConstraint.Create(
    _passwordField, NSLayoutAttribute.Top, NSLayoutRelation.Equal,
    _usernameTextField, NSLayoutAttribute.Bottom, 1f, 20f));
_passwordField.AddConstraint(NSLayoutConstraint.Create(
    _passwordField, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal,
    View, NSLayoutAttribute.CenterX, 1f, 0f));

And turns it into this:

View.ConstrainLayout(() =>
    _passwordField.Frame.Top == _usernameTextField.Frame.Bottom + 20 &&
    _passwordField.Frame.GetCenterX() == View.Frame.GetCenterX()
    );

If you're on a team, or storyboards just aren't your thing, it's a lifesaver!

What's Wrong with Android .axml?

Android's axml files are ok, but on large projects, they take a long time to generate, and they make it hard to share layout information cross platform. But if you try to code Android by hand, you quickly discover the same type of verbosity that Xamarin iOS had. Enter EasyLayout.Droid.

Example 1 - Parent Align

If you want to align an image to the edges of the frame, you used to do this:

var layoutParams = new RelativeLayout.LayoutParams(
    ViewGroup.LayoutParams.MatchParent,
    ViewGroup.LayoutParams.MatchParent);
layoutParams.AddRule(LayoutRules.AlignParentTop);
layoutParams.AddRule(LayoutRules.AlignParentBottom);
layoutParams.AddRule(LayoutRules.AlignParentRight);
layoutParams.AddRule(LayoutRules.AlignParentLeft);
_image.LayoutParams = layoutParams;

Now you can do this:

relativeLayout.ConstrainLayout(() =>
    _image.Top == relativeLayout.Top
    && _image.Right == relativeLayout.Right
    && _image.Left == relativeLayout.Left
    && _image.Bottom == relativeLayout.Bottom
    );

There's no need to set LayoutParams at all. If they don't exist, EasyLayout.Droid will add them, if they do, EasyLayout.Droid will append to them. And if you don't add them, it will take care of choosing LayoutParams.MatchParent or WrapContent.

Example 2 - Relative Alignment and Constants

If you wanted to align an image 20 dp under another image and center align it to the parent, you used to do this:

var layoutParams = new RelativeLayout.LayoutParams(
    ViewGroup.LayoutParams.WrapContent,
    ViewGroup.LayoutParams.WrapContent);
layoutParams.AddRule(LayoutRules.CenterHorizontal);
layoutParams.AddRule(LayoutRules.AlignBottom, image1.Id);
layoutParams.TopMargin = DpToPx(20);
_image2.LayoutParams = layoutParams;

There's a couple of gotchas.

  1. If you set the TopMargin to 20, then Android assumes you mean pixels not device independent pixels. To fix that, you need to remember to call a function like DpToPx().
  2. Your relative view (image1) needs to have an Id. If you forget to set it, there's no error, it just does strange layout things.

EasyLayout.Droid replaces the code above with:

relativeLayout.ConstrainLayout(() =>
    _image2.Top == _image1.Bottom + 20
    && _image2.GetCenterX() == relativeLayout.GetCenterX()
    );

That's less code, and it's easier to read, plus there's some other small benefits:

  1. If you forget to add an Id to _image1, EasyLayout.Droid will throw a helpful runtime error.
  2. EasyLayout.Droid always assumes every number is in Dp, so it automatically converts all literals for you.

Incidentally, GetCenterX() is one of a couple of new extension methods along with GetCenterY() and GetCenter().

Example 3 - Constants

Constants weren't difficult to work with previously, but for completeness, they used to work like this:

var layoutParams = new RelativeLayout.LayoutParams(
    DpToPx(50),
    DpToPx(ViewModel.SomeHeight);
_image2.LayoutParams = layoutParams;

With EasyLayout.Droid, you can do this:

relativeLayout.ConstrainLayout(() =>
    _image.Width == 50
    && _image.Height == ViewModel.SomeHeight.ToConst()
    );

As mentioned previously, 50 will be assumed to be in dp and will be auto-converted to pixels. Also arbitrary properties such as SomeHeight will need the .ToConst() extension method applied in order to tell EasyLayout.Droid that they should be treated as constants.

Limitations

Android relative layouts are far from a replacement for iOS's auto layout. To that end, you cannot do the following operations that EasyLayout could:

  • Constraining Heights or Widths to be equal to the Heights or Widths of other elements
  • Using >= or <= signs to indicate GreaterThanOrEqual or LessThanOrEqual type constraints
  • Multiplication of elements (e.g. _image2.Width == _image1.Width * .25f)

Installation

If you want to add this to your project, you can either install via NuGet (safer):

Install-Package EasyLayout.Droid

or if you think it's perfect as-is (you don't want updates), you can copy EasyLayoutDroid.cs into your source. Next using EasyLayout.Droid and you're good to go.

Conclusion

Hope this helps make someone's Xamarin Android day a little better. The code is MIT licensed. If you have any questions, please contact me on twitter.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Lee P Richardson
Web Developer
United States United States
Lee is the author of Siren of Shame, a USB siren currently monitoring continuous integration builds in over 300 companies in 28 countries across the world.

News sites including CodeProject, Visual Studio Magazine, and DevX.com have published nearly two dozen of Lee's technical articles since 2006. He is an avid blogger at leerichardson.com with more than 75 posts over the last decade.

He has worked in software development in the Washington, DC Metropolitan Area for close to 20 years and is currently a senior developer at InfernoRed where he is building cross platform iOS and Android applications for the banking industry.

You may also be interested in...

Pro
Pro

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170217.1 | Last Updated 20 Jan 2017
Article Copyright 2017 by Lee P Richardson
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid