> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/ios/basic-operations/basics/viewer/viewer-configuration-legacy.md).

# Customize a document view controller on iOS

Learn how to customize the legacy PTDocumentViewController class for optimal viewing experience. Explore new developments with PTDocumentController for enhanced functionality. Customize viewer classes

{% hint style="info" %}
**Legacy Viewer**

This guide is for the legacy `PTDocumentViewController` class. This class is no longer being updated. For the best viewing experience and to take advantage of new developments, the `PTDocumentController` should be used. Please see [this guide](/ios/ui-customization/viewer-configuration.md) for information.
{% endhint %}

This article explains how to customize the document viewer classes [`PTDocumentViewController`](https://sdk.apryse.com/api/ios/Classes/PTDocumentViewController.html) and [`PTTabbedDocumentViewController`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html).

Because the document viewer classes are part of the open source Tools UI framework, it is possible to achieve virtually any required modification. That said, it is usually faster and more convenient to configure the viewers via APIs, which this guide describes.

## PTDocumentViewController

![](https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-9aa75e52b3945609e68304121e477b2dd6625259%2Faa266fa7b632db20aea3f1b1f35efc263386ea13-2366x1948.png?alt=media)

The **image on the left** indicates areas that are controllable via the `PTDocumentViewController`'s API. Information on customizing these is available [directly below](https://docs.apryse.com).

The **image on the right** indicates a number of default buttons that create and present new controls. Information on where to look to customize these presented controls can be found in the [component controls table](https://docs.apryse.com).

### 1: Left bar button item

When presented in a `UINavigationController`, the `PTDocumentViewController`'s left bar button item will display the name of the previous view controller's navigation item's [`title`](https://developer.apple.com/uikit/uinavigationitem/1624965-title/) (or, if set, its [`backBarButtonItem`](https://developer.apple.com/uikit/uinavigationitem/1624958-backbarbuttonitem/)). When presented as a `UINavigationController`'s root controller, the space will be empty.

The `PTDocumentViewController`'s left bar button item can be added or replaced as follows:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
let title = NSLocalizedString("Documents", comment: "Go back to the document picker.")
documentViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "title, style: .plain, target: self, action: #selector(self.pressedLeft(_:)))"
...

@objc func pressedLeft(_ item: UIBarButtonItem)
{
    // handle bar button item action
}
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
// e.g. in viewDidLoad
NSString *title = NSLocalizedString(@"Documents", @"Go back to the document picker.");
self.myDocumentViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:self action:@selector(action:)];
...

- (void)action:(UIBarButtonItem *)barButtonItem
{
    // handle bar button item action
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 2: Right bar button items

These buttons, which are contained in the [`rightBarButtonItems`](https://developer.apple.com/uikit/uinavigationitem/1624956-rightbarbuttonitems/) array, are completely customizable. It is possible to

* [Remove (hide) buttons](https://docs.apryse.com)
* [Add buttons](https://docs.apryse.com)
* [Move buttons](https://docs.apryse.com)
* [Change icons](https://docs.apryse.com)

#### Remove buttons

Default buttons can be removed ("hidden") using built-in properties. From left-to-right:

* [`searchButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)searchButtonHidden)
* [`shareButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)shareButtonHidden)
* [`viewerSettingsButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)viewerSettingsButtonHidden)
* [`annotationToolbarButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)annotationToolbarButtonHidden)

For example to hide the share and viewer settings buttons:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
documentViewController.shareButtonHidden = true
documentViewController.viewerSettingsButtonHidden = true
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
documentViewController.shareButtonHidden = YES;
documentViewController.viewerSettingsButtonHidden = YES;
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Add buttons

Buttons can be added by accessing the appropriate BarButtonItem array and adding a button:

Adds a button to the top navigation bar:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// add a button to the top bar
let plusButtonTop = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(self.writeButtonName(_:)))

if let rightItems = documentViewController.navigationItem.rightBarButtonItems {
    documentViewController.navigationItem.rightBarButtonItems = rightItems + [plusButtonTop]
}

// add a button to the right of the page slider
let refreshButtonBottom = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(self.writeButtonName(_:)))

if let bottomItems = documentViewController.thumbnailSliderController.trailingToolbarItems{
    documentViewController.thumbnailSliderController.trailingToolbarItems = bottomItems + [refreshButtonBottom]
}
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
// add a button to the top bar
UIBarButtonItem* plusButtonTop = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(writeButtonName:)];

documentViewController.navigationItem.rightBarButtonItems = [documentViewController.navigationItem.rightBarButtonItems arrayByAddingObject:plusButtonTop];

// add a button to the right of the page slider
UIBarButtonItem* refreshButtonBottom = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(writeButtonName:)];

documentViewController.thumbnailSliderController.trailingToolbarItems = [documentViewController.thumbnailSliderController.trailingToolbarItems arrayByAddingObject:refreshButtonBottom];

-(void)writeButtonName:(UIBarButtonItem*)barButtonItem
{
    NSLog(@"%@ was pressed.", barButtonItem);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Move buttons

The default buttons are all accessible via properties, making it easy to rearrange or move them. The following code swaps the position of the search button and navigation lists button:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
var rightItems = documentViewController.navigationItem.rightBarButtonItems
rightItems?.removeAll(where: { element in element == documentViewController.searchButtonItem })
rightItems?.append(documentViewController.navigationListsButtonItem)

var bottomRightItems:[UIBarButtonItem]? = documentViewController.thumbnailSliderController.trailingToolbarItems
bottomRightItems?.removeAll(where: { element in element as NSObject == documentViewController.navigationListsButtonItem })
bottomRightItems?.append(documentViewController.searchButtonItem)

documentViewController.navigationItem.rightBarButtonItems = rightItems
documentViewController.thumbnailSliderController.trailingToolbarItems = bottomRightItems
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
NSMutableArray* rightItems = [documentViewController.navigationItem.rightBarButtonItems mutableCopy];
[rightItems removeObject:documentViewController.searchButtonItem];
[rightItems addObject:documentViewController.navigationListsButtonItem];

NSMutableArray* bottomRightItems = [documentViewController.thumbnailSliderController.trailingToolbarItems mutableCopy];
[bottomRightItems removeObject:documentViewController.navigationListsButtonItem];
[bottomRightItems addObject:documentViewController.searchButtonItem];

documentViewController.navigationItem.rightBarButtonItems = [rightItems copy];
documentViewController.thumbnailSliderController.trailingToolbarItems = [bottomRightItems copy];
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Change icons

The icons of existing buttons may be changed by creating new `UIBarButtonItems` that have the same target and action as an existing item, and replacing the existing item with the new item:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// new share UIBarButtonItem
let newShareItem = UIBarButtonItem(barButtonSystemItem: .action, target: documentViewController.shareButtonItem.target, action: documentViewController.shareButtonItem.action)

// replace old share UIBarButtonItem with new share UIBarButtonItem
var rightItems = documentViewController.navigationItem.rightBarButtonItems
var index: Int? = (rightItems as NSArray?)?.index(of: documentViewController.shareButtonItem)
rightItems?.removeAll(where: { element in element == documentViewController.shareButtonItem })
rightItems?.insert(newShareItem, at: index ?? 0)

// new search UIBarButtonItem
let newSearchItem = UIBarButtonItem(barButtonSystemItem: .search, target: documentViewController.searchButtonItem.target, action: documentViewController.searchButtonItem.action)

// replace old search UIBarButtonItem with new search UIBarButtonItem
index = (rightItems as NSArray?)?.index(of: documentViewController.searchButtonItem)
rightItems?.removeAll(where: { element in element == documentViewController.searchButtonItem })
rightItems?.insert(newSearchItem, at: index ?? 0)

// update the icons
documentViewController.navigationItem.rightBarButtonItems = rightItems
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
// new share UIBarButtonItem
UIBarButtonItem* newShareItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:documentViewController.shareButtonItem.target action:documentViewController.shareButtonItem.action];

// replace old share UIBarButtonItem with new share UIBarButtonItem
NSMutableArray* rightItems = [documentViewController.navigationItem.rightBarButtonItems mutableCopy];
NSUInteger index = [rightItems indexOfObject:documentViewController.shareButtonItem];
[rightItems removeObject:documentViewController.shareButtonItem];
[rightItems insertObject:newShareItem atIndex:index];

// new search UIBarButtonItem
UIBarButtonItem* newSearchItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:documentViewController.searchButtonItem.target action:documentViewController.searchButtonItem.action];

