> 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/ui-customization/adding-a-uiview-to-a-pdf-page.md).

# Add a UIView to a PDF page

Learn how to reposition views in PTPDFViewCtrl when the PDF page shifts due to changes like zooming or presentation mode. Implement delegate methods pdfScrollViewDidEndZooming and onLayoutChanged for

This guide demonstrates how to make a \`UIView\` appear as if it is stuck to a page.

It is convenient for the user to make a `UIView` that is "stuck" to a page record its desired page location. To do this, you could add an extension/category to a `UIView`, or use a derived class, as shown below:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
public class FloatingView : UIView
{
    public FloatingView() : base()
    {
        
    }
    
    public int PageNumber { get; set; }

    public pdftron.PDF.Rect PdfPageRect { get; set; }
}
```

{% endcode %}
{% endtab %}

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

```swift
class FloatingView: UIView {
    // the page on which the UIView appears
    
    var pageNumber: Int32 = 0
    // the location, expressed in PDF coordinates, at which the view appears
    var pdfPageRect: PTPDFRect?
}
```

{% endcode %}
{% endtab %}

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

```objc
@interface FloatingView : UIView
// the page on which the UIView appears
@property (assign, nonatomic) int pageNumber;
// the location, expressed in PDF coordinates, at which the view appears
@property (strong, nonatomic) PTPDFRect* pdfPageRect;
@end
@implementation FloatingView
@end
```

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

<figure><img src="https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-8929a6dcdaf574fd314aa5906d48b025658c6373%2F6a1904fb2338f346c43385c570e3851499992dcb-746x1057.png?alt=media" alt=""><figcaption><p>A red `UIView` positioned near the bottom left hand corner of the first page.</p></figcaption></figure>

In this example, we will add a red square to a location near the bottom left hand corner of the first page:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
var mCustomView = new FloatingView();
mCustomView.BackgroundColor = UIColor.Red;
mCustomView.PageNumber = 1;
mCustomView.PdfPageRect = new Rect(10, 10, 100, 100);
mPdfViewCtrl.OverlayView.AddSubview(mCustomView);

// position the view
positionFloatingViews();
```

{% endcode %}
{% endtab %}

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

```swift
// prepare the new view
let redRect = FloatingView()
redRect.backgroundColor = UIColor.red
redRect.pageNumber = 1
redRect.pdfPageRect = PTPDFRect(x1: 10, y1: 10, x2: 100, y2: 100)
// add the view to PTPDFViewCtrl's overlayView
self.pdfViewCtrl.overlayView.addSubview(redRect)
// position the view
positionFloatingViews()
```

{% endcode %}
{% endtab %}

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

```objc
// prepare the new view
FloatingView* redRect = [[FloatingView alloc] init];
[redRect setBackgroundColor:[UIColor redColor]];
redRect.pageNumber = 1;
redRect.pdfPageRect = [[PTPDFRect alloc] initWithX1:10 y1:10 x2:100 y2:100];
// add the view to PTPDFViewCtrl's overlayView
[self.pdfViewCtrl.overlayView addSubview:redRect];
// position the view
[self positionFloatingViews];
```

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

Without the last line in the code snippet above, the new view would not appear in the correct location. The following method will position it, and any others that have been added:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
void positionFloatingViews()
{
    foreach (UIView view in mPdfViewCtrl.OverlayView.Subviews)
    {
        if (view is FloatingView)
        {
            var overlayView = view as FloatingView;
            bool pageHidden = false;
            if (!mPdfViewCtrl.PagePresentationModeIsContinuous)
            {
                pageHidden = !mPdfViewCtrl.PageIsOnScreen(overlayView.PageNumber);
            }
            overlayView.Hidden = pageHidden;
            CGRect screenRect = mPdfViewCtrl.PDFRectPage2CGRectScreen(TypeConvertHelper.ConvRectToNative(overlayView.PdfPageRect), overlayView.PageNumber);
            screenRect.X += (nfloat)mPdfViewCtrl.GetHScrollPos();
            screenRect.Y += (nfloat)mPdfViewCtrl.GetVScrollPos();
            overlayView.Frame = screenRect;
        }
    }
}
```

