Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering a Long Document on iPad

I'm implementing a document viewer with highlighting/annotation capabilities for a custom document format on iPad. The documents are kind of long (100 to 200 pages, if printed on paper) and I've had a hard time finding the right approach. Here are the requirments:

1) Basic rich-text styling: control of left/right margins. Control of font name, size, foreground/background color, and line spacing. Bold, italics, underline, etc.

2) Selection and highlighting of arbitrary text regions (not limited to paragraph boundaries, like in Safari/UIWebView).

3) Customization of the Cut/Copy/Paste popup (UIMenuController) This is one of the essential requirements of the app.

My first implementation was based on UIWebView. I just rendered the document as HTML with CSS for text styling. But I couldn't get the kind of text selection behavior I wanted (across paragraph boundaries) and the UIMenuController can't be customized from within UIWebView.

So I started working on a javascript approach, faking the device text-selection behavior using JQuery to trap touch events and dynamically modifying the DOM to change the background color of selected regions of text. I built a fake UIMenuController control as a hidden DIV, positioning it and unhiding it whenever there was an active selection region.

Not too shabby.

The main problem is that it's SLOOOOOOOW. Scrolling through the document is nice and quick, but dynamically changing the DOM is not very snappy. Plus, I couldn't figure out how to recreate the magnifier loupe, so my fake text-selection GUI doesn't look quite the same as the native implementation. Also, I haven't yet implemented the communication bridge between the javascript layer and the objective-c layer (where the rest of the app lives), but it was shaping up to be a huge hassle.

So I've been looking at CoreText, but there are precious few examples on the web. I spent a little time with this simple little demo:

http://github.com/jonasschnelli/I7CoreTextExample/

It shows how to use CoreText to draw an NSAttributedText string into a UIView. But it has its own problems: It doesn't implement text-selection behavior, and it doesn't present a UIMenuController, so I don't have any idea how to make that happen. And, more importantly, it tries to draw the entire document all at once, with significant performance degradations for long documents. My documents can have thousands of paragraphs, and less than 1% of the document is ever on screen at a time.

On the plus side, these documents already contain precise formatting information. I know the exact page-position of every line of text, so I don't need a layout engine.

Does anyone know how to implement this sort of view using CoreText? I understand that a full-fledged implementation is overkill for a question like this, but I'm looking for a good CoreText example with a few basic requirements:

1) Precise layout & formatting control (using the formatting metrics and text styles I've already calculated).

2) Arbitrary selection of text.

3) Customization of the UIMenuController.

4) Efficient recycling of resources for off-screen objects.

I'd be happy to implement my own recycling when text elements scroll off-screen, but wouldn't that require re-implementing UIScrollView?

I'm brand-new to iPhone development, and still getting used to Objective-C, but I've been working in other languages (Java, C#, flex/actionscript, etc) for more than ten years, so I feel confident in my ability to get the work done, if only I had a better feel for the iPhone SDK and the common coding patterns for stuff like this. Is it just me, or does the SDK documentation really suck?

Anyhow, thanks for your help!

like image 884
benjismith Avatar asked Jun 13 '10 18:06

benjismith


2 Answers

Does your document have any semantic components other than each paragraph? If you already have some concept of sections or pages, I would recommend you render each one of those as an independent tablecell. It's pretty simple to create a tablecell that makes you forget you're actually looking at a UITableView. All you would need to do is override drawRect: and setSelected: and setHighlighted: and tah dah! No More cell dividers unless you want them. Furthermore you could do some nifty things by using a tableview as your base. If you defined sections in the UITableView then you could have a nifty header that scrolls along as you're paging through your document. Another thing you could do is add a "jump to section" bar / a bookmarks menu, and that way you don't have to provide selection across the boundaries of sections.

Massive copy paste blocks would be pretty painful on the system as well. Further, if you went through the trouble to provide this content you might not want to make it too easy for someone to copy it all at once... (Can't follow this line of thought more without more specifics on your project).

If you really do want to provide the copy paste options you could add buttons to each logical page or section that immediately selects and copies the whole section for the user's convenience. (Maybe with citation associated?)

I recommend you lookup the UITableViewCell UITableViewDelegate and UITableViewDataSource in the SDK docs as those pages will significantly help if you choose to use this suggestion.

like image 163
fbartho Avatar answered Sep 27 '22 19:09

fbartho


Just two random observations:

  • Can you afford to create a paging interface? (As opposed to “endless scrolling”.) It looks like a paging interface would be a lot easier on system resources.

  • The UIActionBar is actually the UIMenuController class. The interface is a bit weird, as the menu is a singleton (wtf?), but I’m sure you’ll have no trouble figuring it out.

Hope that helps.

like image 41
zoul Avatar answered Sep 27 '22 19:09

zoul