// replace old search UIBarButtonItem with new search UIBarButtonItem
index = [rightItems indexOfObject:documentViewController.searchButtonItem];
[rightItems removeObject:documentViewController.searchButtonItem];
[rightItems insertObject:newSearchItem atIndex:index];

// update the icons
documentViewController.navigationItem.rightBarButtonItems = [rightItems copy];
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 3: PDFViewCtrl

The `PTPDFViewCtrl` is a `UIView` that displays the PDF. It is customizable via is properties/methods and delegate methods.

For an overview see the [PTPDFViewCtrl Guide ](/ios/basic-operations/basics/viewer/pdfviewctrl.md#customize-a-ptpdfviewctrl), or the detailed [API documentation](https://sdk.apryse.com/api/ios/Classes/PTPDFViewCtrl.html).

Note that all PDF "interaction" (annotations, form filling, text selection, link following, etc.) is supplementary to the PDFViewCtrl, and is implemented in the open source [`tools.framework`](/ios/annotation/overview.md).

### 4: Page number indicator

The page indicator can be enabled/disabled via the [`pageIndicatorEnabled`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)pageIndicatorEnabled) property.

### 5: Thumbnail slider controller

The thumbnail slider can be enabled/disabled via the [`bottomToolbarEnabled`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)bottomToolbarEnabled) property.

