Как приложението iBooks форматира текста на отделни страници?

Разглеждайки приложението iBooks, се чудех как успява да форматира текст (вероятно много прост txt файл), така че да НЕ ПРЕВЪРТАВА, а да бъде разделен на отделни страници.

Бих искал да постигна същото, но само с редактируем текст.

Откъде трябва да започна? UITextView не работи, докато превърта. Дори и да задам свойството pagingEnabled на YES, то няма да свърши работа.

Изглежда, че трябва да ОГРАНИЧАВАм количеството текст, което мога да поставя на определена страница. Има ли функция за ОГРАНИЧАВАНЕ на въвеждането на UITextView? Ще трябва да огранича броя на РЕДОВЕ (не знаци), тъй като те ще бъдат показани на цял екран на iPhone (предполагам, че можете да поберете 20 или повече реда, в зависимост от размера на шрифта).

Всяка помощ ще бъде оценена! Тъй като съм начинаещ, особено оценявам примери, в които се използват подобни методи.

Благодаря!


person n.evermind    schedule 08.03.2011    source източник


Отговори (2)


Това, от което се нуждаете, е собствен алгоритъм за оформление, който взема текста, измерва размера му и го изрязва, докато се побере в текстов изглед на една страница. След това започнете с останалата част от текста, същото нещо за следващ текстов изглед и така нататък... След това (или вътре в алгоритъма) подреждате всички произтичащи текстови изгледи в изглед за превъртане (или в масив, който по-късно прелиствате с анимации за страниране - ако ви харесва кичозно). Направих подобно нещо, но с UILabels трябва да работи и с текстови изгледи. Това, от което се нуждаете, е: NSString's - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size и rangeOfString:@" " options:NSBackwardsSearch (търсете интервали от думи) и substringFromIndex: респ. substringToIndex:

Ако имате нужда от повече информация, просто публикувайте коментар.

РЕДАКТИРАНЕ:

Здравейте, следният код не е тестван, но съдържа повечето от това, от което се нуждаете (надявам се), но може да съдържа някои грешки, особено що се отнася до рекурсията... Коригирах идеята BackWardsSearch, защото може да отнеме много време, за да изрежете дълго текст. Това, което напълно пренебрегнах - и това може да бъде наистина трудно - е повторно изобразяване по време на редактиране. Но както и да е, ето кода. Това е контролер за изглед, приет за стари 4 члена (заглавният файл не е публикуван):

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

И това е самият контролер:

//
//  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
person Kai Huppmann    schedule 08.03.2011
comment
Благодаря за бързия отговор. Разбирам какво имаш предвид (особено алгоритъма за нарязване на текста на малки парчета), но съм напълно изгубен, когато започна да мисля откъде да започна. - person n.evermind; 08.03.2011
comment
(1) Да приемем, че имам алгоритъм на място. Някакъв вид методи, на които предавам масив и методите го нарязват и го записват в друг масив. - person n.evermind; 08.03.2011
comment
(2) Каква ще бъде следващата ми стъпка? Да приемем, че искам да имам отделен алгоритъм/метод за това. Поставям масива в UITextView? - person n.evermind; 08.03.2011
comment
Имате ли някакъв примерен код, който бихте желали да споделите? Не е задължително да е всичко, просто съм напълно изгубен, когато се стигне до прилагането на теорията. Благодаря! - person n.evermind; 08.03.2011
comment
Благодаря много, това е наистина мило от ваша страна! Надявам се това да ме насочи към правилната посока. След като постигнах известен напредък, интересувате ли се да видите резултатите? Ако е така, уведомете ме как да ви държа в течение! Благодаря отново, наистина оценявам помощта ви! - person n.evermind; 09.03.2011
comment
Да, моля, публикувайте коментари тук с вашия опит. Особено ме интересува дали/как управлявате повторното изобразяване по време на редактиране. - person Kai Huppmann; 09.03.2011

Не съм виждал изходния код, но бих искал да гарантирам, че те използват CoreText framework за извършване на тяхното страниране и изобразяване. Имайте предвид обаче, че когато пише "ниско ниво", това означава. Това е рамка, която се занимава с директно изобразяване на символи. Неща като избор и вмъкване на знаци (които вероятно бихте искали за редактируем текст) са доста трудни с CoreText.

Бих препоръчал да отидете на с NSString чертежа и методи за оразмеряване, които са част от рамката на UIKit. Но дори и тогава ще трябва да свършите доста работа, за да направите това функционално. Не мисля, че UIKit предлага контрол за редактиране на текст, който не превърта. Предполагаме, че ако искате да редактирате текст, той ще бъде с произволна дължина, което означава, че го поставяме в контейнер с възможност за превъртане (така че да може да има произволна дължина).

С две думи, ако сте начинаещ, бих препоръчал да работите върху нещо друго. Това, което искаш, не е лесно да се направи. :)

person Dave DeLong    schedule 08.03.2011
comment
Хм... значи предлагаш да се откажа... Защо това е толкова трудно? Трябва да има някакъв лесен начин да се постигне това. Да забравим за анимацията и всичко останало. Да предположим, че имаме текстов файл, който ще запълни 2 1/2 екрана на iphone (или просто „страници“). Трябва да има лесен начин (с PageControl?) да се програмира приложение, което запълва първата страница, след което осъзнава, че вече няма място, отваря страница 2, отново осъзнава, че няма място и накрая запълва половината от страница 3. - person n.evermind; 08.03.2011
comment
Със сигурност не може да бъде толкова трудно... нали? - person n.evermind; 08.03.2011
comment
@DanielNicolae: не е невъзможно и за опитен програмист може дори да не е толкова трудно. но също така не бих го нарекъл проблем на ниво начинаещ. твърдата твърда твърда част е редактируемото естество на вашия текст. Правенето на това за статичен текст трябва да е доста лесно. Да направите това за текст, който може да се редактира, е много по-трудно, защото изведнъж имате клавиатурата, за да се притеснявате, че ще ви пречи. Какво се случва, когато се появи клавиатурата? преоразмеряваш ли всичко? внезапно разрешаваш превъртане? намаляваш ли размера на страницата? това не е прост проблем - person Dave DeLong; 09.03.2011
comment
Добре тогава, нека първо да го сортирам за статичен текст. И дори след това не виждам проблем с клавиатурата. Вече го програмирах така, че да не може да скрие текста. Планът беше след това да разреша превъртане (всъщност не го забраних преди - просто не беше необходимо, тъй като имах само ограничено количество редове на екрана). Така че, да, ако се появи клавиатурата, ще преоразмерим UITextView (или просто ще го бутнем нагоре, без да го преоразмеряваме, но тези около 50% ще бъдат скрити). - person n.evermind; 09.03.2011
comment
В известен смисъл това е като да имате (1) приложение iBooks със СТАТИЧЕН текст, което (2) внезапно се променя в приложение за бележки (с всички превъртащи се тънкости), когато потребителят иска да редактира страница. Въведеното обаче ще повлияе на това как се форматира останалата част (напр. ако той вмъкне друга страница с текст на страница 2, например, ще трябва да преместим това съдържание на страници 3 и 4 и т.н. - person n.evermind; 09.03.2011