jjzjj

ios - UIPageViewController/TextKit 在分页上重排文本

coder 2023-09-28 原文

我正在开发一个由 TextKit 支持的多页阅读应用程序,该应用程序基于 WWDC 2013 的“高级文本布局和文本工具包效果” session (但一些代码是根据不完整的示例重建的)。基本结构是预先计算文本所需的页面数,然后为每个页面创建一个 NSTextContainer 并将其添加到 NSLayoutManager。每当 UIPageViewController 请求下一页或上一页时,您都会创建一个新的 UITextView 并通过从 NLayoutManger 的 NSTextContainers 数组中选择正确的一个来设置其背景文本容器。

不幸的是,我遇到了一个问题,即文本在第一页和我第一次翻页返回任何给定页面时都会重排。这是它的样子:

这不是最明显的效果(如果你错过了,翻页时注意屏幕顶部),但它有点让人迷惑,如果可能我想消除它。鉴于文本容器应该预先计算,我不明白为什么它会重排文本,或者如何防止它。有谁知道问题出在哪里?

编辑:添加代码示例。

@interface ReaderViewController () <UIPageViewControllerDataSource>

@property (nonatomic, assign) NSUInteger numberOfPages;

@property (nonatomic, retain) UIPageViewController *pageViewController;
@property (nonatomic, retain) NSTextStorage *currentDocument;
@property (nonatomic, retain) NSLayoutManager *layoutManager;

@end

@implementation ReaderViewController

- (instancetype)initWithDocument:(NSTextStorage *)document {
  if ((self = [super init])) {
    _currentDocument = document;
  }
  return self;
}

- (void)viewDidLoad
{
  [super viewDidLoad];

  _layoutManager = [[NSLayoutManager alloc] init];
  [self.layoutManager setTextStorage:self.currentDocument];
  self.layoutManager.delegate = self;

  _pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
                                                        navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
                                                                      options:nil];
  self.pageViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
  self.pageViewController.dataSource = self;
  [self addChildViewController:self.pageViewController];
  [self.view addSubview:self.pageViewController.view];

  // the numberOfPages accessor lazily calculates the number of pages needed to contain the document
  for (int i = 0; i < self.numberOfPages; ++i) {
    NSTextContainer *container = [[NSTextContainer alloc] init];
    container.size = [self _textFrame].size;
    [self.layoutManager addTextContainer:container];
  }

  [self.pageViewController setViewControllers:@[[self viewControllerForPageNumber:0]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}

- (UIViewController *)viewControllerForPageNumber:(NSUInteger)pageNumber {
  if (pageNumber >= self.numberOfPages) {
    return nil;
  }

  // SinglePageViewController is a lightweight view controller that has a UITextView and a page number
  SinglePageViewController *vc = [[SinglePageViewController alloc] init];

  UITextView *textView = [[UITextView alloc] initWithFrame:[self _textFrame] textContainer:[self.layoutManager.textContainers objectAtIndex:pageNumber]];
  textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
  textView.scrollEnabled = NO;
  textView.editable = NO;
  [textView setFont:[UIFont fontWithName:@"IowanOldStyle-Roman" size:20.f]];
  [vc.view addSubview:textView];

  vc.textView = textView;
  vc.pageNumber = pageNumber;

  return vc;
}

#pragma mark - UIPageViewControllerDataSource

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
  NSUInteger currentPage = [(SinglePageViewController *)viewController pageNumber];
  if (currentPage >= self.numberOfPages) {
    return nil;
  }

  return [self viewControllerForPageNumber:currentPage + 1];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
  NSUInteger currentPage = [(SinglePageViewController *)viewController pageNumber];
  if (currentPage == 0) {
    return nil;
  }

  return [self viewControllerForPageNumber:currentPage - 1];
}

#pragma mark - Private

- (CGRect)_textFrame {
  return CGRectInset(self.view.bounds, 5., 0.);
}

@end

最佳答案

我遇到了同样的问题。我的解决方案是将 scrollEnabled 放在 addSubview 之后,将强制 textContainer 重新计算大小。见以下代码:

vc.view.addSubview(textView)
textView.scrollEnabled = false;

更新。最后,我想我找到了正确的答案......我们需要在 didChangeGeometryFromSize 回调中重置容器大小。如果不正确请纠正我:)

func layoutManager(layoutManager: NSLayoutManager, 
                   textContainer: NSTextContainer, 
                   didChangeGeometryFromSize oldSize: CGSize) {

    textContainer.size = self.textFrame().size;
    println(textContainer.size.width)
    println(textContainer.size.height)
}

关于ios - UIPageViewController/TextKit 在分页上重排文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24710845/

有关ios - UIPageViewController/TextKit 在分页上重排文本的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  3. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  6. ruby-on-rails - rspec - 我怎样才能让 "pendings"有我的文本而不仅仅是 "No reason given" - 2

    我有这个代码:context"Visitingtheusers#indexpage."dobefore(:each){visitusers_path}subject{page}pending('iii'){shouldhave_no_css('table#users')}pending{shouldhavecontent('Youhavereachedthispageduetoapermissionic错误')}它会导致几个待处理,例如ManagingUsersGivenapractitionerloggedin.Visitingtheusers#indexpage.#Noreason

  7. ruby - 如何为 pbcopy 生成富文本链接 - 2

    我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te

  8. ruby - 每个页面上的 Jekyll 分页 - 2

    据我们所知,Jekyll默认分页仅支持index.html,我想创建blog.html并在那里包含分页。有什么解决办法吗? 最佳答案 如果您创建一个名为/blog的目录并在其中放置一个index.html文件,那么您可以向_config.yml表示paginate_path:"blog/page:num"。不是使用根文件夹中的默认index.html作为分页器模板,而是使用/blog/index.html。分页器将根据需要生成类似/blog/page2/和/blog/page3/的页面。这将使您到达yourwebsite.com/b

  9. ruby-on-rails - 尝试打开 .gitignore 以在文本编辑器中对其进行编辑,但在 OS X Mountain Lion 上找不到文件位置 - 2

    我使用“newapp_name”创建了一个新的Rails应用程序,我正在尝试编辑.gitignore文件,但在我的应用程序文件夹中找不到它。我在哪里可以找到它?我安装了Git。 最佳答案 .gitignore位于项目的root中,而不是app子目录中。首先打开终端并进入您的目录。您需要使用ls-a来显示stash文件。然后使用打开.gitignore 关于ruby-on-rails-尝试打开.gitignore以在文本编辑器中对其进行编辑,但在OSXMountainLion上找不到文件位

  10. ruby - 如何将一段文本可逆地压缩成更少的 ASCII 字符? - 2

    我想获取任意的ASCII文本字符串,例如“Helloworld”,并将其压缩为字符数较少(尽可能少)的版本,但要采用可以解压缩的方式。压缩版本应仅由ascii字符组成。有没有一种方法可以做到这一点,尤其是在Ruby中? 最佳答案 如果知道只会使用ASCII字符,那就是每个字节的低7位。通过位操作,您可以将每8个字节混合成7个字节(节省12.5%)。如果您可以将其放入更小的范围(仅限64个有效字符),则可以删除另一个字节。但是,因为您希望压缩形式也只包含ASCII字符,所以会丢失一个字节-除非您的输入可以限制为64个字符(例如,有损压

随机推荐