UILocalizedIndexedCollation
UITableView starts to become unwieldy once it gets to a few hundred rows. If users are reduced to frantically scratching at the screen like a cat playing Fruit Ninja in order to get at what they want… you may want to rethink your UI approach.
So, what are your options?
Well, you could organize your data into a hierarchy, which could dramatically reduce the number of rows displayed on each screen in fashion, based on its branching factor.
You could also add a UISearch
to the top of your table view, allowing the user to filter on keywords to get exactly what they’re looking for (or–perhaps more importantly–determine that what they seek doesn’t exist in the first place).
There is also a third approach, which is generally under-utilized in iOS applications: section index titles. These are the vertically flowing letters found along the right side of table views in your Address Book contacts list or Music library:
As the user scrolls their finger down the list, the table view jumps to the corresponding section. Even the most tiresome table view is rendered significantly more usable as a result.
Section index titles can be enabled by implementing the following UITable
delegate methods:
-
-section
- Returns an array of the section index titles to be displayed along the right hand side of the table view, such as the alphabetical list “A…Z” + “#”. Section index titles are short–generally limited to 2 Unicode characters.Index Titles For Table View: -
-table
- Returns the section index that the table view should jump to when the user touches a particular section index title.View:section For Section Index Title:at Index:
As longtime readers of NSHipster doubtless have already guessed, the process of generating that alphabetical list is not something you would want to have to generate yourself. What it means to something to be alphabetically sorted, or even what is meant by an “alphabet” varies wildly across different locales.
Coming to our rescue is UILocalized
.
UILocalized
is a class that helps to organize data in table views with section index titles in a locale-aware manner. Rather than creating the object directly, a shared instance corresponding to the current locale supported by your application is accessed, with UILocalized
The first task for UILocalized
is to determine what section index titles to display for the current locale, which are can be read from the section
property.
To give you a better idea of how section index titles vary between locales:
In order to see these for yourself, you’ll need to explicitly add the desired locales to your Project Localizations list.
Locale | Section Index Titles |
---|---|
en_US | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, # |
ja_JP | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, あ, か, さ, た, な, は, ま, や, ら, わ, # |
sv_SE | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Å, Ä, Ö, # |
ko_KO | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, ㄱ, ㄴ, ㄷ, ㄹ, ㅁ, ㅂ, ㅅ, ㅇ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ, # |
AR_sa | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, آ, ب, ت, ث, ج, ح, خ, د, ذ, ر, ز, س, ش, ص, ض, ط, ظ, ع, غ, ف, ق, ك, ل, م, ن, ه, و, ي, # |
Aren’t you glad you don’t have to do this yourself?
So with the list of section titles laid out before you, the next step is to determine what section each object should be assigned to. This is accomplished with -section
. This method returns the NSInteger
index corresponding to the string value of the object when performing the specified selector. This selector might be something like localized
, title
, or even just description
.
So, as it stands, your table view data source has a NSArray property corresponding to the number of sections in the table view, with each element of the array containing an array representing each row in the section. Since collation was handled by UILocalized
, it makes sense for it to sort the rows in each section as well. – sorted
does this in similar fashion to -section
, by sorting the objects in the section by their respective localized title.
Finally, the table view should implement -table
, so that touching a section index title jumps to the corresponding section in the table view. UILocalized
does the trick.
All told, here’s what a typical table view data source implementation looks like:
class Object Table View Controller: UITable View Controller {
let collation = UILocalized Indexed Collation.current()
var sections: [[Any Object]] = []
var objects: [Any Object] = [] {
did Set {
let selector = #selector(getter: UIApplication Shortcut Item.localized Title)
sections = Array(repeating: [], count: collation.section Titles.count)
let sorted Objects = collation.sorted Array(from: objects, collation String Selector: selector)
for object in sorted Objects {
let section Number = collation.section(for: object, collation String Selector: selector)
sections[section Number].append(object as Any Object)
}
self.table View.reload Data()
}
}
// MARK: UITable View Delegate
override func table View(_ table View: UITable View, title For Header In Section section: Int) -> String? {
return collation.section Titles[section]
}
override func section Index Titles(for table View: UITable View) -> [String]? {
return collation.section Index Titles
}
override func table View(_ table View: UITable View, section For Section Index Title title: String, at index: Int) -> Int {
return collation.section(for Section Index Title: index)
}
}
- (void)set Objects:(NSArray *)objects {
SEL selector = @selector(localized Title);
NSInteger index, section Titles Count = [[[UILocalized Indexed Collation current Collation] section Titles] count];
NSMutable Array *mutable Sections = [[NSMutable Array alloc] init With Capacity:section Titles Count];
for (NSUInteger idx = 0; idx < section Titles Count; idx++) {
[mutable Sections add Object:[NSMutable Array array]];
}
for (id object in objects) {
NSInteger section Number = [[UILocalized Indexed Collation current Collation] section For Object:object collation String Selector:selector];
[[mutable Sections object At Index:section Number] add Object:object];
}
for (NSUInteger idx = 0; idx < section Titles Count; idx++) {
NSArray *objects For Section = [mutable Sections object At Index:idx];
[mutable Sections replace Object At Index:idx with Object:[[UILocalized Indexed Collation current Collation] sorted Array From Array:objects For Section collation String Selector:selector]];
}
self.sections = mutable Sections;
[self.table View reload Data];
}
- (NSString *)table View:(UITable View *)table View
title For Header In Section:(NSInteger)section
{
return [[[UILocalized Indexed Collation current Collation] section Titles] object At Index:section];
}
- (NSArray *)section Index Titles For Table View:(UITable View *)table View {
return [[UILocalized Indexed Collation current Collation] section Index Titles];
}
- (NSInteger)table View:(UITable View *)table View
section For Section Index Title:(NSString *)title
at Index:(NSInteger)index
{
return [[UILocalized Indexed Collation current Collation] section For Section Index Title At Index:index];
}
UITableViewIndexSearch
There is one special section index title worth mentioning, and that’s UITable
. It’s a common pattern to have both a search bar and section indexes. In equal parts convenience and visual consistency, a search icon is often included as the first section index title, which can be touched to bring up the UISearch
in the header of the table view.
To include the search icon in your table view, you would simply prepend the NSString
constant UITable
to the return value of -section
, and adjust -table
to account for the single element shift.
So remember, NSHipsters one and all: if you see an excessively long table view, kill it with fire!
…which is to say, refactor your content with some combination of hierarchies, a search bar, and section indexes. And when implementing section index titles, take advantage of UILocalized
.
Together, we can put an end to scroll view-induced repetitive stress injuries, and spend more time enjoying the finer things in life, like watching videos of pets playing with iPads.