Document View

  • The document view controller is the starting point for visualizing a document on screen. It groups all the UI that deals with showing documents on screen and controls the view hierarchy and the layout.

    The Layout

    The main way of controlling how a layout looks is through PSPDFDocumentViewLayout. While PSPDFKit provides you with a set of default layouts such as a continuous scrolling layout, a paginated scroll per spread layout and a curl based layout, layouts are meant to be fully customizable so you can adopt PSPDFKit to your design perfectly.

    To customize a design you can start by changing properties on a design provided by PSPDFKit. If this is not enough, PSPDFDocumentViewLayout and its subclasses provide various levels of entry points to best fit what your desired outcome is.

    You can either subclass PSPDFContinuousScrollingLayout or PSPDFScrollPerSpreadLayout if you want a layout similar to these two but only need a couple of tweaks. If you want to have more control but your layout still follows the general idea of a layout that scrolls in a single direction, either vertically or horizontally, PSPDFStackViewLayout, gives you a lot of control while covering the basics and a couple of convenience methods that make your life easier. This should be enough control for almost all designs. However if your design is very specific, we also give you the same base class all of our own layouts use: PSPDFDocumentViewLayout. With this layout you need to do everything on your own but there should be pretty much no limitations on what to do with it.

    To get you started with implementing your own layout, check out the documentation for PSPDFDocumentViewLayout.

    The Hierarchy

    The document view hierarchy can be seen in the following diagram.

    ╔═══════════════════════════╗         ┌───────────────────────────┐
      DocumentViewController              PSPDFDocumentViewLayout  
                               ║────────▶│                           
    ╚═══════════════════════════╝         └───────────────────────────┘
    ┌───────────────────────────┐
           UIScrollView        
       (scrolling & zooming)   │◀───┐            Depending on
    └───────────────────────────┘         spreadBasedZooming either
    ┌───────────────────────────┐    ├──── one of these scroll views
           UIScrollView                 is responsible for zooming
             (zooming)         │◀───┘            the content.
    └───────────────────────────┘
    ╔═══════════════════════════╗
            SpreadView         
                               
    ╚═══════════════════════════╝
    ╔═══════════════════════════╗
             PageView          
                               
    ╚═══════════════════════════╝
    
    ┌─────────────────────────────────────────────────────────────────┐
                            ═══  Subclassable                        
    └─────────────────────────────────────────────────────────────────┘
    

    Continuous Spread Index

    Usually you should prefer the integer based spreadIndex APIs. The spreadIndex is less complex and does the necessary conversion to the continuous spread index for you. However there are use cases where you need floating point precision for the current scrolling position.

    The continuousSpreadIndex maps the spreads of the document on to the viewport in a size independent way. That means that no matter what size a spread is displayed on and also no matter what other spread sizes are already known of a document, the continuous spread index remains stable. E.g. a continuous spread index of 2.5 will always refer to the center of spread 2.

    In the places where a continuous spread index is related to a certain position in the view hierarchy, it is related to the center of the current viewport. So if you call continuousSpreadIndex you will receive the continuous spread index that is currently shown at the center of the document view controller’s view.

    If you implement your own custom layout and this layout does not build on top of PSPDFStackViewLayout, you may need to deal with the continuous spread index though and do calculations between the continuous spread index and the content offset yourself. For that it is important how the function of the continuous spread index looks. It is a monotonically increasing function over all spreads of a document. Its valid range is [0, spreadCount). Note that it is monotonically, but not strictly monotonically increasing. The spaces between spread are not considered to be a part of a spread, therefore in this area, the continuous spread index does not change. E.g. spread 2 has a range of [2, 3), then there is the inter-item spacing between spread 2 and 3 where the continuous spread index is 3 and only when you start scrolling into spread 3, the continuous spread index starts increasing again in the range of [3, 4) for this spread.

    3.0 ─│               
                       
                            This diagram shows how the continuous spread index
                            is calculated over the spreads. In the gap between
    2.0 ─│         ╱─╱        two spreads, the continuous spread index is not
                            changing.
                
                            Inside each spread, the continuous spread index is
    1.0 ─│   ╱─╱              linear in the range [i, i+1).
           
          
         │╱
         ╳────────────────
         ┌───┐ ┌───┐ ┌───┐
                    
          0   1   2 
                    
         └───┘ └───┘ └───┘
    
    See more

    Declaration

    Objective-C

    
    @interface PSPDFDocumentViewController : UIViewController <PSPDFOverridable>

    Swift

    class PDFDocumentViewController : UIViewController, Overridable
  • A document view layout controls how a document is visualized on screen. It controls where a spread (a set of pages) is placed on the screen and how scrolling and zooming behaves.

    Subclassing

    PSPDFDocumentViewLayout is an abstract base class meant for subclassing. You can either subclass PSPDFContinuousScrollingLayout or PSPDFScrollPerSpreadLayout if you want a layout similar to these two but only need a couple of tweaks. If you want to have more control but your layout still follows the general idea of a layout that scrolls in a single direction, either vertically or horizontally, PSPDFStackViewLayout, the superclass of the two aforementioned layouts, gives you a lot of control while covering the basics and a couple of convenience methods that make your life easier. This should be enough control for almost all designs. However if your design is very specific, we also give you the same base class all of our own layouts use: PSPDFDocumentViewLayout. With this layout you need to do everything on your own but there are almost no limitations on what to do with it.

    Spreads

    The main thing that a document view layout cares about is a spread; this is what it calculates the position of. A spread is a collection of pages that are always viewed together. If you have the most basic layout, a layout with its spread mode set to single, every spread corresponds to a single page in the document, which means the amount of spreads is equal to the amount of pages. However you can also have a double paged layout or a book layout. To convert between pages and spreads, PSPDFDocumentViewLayout provides you with helper methods. To make your layout work with all spread modes, it is important that you use these methods for conversion and, in case you want to implement your own spreading algorithms, override these methods and make them do the proper conversion, otherwise your layout may not work correctly in all cases.

    UICollectionViewLayout

    It is very important to keep in mind that a document view layout is based on UICollectionViewLayout and that this is what is used to calculate the position of a spread on the screen in the end. PSPDFDocumentViewLayout and especially its subclass PSPDFStackViewLayout offer you convenience methods that hide a lot of the complexity of collection views but depending on how the layout you are building should look, keep in mind that all the collection view layout methods can be used as well.

    While the collection view layout works with index paths as its item identifying object, the document view layout does not need multiple levels of indexes. Each layout only needs to deal with one section. The important identifier for a document view layout is the spread index an item is representing. Therefore all the methods a PSPDFDocumentViewLayout and its subclasses offer refer to the spread index instead of an index path. For most layouts you will not come into contact with any of the index path based methods, but in case you do need them, PSPDFKit offers you two new methods on NSIndexPath to easily convert between index paths and spread indexes: +[NSIndexPath pspdf_indexPathForSpreadAtIndex:] and -[NSIndexPath pspdf_spreadIndex]. You should always use these methods to convert back and forth between spread indexes and index paths and not make any assumptions about how an index path maps to a spread index.

    Additional APIs

    Aside from the collection view layout, a document view layout also offers a few additional things that the document view controller and its views use to determine other behaviors, such as how zooming behaves (spreadBasedZooming), how spreads map to pages, and how the actual view hierarchy is positioned in relation to the view controller’s view (scrollViewFrameInsets).

    Make sure to use the methods PSPDFDocumentViewLayout and its subclasses offer instead of just implementing everything by overriding the collection view layout methods. If you override one of the collection view layout methods, it is up to you to make sure that other methods such as spreadIndexForPageAtIndex:, pageRangeForSpreadAtIndex:, continuousSpreadIndexForContentOffset:, or contentOffsetForContinuousSpreadIndex: don’t return conflicting values or otherwise you might get unexpected results.

    See more

    Declaration

    Objective-C

    
    @interface PSPDFDocumentViewLayout : UICollectionViewLayout

    Swift

    class PDFDocumentViewLayout : UICollectionViewLayout
  • The stack view layout produces a similar look than a UIStackView. It lays out its content either in a vertical or horizontal line.

    By default all items in a stack view layout have the same size and this size is deduced from the viewport of the layout.

    Note

    A stack view layout can only be used in a document view. It will not work properly when assigned to an arbitrary collection view.

    Subclassing

    If you want to create your own document view layout, subclassing PSPDFStackViewLayout is a good starting point. As long as you stick with the general idea that content only expands in one direction, all you need to override to customize the layout is the layoutAttributesForItemAtIndexPath: method. It is used by the other methods that deal with layout attributes.

    If you just want to change the size of items, overriding sizeForSpreadAtIndex: should be enough.

    Make sure when overriding layoutAttributesForItemAtIndexPath: to get the size for each attribute from sizeForSpreadAtIndex: as other parts of the layout are using this as well.

    See more

    Declaration

    Objective-C

    
    @interface PSPDFStackViewLayout : PSPDFDocumentViewLayout

    Swift

    class StackViewLayout : PDFDocumentViewLayout
  • Undocumented

    See more

    Declaration

    Objective-C

    
    @interface PSPDFScrollPerSpreadLayout : PSPDFStackViewLayout

    Swift

    class ScrollPerSpreadLayout : StackViewLayout
  • Undocumented

    See more

    Declaration

    Objective-C

    
    @interface PSPDFContinuousScrollingLayout : PSPDFStackViewLayout

    Swift

    class ContinuousScrollingLayout : StackViewLayout
  • The spread view is responsible for laying out one or multiple page views.

    It ensures the best display for the pages it is responsible for and makes sure pages are shown in the correct order (e.g. respecting the page binding).

    A spread describes a collection of continuous pages that are grouped in a logical container from the layout. E.g. if you have a book, when the book is open you will always see two pages next to each other. These two pages build one spread. If you have a stack of loose paper on the other hand, you always only see one page, so a spread only consists of one page in that example.

    See more

    Declaration

    Objective-C

    
    @interface PSPDFSpreadView : UIView <PSPDFOverridable>

    Swift

    class PDFSpreadView : UIView, Overridable
  • Spread position in the viewport.

    See more

    Declaration

    Objective-C

    enum PSPDFSpreadScrollPosition : NSInteger {}

    Swift

    @frozen enum PSPDFSpreadScrollPosition : Int, @unchecked Sendable