The default buttons presented to the right and left of the slider are easily hidden through the convenience properties [`thumbnailBrowserButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)thumbnailBrowserButtonHidden) and [`navigationListsButtonHidden`](https://sdk.apryse.com/api/ios/Classes/PTDocumentBaseViewController.html#/c:objc\(cs\)PTDocumentBaseViewController\(py\)navigationListsButtonHidden) on the `PTDocumentViewController`:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
documentViewController.thumbnailBrowserButtonHidden = true
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
documentViewController.thumbnailBrowserButtonHidden = YES;
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 6-12: Controls Presented by a PTDocumentViewController

To customize the controls that are presented by the `PTDocumentViewController`'s default buttons, please see the corresponding guide or API:

| Image number | Control                                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| 6            | [PTTextSearchViewController](/ios/search/text.md)                                                            |
| 7            | [`UIDocumentInteractionController`](https://developer.apple.com/uikit/uidocumentinteractioncontroller/)      |
| 8            | [`PTSettingsViewController`](https://sdk.apryse.com/api/ios/Classes/PTSettingsViewController.html)           |
| 9            | [`PTAnnotationToolbar`](/ios/annotation/annotation-toolbar-i.md#customization)                               |
| 10           | [`PTPageIndicatorViewController`](https://sdk.apryse.com/api/ios/Classes/PTPageIndicatorViewController.html) |
| 11           | [`PTThumbnailSliderViewController`](/ios/ui-customization/thumbnail-slider-i.md#customization)               |
| 12           | [`PTNavigationListsViewController`](/ios/ui-customization/navigation-lists.md#customization)                 |

## PTTabbedDocumentViewController

The [tabbed document view controller](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html) displays a collection of [document viewer controllers](https://sdk.apryse.com/api/ios/Classes/PTDocumentViewController.html) in tabs.

### Tab Settings

Tabs can be disabled using the [`tabsEnabled`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)tabsEnabled) property, and the maximum number of allowed tabs can be set using [`maximumTabCount`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)maximumTabCount).

### Access to child PTDocumentViewControllers

The current document view controller can be accessed via [`selectedViewController`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)selectedViewController), and others via [`documentViewController(at:)`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(im\)documentViewControllerAtIndex:)

To configure a document view controller before it is displayed, conform to and implement the [`PTTabbedDocumentViewControllerDelegate`](https://sdk.apryse.com/api/ios/Protocols/PTTabbedDocumentViewControllerDelegate.html#/c:objc\(pl\)PTTabbedDocumentViewControllerDelegate\(im\)tabbedDocumentViewController:willAddDocumentViewController:) method [`tabbedDocumentViewController(_:willAdd:)`](https://sdk.apryse.com/api/ios/Protocols/PTTabbedDocumentViewControllerDelegate.html#/c:objc\(pl\)PTTabbedDocumentViewControllerDelegate\(im\)tabbedDocumentViewController:willAddDocumentViewController:). Note that it **is** permissible to assign the internal `PTDocumentViewController`'s delegate to an external object.

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
func tabbedDocumentViewController(_ tabbedDocumentViewController: PTTabbedDocumentViewController, willAdd documentViewController: PTDocumentViewController) {
        documentViewController.delegate = self
        // customize documentViewController
    }
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
-(void)tabbedDocumentViewController:(PTTabbedDocumentViewController *)tabbedDocumentViewController willAddDocumentViewController:(PTDocumentViewController *)documentViewController
{
    documentViewController.delegate = self;
    // customize documentViewController
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Summary

| API                                                                                                                                                                                                                                                     | Functionality                                                         |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [`tabsEnabled`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)tabsEnabled)                                                                                                | Enables/disables tabs.                                                |
| [`maximumTabCount`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)maximumTabCount)                                                                                        | Controls the maximum number of concurrent tabs.                       |
| [`selectedViewController`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(py\)selectedViewController)                                                                          | The current `PTDocumentViewController`.                               |
| [`documentViewController(at:)`](https://sdk.apryse.com/api/ios/Classes/PTTabbedDocumentViewController.html#/c:objc\(cs\)PTTabbedDocumentViewController\(im\)documentViewControllerAtIndex:)                                                             | The `PTDocumentViewController` at the given index.                    |
| [`tabbedDocumentViewController(_:willAdd:)`](https://sdk.apryse.com/api/ios/Protocols/PTTabbedDocumentViewControllerDelegate.html#/c:objc\(pl\)PTTabbedDocumentViewControllerDelegate\(im\)tabbedDocumentViewController:willAddDocumentViewController:) | Access to a `PTDocumentViewController` that is about to be displayed. |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/ios/basic-operations/basics/viewer/viewer-configuration-legacy.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
