So the project I’m working on now requires text entry. Not a single line of text, for which a UITextField would be well suited, but one or perhaps multiple lines. I’ve been trying to achieve an effect similar to that of the “notes” field in the Apple Contacts app, or the “reminders” field in the Apple Reminders app. These are essentially UITableViewCells that contain a UITextView to allow for text input, and they grow (or shrink) dynamically as the user inputs text.

Dynamic sizing for text entry from Apple's Reminders app.

Another example of self-sizing text entry from Apple's Contacts app.

Sounds simple enough, right? Ha!

It makes me think of a quote I just read from Bertrand Russell, a famous mathematician who suffered permanent burnout from the experience of writing his hallmark Principia Mathematica:

In the end, the work was finished but my intellect never quite recovered from the strain. I have been ever since definitely less capable of dealing with difficult abstractions than I was before. This is part, though no means the whole, of the reason for the change in the nature of my work.

Oh, I’m being melodramatic. It’s not like this was iCloud with Core Data or anything. On to the pork n’ beans!

I’m using iOS 6 with Autolayout and Storyboards for this example. I think half the problem is the learning curve of new technologies, but I’m a firm believer in just adopting everything new as early as possible and just moving forward.

Creating a Self-Sizing TextView and Cell in a Static, Grouped TableView

My specific needs called for a static, grouped UITableView, a la Contacts. This approach is slightly easier because when you create a static tableview using IB and a storyboard, it’s like designing any other view inside a view controller. There’s no need to subclass tableviewcells, you can wire up all your control objects right on the screen in front of you, all your outlets are available when the view loads.

In part 2 of this post, I’ll show you how to achieve the same effect using dynamic table view cells.

I think a lot of times with text entry users want to rotate the device and Auto Layout makes this easier. This approach supports portrait and landscape orientations.

Getting Started

You’ll want to add a Table View Controller object to your storyboard. In the Attributes inspector for the Table View set the Content to Static Cells and the Style to Grouped.

Subclass a new Table View Controller to manage this table view. Because it’s static table view, you can clean out all the stubbed and commented datasource and delegate methods. It doesn’t generally use these (some can cause problems as it can conflict with information it’s getting from your storyboard), but we will need to implement some methods as you’ll see later. Be sure to set the View Controller on your storyboard to be an instance of your subclassed Table View Controller (via the Identity inspector’s Custom Class).

Using Auto Layout

Our strategy here is that Auto Layout will handle some of the resizing for us, using constraints, and we’ll handle the rest in code. Specifically, Auto Layout is going to handle resizing the UITextView. Auto Layout is going to keep it pinned to four sides of the table view cell.

When working with Auto Layout, remember this two-part rule: for each view you place, you must have constraints in place to determine the view’s position and its size. And not more constraints than are necessary.

These i-beams keep the label pinned to the top and left of the tableview cell.

First drag a UILabel out to your static table view cell. As a static label describing your text, you want it to have a fixed location. As you place it, by default it grabs on to the edges of it’s superview. The I-beams you see are like glue. They will pin, or stick, your label to the top and left a fixed number of points. These two constraints describe the label’s position (per our rule above).

A UILabel, being dragged out of the object library like this, won’t contain any constraints regarding it’s size, its width and height. A UILabel has an intrinsic content size, which is essentially the size of the contents it contains. However, make any changes to the label, for instance, change the text “Label” to “notes:” and suddenly Xcode throws new size constraints in there. To remove the newly added size constraints and go back to the intrinsic size, select the label and choose Editor – > Size to Fit Content.

I mention this because Xcode is VERY touchy about constraints. The slightest movement of views can add or remove constraints. Suddenly you have eight constraints in a small UITableViewCell and it can be hard to tell what’s what. Not to mention that they can conflict with each other and cause crashes.

Here are a couple of pointers when trying to wrangle constraints:

  • In the scene outline view, blue constraints can be deleted, purple ones cannot
  • Xcode adds purple ones to fulfill basic requirements of either size and/or position
  • If you want to delete a purple one because you feel it’s not what you want, you need to add a new constraint to replace it first. To do this, think size, then think position.
  • When trying to think in terms of constraints (versus point-based layout), ask yourself, “What if?” as in “What if the device rotated to landscape, how would I want this button or label to react? Would I want it to grow, stick to the sides?
  • Look closely at the constraints in outline view as you add objects and add constraints to see what Xcode is adding/removing/replacing. This is a great way to learn what’s going on.