{% endcode %}
{% endtab %}

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

```swift
func positionFloatingViews() {
    for case let overlayView as FloatingView in self.pdfViewCtrl.overlayView.subviews {
        // make sure this is a floating view
        if type(of: overlayView) === FloatingView.self {
            var pageHidden = false
            if !pdfViewCtrl.pagePresentationModeIsContinuous() {
                pageHidden = !pdfViewCtrl.pageIs(onScreen: overlayView.pageNumber)
            }
            overlayView.isHidden = pageHidden
            var screenRect: CGRect = pdfViewCtrl.pdfRectPage2CGRectScreen(overlayView.pdfPageRect, pageNumber: overlayView.pageNumber)
            screenRect.origin.x += CGFloat(pdfViewCtrl.getHScrollPos())
            screenRect.origin.y += CGFloat(pdfViewCtrl.getVScrollPos())
            overlayView.frame = screenRect
        }
    }
}
```

{% endcode %}
{% endtab %}

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

```objc
-(void)positionFloatingViews
{
    for(FloatingView* overlayView in self.pdfViewCtrl.overlayView.subviews)
    {
        // make sure this is a floating view
        if( [overlayView isMemberOfClass:[FloatingView class]])
        {
            BOOL pageHidden = NO;
            if( ![self.pdfViewCtrl pagePresentationModeIsContinuous] )
            {
                pageHidden = ![self.pdfViewCtrl pageIsOnScreen:overlayView.pageNumber];
            }
            overlayView.hidden = pageHidden;
            CGRect screenRect = [self.pdfViewCtrl PDFRectPage2CGRectScreen:overlayView.pdfPageRect PageNumber:overlayView.pageNumber];
            screenRect.origin.x += [self.pdfViewCtrl GetHScrollPos];
            screenRect.origin.y += [self.pdfViewCtrl GetVScrollPos];
            overlayView.frame = screenRect;
        }
    }
}
```

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

Whenever the PDF page shifts within the [`PTPDFViewCtrl`](https://sdk.apryse.com/api/ios/Classes/PTPDFViewCtrl.html), which may happen when changing the page presentation mode, zooming, and such, the views need to be re-positioned (`positionFloatingViews` needs to run again). To do this, implement the `PTPDFViewCtrl` delegate methods [`pdfScrollViewDidEndZooming:`](https://sdk.apryse.com/api/ios/Protocols/PTPDFViewCtrlDelegate.html#/c:objc\(pl\)PTPDFViewCtrlDelegate\(im\)pdfScrollViewDidZoom:) and [`onLayoutChanged`](https://sdk.apryse.com/api/ios/Protocols/PTPDFViewCtrlDelegate.html#/c:objc\(pl\)PTPDFViewCtrlDelegate\(im\)onLayoutChanged), and in them, call `positionFloatingViews`:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
mPdfViewCtrl.PdfViewCtrlOnLayoutChanged += (sender, e) =>
{
    positionFloatingViews();
};
mPdfViewCtrl.PdfScrollViewDidEndZooming += (sender, e) =>
{
    positionFloatingViews();
};
```

{% endcode %}
{% endtab %}

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

```swift
func pdfViewCtrl(onLayoutChanged pdfViewCtrl: PTPDFViewCtrl!) {
    positionFloatingViews()
}
func pdfViewCtrl(_ pdfViewCtrl: PTPDFViewCtrl!, pdfScrollViewDidEndZooming scrollView: UIScrollView!, with view: UIView!, atScale scale: Float) {
    positionFloatingViews()
}
```

{% endcode %}
{% endtab %}

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

```objc
-(void)pdfViewCtrlOnLayoutChanged:(PTPDFViewCtrl *)pdfViewCtrl
{
    [self positionFloatingViews];
}
-(void)pdfViewCtrl:(PTPDFViewCtrl *)pdfViewCtrl pdfScrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    [self positionFloatingViews];
}
```

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


---

# 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/ui-customization/adding-a-uiview-to-a-pdf-page.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.
