ios电子书翻页效果代码详解

 更新时间:2018年02月01日 11:33:32   投稿:laozhang  
这篇文章主要介绍了ios电子书翻页效果代码实现过程以及对应的代码讲解,有需要的朋友参考下。

近实现了一个完整的电子书阅读器,支持txt和epub格式的电子书阅读,其中epub支持图文混排的方式展示。本文主要谈谈其中两种翻页效果的实现,分别为仿真翻页和水平滑动翻页。

仿真翻页

最合适的方案就是使用系统提供的UIPageviewcontroller了,不过默认的UIpageviewcontroller翻页时背面是白色的,而阅读器通常都会有背景色或背景图片,翻页时用户体验就很糟糕,比如就像下面这样

所以接下来主要说说如何修改背面颜色以达到美观的翻页效果。

UIpageviewcontroller有一个属性叫做isDoubleSided,默认为yes,也就是内容只会在单面(正面)显示,设置为no后,内容便可以正面和背面双面显示,这时每翻一页,pageview的下面两个回调会调用两次

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
{
  // 第一次回调索取背面的controller
  // 第二次回调索取正面的controller
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
{
  // 第一次回调索取背面的controller
  // 第二次回调索取正面的controller
}

所以我们可以对正面的controller进行反向截图,并将其放在背面的controller上显示,这样整体翻页效果就会很美观了。
代码示例

// 对输入的controller进行反向截图
func grabViewController(viewController: DUAPageViewController) -> Void {
  self.index = viewController.index
  self.chapterBelong = viewController.chapterBelong
  let rect = viewController.view.bounds
  UIGraphicsBeginImageContextWithOptions(rect.size, true, 0.0)
  let context = UIGraphicsGetCurrentContext()
  let transform = CGAffineTransform(a: -1.0, b: 0.0, c: 0.0, d: 1.0, tx: rect.size.width, ty: 0.0)
  context?.concatenate(transform)
  viewController.view.layer.render(in: context!)
  self.backImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
 }

效果像下面这样

左右平滑翻页

最初采用的是UIpageviewcontroller的另一种翻页模式——滚动模式。该模式苹果在底层是用scrollView实现的。但这种模式在页面切换时存在一些问题,由于苹果会对相邻的controller进行缓存,当调用open func setViewControllers(_ viewControllers: [UIViewController]?, direction: UIPageViewControllerNavigationDirection, animated: Bool, completion: ((Bool) -> Swift.Void)? = nil)方法并且动画为true时,有时苹果会错误的认为它已经有了页面的缓存而不再执行数据源方法,从而引发一些问题,更详细的说明可以看这篇文章,因此决定自己写一个翻页控件

DUATranslationController

DUATranslationController并没有采用Scrollview的方式实现,而是基于controller容器,通过替换child controller来实现,具体来说就是当用户点击或者滑动时,判断需要展示上一个页面还是下一个页面,然后模仿UIpageviewcontroller通过回调的方式索取controller,加入到controller容器中,并通过动画的方式将新的controller平滑移动进入屏幕,旧的controller同时移出,如下是单击手势代码示例(滑动手势涉及和用户交互,逻辑更复杂些,但基本思路是一致的)

@objc func handleTapGes(gesture: UITapGestureRecognizer) -> Void {
  let hitPoint = gesture.location(in: gesture.view)
  let curController = self.childViewControllers.first!
  
  if hitPoint.x < gesture.view!.frame.size.width/3 {
//   滑向上一个controller
   let lastController = self.delegate?.translationController(translationController: self, controllerBefore: curController)
   if lastController != nil {
    self.delegate?.translationController(translationController: self, willTransitionTo: lastController!)
    self.setViewController(viewController: lastController!, direction: .right, animated: allowAnimating, completionHandler: {(complete) in
     self.delegate?.translationController(translationController: self, didFinishAnimating: complete, previousController: curController, transitionCompleted: complete)
    })
   }
   
  }
  if hitPoint.x > gesture.view!.frame.size.width*2/3 {
//   滑向下一个controller
   let nextController: UIViewController? = self.delegate?.translationController(translationController: self, controllerAfter: self.childViewControllers.first!)
   if nextController != nil {
    self.delegate?.translationController(translationController: self, willTransitionTo: nextController!)
    self.setViewController(viewController: nextController!, direction: .left, animated: allowAnimating, completionHandler: {(complete) in

     self.delegate?.translationController(translationController: self, didFinishAnimating: complete, previousController: curController, transitionCompleted: complete)
    })
   }
   
  }
  
 }
// 该方法模仿UIpageviewcontroller,切换到某一个controller
func setViewController(viewController: UIViewController, direction: translationControllerNavigationDirection, animated: Bool, completionHandler: ((Bool) -> Void)?) -> Void {
  if animated == false {
   // 直接添加child controller ,略
  }else {
   let oldController = self.childViewControllers.first
   self.addController(controller: viewController)
   
   var newVCEndTransform: CGAffineTransform
   var oldVCEndTransform: CGAffineTransform
   viewController.view.transform = .identity
   if direction == .left {
    viewController.view.transform = CGAffineTransform(translationX: screenWidth, y: 0)
    newVCEndTransform = .identity
    oldController?.view.transform = .identity
    oldVCEndTransform = CGAffineTransform(translationX: -screenWidth, y: 0)
   }else {
    viewController.view.transform = CGAffineTransform(translationX: -screenWidth, y: 0)
    newVCEndTransform = .identity
    oldController?.view.transform = .identity
    oldVCEndTransform = CGAffineTransform(translationX: screenWidth, y: 0)
   }
   
   UIView.animate(withDuration: animationDuration, animations: {
    oldController?.view.transform = oldVCEndTransform
    viewController.view.transform = newVCEndTransform
   }, completion: { (complete) in
    if complete {
     self.removeController(controller: oldController!)
    }
    if completionHandler != nil {
     completionHandler!(complete)
    }
    
   })
  }
 }
 

最终效果像这样:

相关文章

  • 浅谈Xcode 开发工具 XCActionBar

    浅谈Xcode 开发工具 XCActionBar

    本文主要给大家简单讲解了Xcode的开发工具 XCActionBar的介绍与使用方法,非常的全面实用,有需要的小伙伴可以参考下。
    2015-11-11
  • iOS 二维码生成及扫码详解及实例代码

    iOS 二维码生成及扫码详解及实例代码

    这篇文章主要介绍了iOS 二维码生成及扫码详解及实例代码的相关资料,需要的朋友可以参考下
    2016-12-12
  • iOS常用组件之高效切圆角的方法汇总

    iOS常用组件之高效切圆角的方法汇总

    最近在研究切圆角的方法,也找了下网上的资料,所以下面这篇文章主要给大家总结介绍了关于iOS常用组件之高效切圆角的一些方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-01-01
  • iOS开发中使用UIWebView 屏蔽 alert警告框

    iOS开发中使用UIWebView 屏蔽 alert警告框

    这篇文章主要介绍了iOS开发中使用UIWebView 屏蔽 alert警告框的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-11-11
  • iOS端React Native差异化增量更新的实现方法

    iOS端React Native差异化增量更新的实现方法

    这篇文章主要给大家介绍了关于iOS端React Native差异化增量更新的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-06-06
  • iOS如何将照片保存到相册

    iOS如何将照片保存到相册

    这篇文章主要为大家详细介绍了iOS将照片保存到相册的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • IOS开发Objective-C Runtime使用示例详解

    IOS开发Objective-C Runtime使用示例详解

    这篇文章主要为大家介绍了IOS开发Objective-C Runtime使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 简单谈谈c/c++中#import、#include和@class的区别

    简单谈谈c/c++中#import、#include和@class的区别

    对于#import,我想做过iOS开发的人应该都不陌生。在开发过程中,当我们需要声明某一个类时,都需要去引用。而#imclude的话,在我们学习C时就已经知道了,他的作用也是引用声明的意思。在表面上他们的作用似乎都是一样的。但是在具体功能实现方式上,还是有着很大的区别。
    2018-01-01
  • ios实现简易队列

    ios实现简易队列

    这篇文章主要为大家详细介绍了ios实现简易队列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • iOS 中weak的实现代码示例

    iOS 中weak的实现代码示例

    本篇文章主要介绍了iOS 中weak的实现代码示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05

最新评论