Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using a Static UITableView as a Layout Device: Take Two

DZone's Guide to

Using a Static UITableView as a Layout Device: Take Two

If you're creating an app that automatically responds to device orientation and size, UITableView might be your best bet. Here's an example to show you why.

· Mobile Zone
Free Resource

While layout constraints and the new UIStackView class have made it much easier to create applications that automatically respond to device size and orientation changes, another option for implementing autolayout sometimes gets overlooked: UITableView. Since iOS 8, table views have supported “self-sizing” cells, allowing developers to create complex table-based user interfaces without needing to compute cell heights manually. As table views often make up a large part of an iOS application's user interface, taking advantage of self-sizing cells can significantly reduce overall development time. Additionally, this capabilitity extends to custom cells – as long as the cell defines constraints that unambiguously define the position of each subview, the cell's contents will be automatically laid out as needed by the table view. No manual size calculation or layout code is required.

A good example of using self-sizing table view cells can be found here:

http://www.oliverfoggin.com/using-a-static-uitableview-as-a-layout-device/

This example, written by Oliver Foggin, uses two table views. The first table view presents a list of animals to the user. Tapping a row in this view presents the second table view, which displays detailed information about the selected animal, including name, Latin name, image, and description, as well an author's name and image.

The detail view uses self-sizing static table view cells along with layout constraints to automatically arrange its contents. The structure of the detail view is defined in a storyboard. I was inspired to try to replicate this layout using MarkupKit. The final results are shown below:

(after scrolling)

The markup used to create the layout (defined in a file I named AnimalDetailTableView.xml) is as follows:

<?xml version="1.0" encoding="UTF-8"?>

<LMTableView separator backgroundColor="#ffffff" estimatedSectionHeaderHeight="0" estimatedSectionFooterHeight="0">
    <!-- Name and Latin name -->
    <LMTableViewCell>
        <LMColumnView>
            <UILabel id="titleLabel" font="headline"/>
            <UILabel id="dateLabel" font="footnote"/>
        </LMColumnView>
    </LMTableViewCell>

    <!-- Photo -->
    <LMTableViewCell>
        <UIImageView id="articleImageView" height="200" contentMode="scaleAspectFit"/>
    </LMTableViewCell>

    <!-- Text -->
    <LMTableViewCell>
        <UILabel id="articleTextView" numberOfLines="0"/>
    </LMTableViewCell>

    <!-- Author details -->
    <LMTableViewCell>
        <LMColumnView>
            <LMRowView layoutMarginTop="10" layoutMarginLeft="40" layoutMarginBottom="15" layoutMarginRight="40">
                <UIView height="2" backgroundColor="#666666"/>
            </LMRowView>

            <UIImageView id="authorImageView" height="92" contentMode="scaleAspectFit"/>
            <UILabel id="authorNameLabel" font="footnote" textAlignment="center"/>
        </LMColumnView>
    </LMTableViewCell>
</LMTableView>

LMTableView is a subclass of UITableView that acts as its own data source and delegate, serving cells from a statically-defined collection of table view sections.LMTableViewCell is a subclass of UITableViewCell that provides a vehicle for custom cell content. It automatically applies constraints to its content to enable self-sizing behavior.

LMRowView and LMColumnView are layout views that arrange their subviews in a horizontal or vertical line, respectively. They are similar to UIStackView but have some unique properties, such as the ability to distribute subviews by weight as well as specify a background color. They also work in iOS 8. See this article for more information.

The first cell uses a column view to arrange the name and Latin name labels in a vertical line within the cell. The “id” attribute defines outlets for the labels, using the same outlet names that were used in the original storyboard (“titleLabel” and “dateLabel”). As in the original, the labels use the “headline” and “footnote” dynamic text styles:

<!-- Name and Latin name -->
<LMTableViewCell>
    <LMColumnView>
        <UILabel id="titleLabel" font="headline"/>
        <UILabel id="dateLabel" font="footnote"/>
    </LMColumnView>
</LMTableViewCell>

The second cell contains an image view named “articleImageView” that displays a picture of the animal. As in the original storyboard, the height of the image view is constrained to 200 pixels. Similarly, the third cell contains a label named “articleTextView” that displays a description of the animal:

<!-- Photo -->
<LMTableViewCell>
    <UIImageView id="articleImageView" height="200" contentMode="scaleAspectFit"/>
</LMTableViewCell>

<!-- Text -->
<LMTableViewCell>
    <UILabel id="articleTextView" numberOfLines="0"/>
</LMTableViewCell>

The last cell contains a column view that displays the author's name and picture. The picture's height is constrained to 92 pixels, and the name label uses the “footnote” style, as in the original. The column view also contains an empty UIView that is used to create the 2-pixel wide separator found in the original version. A row view is used to establish the margins around the separator view:

<!-- Author details -->
<LMTableViewCell>
    <LMColumnView>
        <LMRowView layoutMarginTop="10" layoutMarginLeft="40" layoutMarginBottom="15" layoutMarginRight="40">
            <UIView height="2" backgroundColor="#666666"/>
        </LMRowView>

        <UIImageView id="authorImageView" height="92" contentMode="scaleAspectFit"/>
        <UILabel id="authorNameLabel" font="footnote" textAlignment="center"/>
    </LMColumnView>
</LMTableViewCell>

Adding the following method to the AnimalDetailTableViewController class to load the view from markup was all I needed to replace the storyboard-based layout with the MarkupKit version:

- (void)loadView
{
    self.view = [LMViewBuilder viewWithName:@"AnimalDetailTableView" owner:self root:nil];
}

No other changes were required! In fact, the tableView:heightForRowAtIndexPath:method of AnimalDetailTableViewController and the detail view scene in the storyboard can actually be removed, since they are not needed by the markup version. Also, although this implementation used markup to define the table view's structure, the same result could have been achieved programmatically. Although markup is often more convenient, all of MarkupKit’s view classes can be used in code as well.

For more information about MarkupKit, including additional table view examples, see the project wiki.

Topics:
mobile ,markupit

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}