Now we need to add a UITextView. Drag it out to your cell and position it to the right of your label. Xcode is going to put a bunch of constraints in there. We want very specific behavior here, so we need to go in and override everything once we’ve placed the text view in the cell.

Let’s think about what we want: for position, we want it to be a fixed distance from the left wall of the cell. And for size, we want it to expand on the top, bottom, and right hand side as the cell gets bigger.

So first, go in and size the text view by hand by setting its Layout Rectangle in the Size Inspector to X: 74 Y: 4 Width: 206 Height: 35 This manual sizing just gives us something to work with. We’re going to go in and override this with constraints.

Next, select the UITextView and Editor->Pin->Leading Space to Superview. Then select the UITextView again and Editor->Pin->Top Space to Superview. Repeat again for Trailing Space to Superview and finally Bottom Space to Superview.

You’ve now given this UITextView enough constraints to have a size and position. Now you need to go in and REMOVE any other constraints Xcode may have added. Delete extraneous constraints until you have the following:

Constraints on our UITextView

Finally, for this UITextView, configure it in Xcode using the Attributes inspector to have a background color of clear color, turn off all the scrollers, disable scrolling, no bounces zoom — you don’t want this thing to move at all when the user is viewing or entering text. You want a hard surface to enter text into.

OK, enough Auto Layout! In your table view controller, create outlets for both your UILabel and your UITextView. You’ll need to reference these in your view controller. Wire them up by ctrl-dragging to your header file.

Resizing Our TextView in Code

UITextView inherits from UIScrollView, which means it has a contentSize property which is basically a rectangle containing the text inside your UITextView.

Our strategy from this point out is to basically look at the text we want to contain in our UITextView, which should be a model object, and calculate how large of a text view we need to contain it. And really, we’re concerned with the height here, because the textview is going to be one of either two widths, depending on if the device is in portrait or landscape mode.

So add the following method in your view controller:

- (CGFloat)heightForTextView:(UITextView*)textView containingString:(NSString*)string
{
    float horizontalPadding = 24;
    float verticalPadding = 16;
    float widthOfTextView = textView.contentSize.width - horizontalPadding;
    float height = [string sizeWithFont:[UIFont systemFontOfSize:kFontSize] constrainedToSize:CGSizeMake(widthOfTextView, 999999.0f) lineBreakMode:NSLineBreakByWordWrapping].height + verticalPadding;

    return height;
}

The UITextView comes out of your storyboard with some bizarre values, so the first thing we do in our view controller is reset its frame and contentSize properties to something form fitting based on the text we want it to contain (by calling the above method). This should be your model, and in the case of a form your model might just hold a placeholder value for now. Here is our -viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // set the model
    self.model = @"The arc of the moral universe is long, but it bends towards justice.";

    // create a rect for the text view so it's the right size coming out of IB. Size it to something that is form fitting to the string in the model.
    float height = [self heightForTextView:self.textView containingString:self.model];
    CGRect textViewRect = CGRectMake(74, 4, kTextViewWidth, height);

    self.textView.frame = textViewRect;

    // now that we've resized the frame properly, let's run this through again to get proper dimensions for the contentSize.

    self.textView.contentSize = CGSizeMake(kTextViewWidth, [self heightForTextView:self.textView containingString:self.model]);

    self.textView.text = self.model;
}

Now, our view controller should be set as the UITextView delegate because it’s going to react when the user types in to the cell: it’s going to grow or shrink the cell whenever they type. So implement -textViewDidChange

- (void) textViewDidChange:(UITextView *)textView
{
    self.model = textView.text;
    [self.tableView beginUpdates];
    [self.tableView endUpdates];

}

This causes the table to recalculate the height for each table cell and it does this by calling the table view data source method tableView: heightForRowAtIndexPath. Here again we calculate a height based on the model using the same method and add a little extra padding in there.

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

    if (indexPath.section == 0 && indexPath.row == 0) {

        if (self.textView.contentSize.height >= 44) {
            float height = [self heightForTextView:self.textView containingString:self.model];
            return height + 8; // a little extra padding is needed
        }
        else {
            return self.tableView.rowHeight;
        }

    }
    else {
        return self.tableView.rowHeight;
    }
}

