How does the iBooks App format the text on separate pages?

有些话、适合烂在心里 提交于 2019-12-21 03:48:53

问题


Looking at the iBooks App, I was wondering how it accomplishes to format text (probably a very simple txt file) so that it is NOT SCROLLABLE but divided on separate pages.

I'd like to achieve the same, but only with editable text.

Where would I need to start? UITextView doesn't work as it scrolls. Even if I set the pagingEnabled property to YES, it won't do the job.

It seems as if I need to LIMIT the amount of text I can put on a certain page. Is there a function to LIMIT the input of a UITextView? I would need to limit the number of LINES (not characters) as they would be shown on a full iPhone screen (I guess you can fit 20 or so lines, depending on the font size).

Any help would be appreciated! As I'm a beginner, I especially appreciate samples in which similar methods are put to use.

Thanks!


回答1:


What you need is an own layout algorithm that takes the text, measuring its size and cuts it until it fits into a single page text view. Then start with the rest of the text, same thing for a next text view and so on... After that (or inside the algorithm) you arrange all the resulting text views on scroll view (or in an array, you later flip through with paging animations - if you like it cheesy). I did a similar thing, but with UILabels, it should also work with textviews. What you need is: NSString's - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size and rangeOfString:@" " options:NSBackwardsSearch (looking for word spaces) and substringFromIndex: resp. substringToIndex:

If you need more information, just post a comment.

EDIT:

Hi following code is not tested but contains most of what you need (hopefully), but may hold some bugs, especially when it comes to the recursion... I corrected the BackWardsSearch idea, because it could take a looong time to cut a long text. What I totally ignored - and that could be really tricky - is re-rendering while editing. But anyway, here's the code. It's a view controller assumed to old 4 members (header file not posted):

  UIView *editableBook;
  NSMutableArray *content;
  int currentPage;
  UIFont *font;

And this is the Controller itself:

//
//  EditableBookController.m
//
//  Created by Kai on 09.03.11.
//

#import "EditableBookController.h"


@implementation EditableBookController

-(id)initWithText:(NSString *)text
{
  if (self=[super init]) 
  {
    font = [UIFont fontWithName:@"SomeFont" size:12];
    content = [[NSMutableArray alloc]init];
    [self cutInPages:text];
    currentPage = 0;  
  }
  return self;
}

- (void)loadView 
{
  self.view = [[UIView alloc] initWithFrame:CGRectMake(.0, .0, 768., 1024.)];//assuming portrait only ...
  editableBook = [[UIView alloc]initWithFrame:self.view.bounds];//could be a scroll view in alternate approach
  UISwipeGestureRecognizer *flipper = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextOrPrevious:)];
  [editableBook addGestureRecognizer:flipper];
  [flipper release];
  [self.view addSubview:editableBook];
  UITextView *textView = [[UITextView alloc]initWithText:[content objectAtIndex:currentPage]];
  textView.frame = editableBook.bounds;
  textView.font = font;
  textView.tag = 23;
  [editableBook addSubview:textView];
  [textView release];
}

-(void)nextOrPrevious:(id)sender
{
  UISwipeGestureRecognizer *flipper = (UISwipeGestureRecognizer*)sender;
  if(flipper.direction == UISwipeGestureRecognizerDirectionLeft)
  {
    [self next];
  }
  else if(flipper.direction == UISwipeGestureRecognizerDirectionRight)
  {
    [self previous];
  }
}

-(void)next
{
  if(currentPage == content.count - 1)
  {
    return;
  }
  currentPage++;
  UIView *fromView = [editableBook viewWithTag:23];
  UIView *toView =  [[UITextView alloc]initWithText:[content objectAtIndex:currentPage]];
  toView.frame = editableBook.bounds;
  toView.tag = 23;
  [UIView transitionWithView:editableBook duration:0.2 options:UIViewAnimationTransitionFlipFromRight
   animations:^
   {
     [fromView removeFromSuperview];
     [editableBook addSubview:toView];
   }
   completion:NULL];
}

-(void)previous
{
  if(currentPage == 0)
  {
    return;
  }
  currentPage--;
  UIView *fromView = [editableBook viewWithTag:23];
  UIView *toView =  [[UITextView alloc]initWithText:[content objectAtIndex:currentPage]];
  toView.frame = editableBook.bounds;
  toView.tag = 23;
  [UIView transitionWithView:editableBook duration:0.2 options:UIViewAnimationTransitionFlipFromLeft
   animations:^
   {
     [fromView removeFromSuperview];
     [editableBook addSubview:toView];
   }
   completion:NULL];
}

-(void)cutInPages:(NSString *)text
{
  NSRange whereToCut = whereToCut = [text rangeOfString:@" "];
  NSString *pageText = [text substringToIndex:whereToCut.location];
  NSString *rest = [text substringFromIndex:whereToCut.location];;
  CGFloat height = 0;
  while (height<1024.) 
  {
    NSRange whereToCut = [rest rangeOfString:@" "];
    NSString *wordOfRest = [rest substringToIndex:whereToCut.location];
    pageText = [NSString stringWithFormat:@"%@%@", pageText, wordOfRest];
    rest = [rest substringFromIndex:whereToCut.location];;
    CGSize size = [pageText sizeWithFont:font
                      constrainedToSize:CGSizeMake(768., 10000) 
                          lineBreakMode:UILineBreakModeWordWrap];
    height = size.height;
  }
  if(height>1024.)
  {
    //TODO cut the last word of pageText and prepend to the eest
  }
  [content addObject:pageText];
  if([rest length] > 0)
  {
    [self cutInPages:rest];
  }
}

- (void)dealloc 
{
  [editableBook release];
  [content release];
  [super dealloc];
}


@end



回答2:


I haven't seen the source code, but I'd be willing to guarantee that they're using the CoreText framework to do their pagination and rendering. Be warned, however, that when it says "low level", it means that. This is a framework that deals with rendering characters directly. Stuff like character selection and insertion (which you'd probably want for editable text) is quite difficult with CoreText.

I'd recommend going to with the NSString drawing and sizing methods that are part of the UIKit framework. But even then, you're going to have to do quite a bit of work to get this functional. I don't think UIKit offers a text-editing control that doesn't scroll. We assume that if you want to edit text, it's going to be of an arbitrary length, which means we put it inside a scrollable container (so that it can be any length).

In a nutshell, if you're a beginner, I would recommend working on something else. What you're asking for is not an easy thing to do. :)



来源:https://stackoverflow.com/questions/5236177/how-does-the-ibooks-app-format-the-text-on-separate-pages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!