It’s important to constantly save your model when editing because you’re constantly calculating your height off of your model. If you have more than one UITextView, in a form for instance, you’ll need to use a series of if or switch statements to identify them by indexPath.

So, run the sample project and you’ll see it loads up the cell sized to fit the text perfectly, and as you add or delete text, everything resizes perfectly and smoothly.

Here is the source code from this sample project: Source Code as Xcode Project

Here's our finished result!

 

Win a Free Copy of Critix for Netflix

On November 15, 2012, in Uncategorized, by jhowlin

We’re giving away ten free copies of Critix for Netflix, the iOS app that takes the guesswork out of finding good movies to stream on Netflix!

What is Critix for Netflix?

Critix for Netflix is an iOS app for movie fans that use Netflix. It runs on iPhones, iPads, and iPod Touches.

Critix allows you to search the Netflix instant catalog and see search results along with their respective Internet Movie Database (IMDb) and Rotten Tomatoes ratings – helpful information Netflix doesn’t provide. Critix also presents Netflix’s own rating score, along with the movie’s artwork and a plot synopsis.

With one tap, you can add a title to your Netflix instant queue, which is like a “to-do list” of titles to watch.

In addition to finding new movies and TV shows, Critix also gives you control over your instant queue, allowing you to rearrange or remove titles.

I will help you find good movies :)

How to Enter

Enter by “Leaving a Reply” in the comments section below with the following information:

Entries will be accepted through Monday, November 19, 2012 at 5:00 PM EST. Ten winners will be chosen randomly from all submitted entries. Please be sure to submit your e-mail address along with your comment so we can notify you that you’ve won (we will not publish your e-mail nor use it for any marketing purposes).

Copyright (C) 2012 Howlin Interactive, Inc. All Rights Reserved. Apple, the Apple logo, iPhone, iPod and iPad are registered trademarks of Apple Inc. in the U.S. and/or other countries. All other trademarks and trade names are the property of their respective owners.

 

Essential App for Movie Fans Gets Update

On November 14, 2012, in Apps, by jhowlin

Essential App for Movie Fans Gets Update

November 12, 2012 – Boynton Beach, Fla. Critix for Netflix, the popular iOS app that helps movie fans find good movies to watch on Netflix, has just been updated to support Apple’s newest iPhone model, iPhone 5.

Critix allows users to search the Netflix catalog and see search results along with their respective Internet Movie Database (IMDb) and Rotten Tomato (RT) ratings. Critix also presents Netflix’s own rating score, along with the movie’s artwork and a synopsis.

The iPhone 5, which features a larger display than previous iPhone models, allows Critix to display even more movies at once. When scanning a list of search results, which can number in the hundreds, movies that received an IMDb score of greater than 7.2 (out of 10) have their score displayed in green as a slight visual cue to the user that this movie is a “go,” or a good pick.

With one tap, users can add a title to their Netflix instant queue, which is like a “to-do list” of titles to watch.

In addition to finding new movies and TV shows, Critix also gives users control over their instant queue, allowing them to rearrange or remove titles.

In this new version of the app, changes were also made to improve performance and to improve communication with Netflix, IMDb, and the Rotten Tomato web services, which Critix taps into for data.

Critix is available for download now in the Apple App Store ( http://itunes.apple.com/us/app/critix-for-netflix/id543942514?mt=8 ). Its retail pricing is set at $1.99. The app is in active development and new features are constantly being rolled out to users.

About Howlin Interactive, Inc.

Howlin Interactive, Inc. builds innovative and useful apps for Apple’s iOS platform, which includes the iPhone and iPad. They were founded in 2010 and are headquartered in sunny Boynton Beach, Fla.

PRESS CONTACT

Jason Howlin

Howlin Interactive, Inc.

Phone: (561) 809-6452

jhowlin@howlin-interactive.com

http://www.howlin-interactive.com

Critix - Howlin Interactive, Inc.

About Howlin Interactive, Inc.

Howlin Interactive, Inc. builds innovative and useful apps for Apple’s iOS platform, which includes the iPhone and iPad. They were founded in 2010 and are headquartered in sunny Boynton Beach, FL.

Press Screenshots

 

New App Helps Netflix Users Discover Acclaimed Movies

July 25, 2012 – Boynton Beach, Fla. For millions of Netflix customers, making the decision between Fred: The Movie and Being Elmo: A Puppeteer’s Journey just got a whole lot easier.

Critix, a new app for the iPhone and iPad, helps Netflix users separate the good from the bad in Netflix’s vast Instant Watch catalog of movies and television shows.

Critix allows users to search the Netflix catalog and see titles along with their respective Internet Movie Database (IMDb) and Rotten Tomato (RT) scores. These are the two de facto movie-fan websites and their scores are typically generated by thousands of amateur film critics that have seen the movie and have weighed in with a vote. Critix also presents Netflix’s own rating score, along with the movie artwork and synopsis.

Therefore, a search for “documentaries” would show that Being Elmo has an IMDb rating of 8.0 out of 10, a Rotten Tomato score of 91 out of 100, and a Netflix rating of 4.2 out of 5. High marks all around and, for any busy consumer, a good two hours spent.

Fred, on the other hand, didn’t fare as well: IMDb: 2.2 / 10, RT: 49/100, Netflix: 3/5. The sequel, Fred 2: Night of the Living Fred, did just slightly better.

Based on these key pieces of information, users can benefit from the wisdom of thousands of Internet users and, with one tap, add the title to their Instant Queue, which is like a “to-do list” of titles to watch.

In addition to finding new movies and TV shows, Critix also gives users serious control over their Instant Queue. Like any good to-do list, a queue can become overrun with good intentions, often becoming unwieldy with hundreds and hundreds of titles. Critix allows users to pare that back and organize it based on the same ratings and scores, offering title reordering and removal functionality.

“Apps on the iPhone should be simple, but still very useful,” said Jason Howlin, founder of Howlin Interactive, Inc., the company that developed the app. “We had one goal: to help people find good movies to watch on Netflix.”

Regarding the simplicity, Mr. Howlin added, “Among the users in the testing phase were a 9-year-old and a 65-year-old. When they picked it up and used it for the first time without any problems, we knew we had achieved our usability goals.”

The project started at Howlin Interactive out of a simple desire to solve a need that Netflix and other apps were not addressing.

Robyn Gottlieb, Howlin Interactive’s marketing manager, explained, “We know from our research that tech-savvy Netflix users would often have three browser windows open doing research to select a movie. We felt there was an opportunity to streamline that.” Furthermore, she explained that most of the other apps on the market did a poor job of interacting with Netflix in general; they were slow, buggy, and difficult to use, probably because, unlike Critix, most were not developed in iOS’s native programming language, Objective-C.

So, what’s next for the hot iOS development firm?

“Our next project is already under development and I can tell you this: it’s much more meaningful,” hinted Mr. Howlin, who is also the chief software engineer at the company. “It’s truly something unique and it is going to make a big difference in the education and communication space.”

Netflix is a popular way for consumers to enjoy on-demand media on a wide variety of devices. Netflix currently has 26 million streaming media customers that access the service on over 800 different devices, including the Nintendo Wii, Microsoft Xbox, various DVD and Blu-ray players, and Apple TV, to name a few. While Netflix does not specifically state the size of their streaming catalog, various estimates place it at between 15,000 and 20,000 titles.

Because of the large number of different devices that access Netflix, the experience can often vary wildly from device to device. To compensate for missing or hard-to-use functionality, subscribers often turn to third-party apps. For example, the Netflix experience on Nintendo Wii offers very limited searching capability.

Critix is available for download now in the Apple App Store ( http://itunes.apple.com/app/critix/id543942514?mt=8 ). Its retail pricing is set at $.99, but for a limited introductory period, the app is being offered free. An updated version is already in development, which will introduce additional innovative features to aid even more in discovery.

Critix - Howlin Interactive, Inc.

About Howlin Interactive, Inc.

Howlin Interactive, Inc. builds innovative and useful apps for Apple’s iOS platform, which includes the iPhone and iPad. They were founded in 2010 and are headquartered in sunny Boynton Beach, FL.

Press Screenshots (Download as .zip file)