Skip to content

Commit 483592d

Browse files
committed
feat: add annotation rendering support (Phase 7.1)
- Add EnableAnnotationRendering property (default: true) - Android: Full control via enableAnnotationRendering() configurator - Separated annotation rendering from link navigation - Triggers document reload when changed after load - Preserves current page on reload - iOS: Controls annotation display via ShouldDisplay property - Iterates through all page annotations and sets visibility - Forces view refresh to update display immediately - Fully functional toggle on both platforms - Add full property mapping in handlers for both platforms - Sample app: Add PDF with annotations for testing - Sample app: Add UI toggle button to enable/disable annotations - Update documentation with Phase 7.1 complete status
1 parent d312349 commit 483592d

9 files changed

Lines changed: 163 additions & 11 deletions

File tree

FEATURE_ENHANCEMENT_PLAN.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ We aim to provide a consistent API across iOS and Android wherever reasonably po
4545
| Best quality (ARGB_8888) || ✅ (default) || ✅ Phase 4 Complete |
4646
| Background color |||| ✅ Phase 4 Complete |
4747
| **Annotations & Rendering** | | | | |
48-
| Annotation rendering || ✅ (default) | |To Add (Phase 7) |
48+
| Annotation rendering || ✅ (default) | | ✅ Phase 7 Complete |
4949
| Password protection |||| ✅ Phase 5.2 Complete |
5050
| Custom drawing (onDraw) |||| **Advanced Feature** |
5151
| Custom drawing all pages |||| **Advanced Feature** |
@@ -167,11 +167,21 @@ We aim to provide a consistent API across iOS and Android wherever reasonably po
167167

168168
**Goal:** Enable PDF annotation rendering and basic interaction
169169

170-
#### 7.1 Annotation Rendering
171-
- Add `EnableAnnotationRendering` property
172-
- Render PDF annotations, forms, comments
173-
- **Android:** Use `enableAnnotationRendering()` configurator
174-
- **iOS:** Enabled by default, add toggle if possible
170+
**Status:** Phase 7.1 complete - Annotation rendering implemented
171+
172+
#### 7.1 Annotation Rendering ✅ **COMPLETE**
173+
- ✅ Added `EnableAnnotationRendering` property (default: true)
174+
-**Android:** Uses `enableAnnotationRendering()` configurator
175+
- Separated from link navigation (previously bundled)
176+
- Triggers document reload when changed
177+
- Preserves current page on reload
178+
-**iOS:** Controls annotation display via `ShouldDisplay` property
179+
- Iterates through all page annotations and sets visibility
180+
- Forces view refresh to update display
181+
- Fully functional toggle on both platforms
182+
- ✅ Property mapping on both platforms
183+
- ✅ Sample app includes PDF with annotations for testing
184+
- ✅ Merged to main
175185

176186
#### 7.2 Annotation Events
177187
- Add `AnnotationTappedEventArgs` with annotation details
@@ -318,9 +328,10 @@ For each phase:
318328
| Phase 5.1 | Display Mode | 0.5 days | ✅ Complete |
319329
| Phase 5.2 | Password Support | 0.5 days | ✅ Complete |
320330
| Phase 6 | Document Metadata | N/A | ❌ Cancelled |
321-
| Phase 7 | Annotations | 1 day | 📋 Planned |
331+
| Phase 7.1 | Annotation Rendering | 0.5 days | ✅ Complete |
332+
| Phase 7.2 | Annotation Events | 0.5 days | 📋 Planned |
322333

323-
**Total remaining**: ~1 day for Phase 7
334+
**Total remaining**: ~0.5 days for Phase 7.2
324335
**Notes:**
325336
- Night Mode feature removed from scope (iOS incompatibility)
326337
- Enhanced Metadata feature cancelled (Android library bug)

samples/MauiPdfViewerSample/PdfTestPage.xaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
<Button x:Name="LoadFileButton"
1919
Text="Load Sample PDF"
2020
Clicked="OnLoadFileClicked" />
21+
<Button x:Name="LoadAnnotationFileButton"
22+
Text="Load Annotations PDF"
23+
Clicked="OnLoadAnnotationFileClicked" />
2124
<Button x:Name="PrevPageButton"
2225
Text="◀ Prev"
2326
Clicked="OnPrevPageClicked"
@@ -48,6 +51,14 @@
4851
Text="Single Page Continuous"
4952
Clicked="OnToggleDisplayModeClicked" />
5053
</HorizontalStackLayout>
54+
55+
<!-- New Phase 7 Features -->
56+
<HorizontalStackLayout Spacing="10" HorizontalOptions="Center">
57+
<Label Text="Annotations:" VerticalOptions="Center" />
58+
<Button x:Name="ToggleAnnotationsButton"
59+
Text="Enabled"
60+
Clicked="OnToggleAnnotationsClicked" />
61+
</HorizontalStackLayout>
5162
</VerticalStackLayout>
5263

5364
<!-- PDF Viewer -->
@@ -61,6 +72,7 @@
6172
PageSpacing="10"
6273
EnableAntialiasing="True"
6374
UseBestQuality="True"
75+
EnableAnnotationRendering="True"
6476
DocumentLoaded="OnDocumentLoaded"
6577
PageChanged="OnPageChanged"
6678
Error="OnError"

samples/MauiPdfViewerSample/PdfTestPage.xaml.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ private void OnLoadFileClicked(object? sender, EventArgs e)
4646
}
4747
}
4848

49+
private void OnLoadAnnotationFileClicked(object? sender, EventArgs e)
50+
{
51+
try
52+
{
53+
StatusLabel.Text = "Loading PDF with annotations...";
54+
55+
// Load PDF with annotations from raw asset
56+
PdfViewer.Source = PdfSource.FromAsset("sample_with_annotations.pdf");
57+
}
58+
catch (Exception ex)
59+
{
60+
StatusLabel.Text = $"Error: {ex.Message}";
61+
DisplayAlert("Error", $"Failed to load PDF: {ex.Message}", "OK");
62+
}
63+
}
64+
4965
private void OnPrevPageClicked(object? sender, EventArgs e)
5066
{
5167
if (PdfViewer.CurrentPage > 0)
@@ -129,4 +145,12 @@ private void OnToggleDisplayModeClicked(object? sender, EventArgs e)
129145
ToggleDisplayModeButton.Text = _displayModeNames[_displayModeIndex];
130146
StatusLabel.Text = $"Display mode: {_displayModeNames[_displayModeIndex]}";
131147
}
148+
149+
// New Phase 7 event handler
150+
private void OnToggleAnnotationsClicked(object? sender, EventArgs e)
151+
{
152+
PdfViewer.EnableAnnotationRendering = !PdfViewer.EnableAnnotationRendering;
153+
ToggleAnnotationsButton.Text = PdfViewer.EnableAnnotationRendering ? "Enabled" : "Disabled";
154+
StatusLabel.Text = $"Annotation rendering: {(PdfViewer.EnableAnnotationRendering ? "Enabled" : "Disabled")}";
155+
}
132156
}

src/MauiNativePdfView/Abstractions/IPdfView.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ public interface IPdfView
9090
/// </summary>
9191
Color? BackgroundColor { get; set; }
9292

93+
/// <summary>
94+
/// Gets or sets whether PDF annotations (forms, comments, highlights, etc.) should be rendered.
95+
/// On Android: Controls whether annotations are displayed.
96+
/// On iOS: Always enabled (PdfKit renders annotations by default).
97+
/// </summary>
98+
bool EnableAnnotationRendering { get; set; }
99+
93100
/// <summary>
94101
/// Occurs when the document has finished loading.
95102
/// </summary>

src/MauiNativePdfView/PdfView.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ public class PdfView : View
158158
typeof(PdfView),
159159
null);
160160

161+
/// <summary>
162+
/// Bindable property for annotation rendering.
163+
/// </summary>
164+
public static readonly BindableProperty EnableAnnotationRenderingProperty =
165+
BindableProperty.Create(
166+
nameof(EnableAnnotationRendering),
167+
typeof(bool),
168+
typeof(PdfView),
169+
true);
170+
161171
/// <summary>
162172
/// Gets or sets the PDF source to display.
163173
/// </summary>
@@ -293,6 +303,17 @@ public bool UseBestQuality
293303
set => SetValue(BackgroundColorProperty, value);
294304
}
295305

306+
/// <summary>
307+
/// Gets or sets whether PDF annotations (forms, comments, highlights, etc.) should be rendered.
308+
/// On Android: Controls whether annotations are displayed.
309+
/// On iOS: Always enabled (PdfKit renders annotations by default).
310+
/// </summary>
311+
public bool EnableAnnotationRendering
312+
{
313+
get => (bool)GetValue(EnableAnnotationRenderingProperty);
314+
set => SetValue(EnableAnnotationRenderingProperty, value);
315+
}
316+
296317
/// <summary>
297318
/// Gets the current page number (0-based).
298319
/// </summary>

src/MauiNativePdfView/Platforms/Android/PdfViewAndroid.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class PdfViewAndroid : IPdfView, IDisposable
3232
private bool _enableAntialiasing = true;
3333
private bool _useBestQuality = true;
3434
private Color? _backgroundColor;
35+
private bool _enableAnnotationRendering = true;
3536
private int _currentPage = 0;
3637
private int _pageCount = 0;
3738

@@ -215,6 +216,20 @@ public Color? BackgroundColor
215216
}
216217
}
217218

219+
public bool EnableAnnotationRendering
220+
{
221+
get => _enableAnnotationRendering;
222+
set
223+
{
224+
if (_enableAnnotationRendering != value)
225+
{
226+
_enableAnnotationRendering = value;
227+
if (_pageCount > 0) // Document is loaded
228+
Reload();
229+
}
230+
}
231+
}
232+
218233
public event EventHandler<DocumentLoadedEventArgs>? DocumentLoaded;
219234
public event EventHandler<PageChangedEventArgs>? PageChanged;
220235
public event EventHandler<PdfErrorEventArgs>? Error;
@@ -298,10 +313,14 @@ private void ConfigureAndLoad(PDFView.Configurator configurator, int pageToResto
298313
// Note: UseBestQuality sets rendering quality (ARGB_8888 vs RGB_565)
299314
// This is handled by the PDFView configuration automatically based on device capabilities
300315

316+
if (_enableAnnotationRendering)
317+
{
318+
configurator.EnableAnnotationRendering(true);
319+
}
320+
301321
if (_enableLinkNavigation)
302322
{
303-
configurator.EnableAnnotationRendering(true)
304-
.LinkHandler(new LinkHandlerImpl(this));
323+
configurator.LinkHandler(new LinkHandlerImpl(this));
305324
}
306325

307326
configurator.Load();

src/MauiNativePdfView/Platforms/Android/PdfViewHandler.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public partial class PdfViewHandler : ViewHandler<PdfView, PDFView>
3333
[nameof(PdfView.EnableAntialiasing)] = MapEnableAntialiasing,
3434
[nameof(PdfView.UseBestQuality)] = MapUseBestQuality,
3535
[nameof(PdfView.BackgroundColor)] = MapBackgroundColor,
36+
[nameof(PdfView.EnableAnnotationRendering)] = MapEnableAnnotationRendering,
3637
};
3738

3839
/// <summary>
@@ -263,6 +264,14 @@ private static void MapBackgroundColor(PdfViewHandler handler, PdfView view)
263264
}
264265
}
265266

267+
private static void MapEnableAnnotationRendering(PdfViewHandler handler, PdfView view)
268+
{
269+
if (handler._pdfViewWrapper != null)
270+
{
271+
handler._pdfViewWrapper.EnableAnnotationRendering = view.EnableAnnotationRendering;
272+
}
273+
}
274+
266275
#endregion
267276

268277
#region Command Mappers

src/MauiNativePdfView/Platforms/iOS/PdfViewHandler.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public partial class PdfViewHandler : ViewHandler<PdfView, PdfKit.PdfView>
2727
[nameof(PdfView.DefaultPage)] = MapDefaultPage,
2828
[nameof(PdfView.EnableAntialiasing)] = MapEnableAntialiasing,
2929
[nameof(PdfView.UseBestQuality)] = MapUseBestQuality,
30-
[nameof(PdfView.BackgroundColor)] = MapBackgroundColor
30+
[nameof(PdfView.BackgroundColor)] = MapBackgroundColor,
31+
[nameof(PdfView.EnableAnnotationRendering)] = MapEnableAnnotationRendering
3132
};
3233

3334
public static CommandMapper<PdfView, PdfViewHandler> CommandMapper = new(ViewCommandMapper)
@@ -252,6 +253,14 @@ public static void MapBackgroundColor(PdfViewHandler handler, PdfView view)
252253
}
253254
}
254255

256+
public static void MapEnableAnnotationRendering(PdfViewHandler handler, PdfView view)
257+
{
258+
if (handler._pdfViewWrapper != null)
259+
{
260+
handler._pdfViewWrapper.EnableAnnotationRendering = view.EnableAnnotationRendering;
261+
}
262+
}
263+
255264
public static void MapGoToPage(PdfViewHandler handler, PdfView view, object? args)
256265
{
257266
if (handler._pdfViewWrapper != null && args is int pageIndex)

src/MauiNativePdfView/Platforms/iOS/PdfViewiOS.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class PdfViewiOS : IPdfView, IDisposable
1818
private PdfScrollOrientation _scrollOrientation = PdfScrollOrientation.Vertical;
1919
private int _defaultPage = 0;
2020
private bool _documentLoaded = false;
21+
private bool _enableAnnotationRendering = true;
2122

2223
public PdfViewiOS()
2324
{
@@ -202,6 +203,19 @@ public Color? BackgroundColor
202203
}
203204
}
204205

206+
public bool EnableAnnotationRendering
207+
{
208+
get => _enableAnnotationRendering;
209+
set
210+
{
211+
if (_enableAnnotationRendering != value)
212+
{
213+
_enableAnnotationRendering = value;
214+
UpdateAnnotationVisibility();
215+
}
216+
}
217+
}
218+
205219
public event EventHandler<DocumentLoadedEventArgs>? DocumentLoaded;
206220
public event EventHandler<PageChangedEventArgs>? PageChanged;
207221
public event EventHandler<PdfErrorEventArgs>? Error;
@@ -339,6 +353,9 @@ private void LoadDocument()
339353
var currentPageIndex = _defaultPage > 0 && _defaultPage < pageCount ? _defaultPage : 0;
340354
PageChanged?.Invoke(this, new PageChangedEventArgs(currentPageIndex, pageCount));
341355

356+
// Apply annotation visibility setting
357+
UpdateAnnotationVisibility();
358+
342359
// Fire rendered event after a short delay to ensure rendering is complete
343360
if (!_documentLoaded)
344361
{
@@ -363,6 +380,29 @@ private void LoadDocument()
363380
}
364381
}
365382

383+
private void UpdateAnnotationVisibility()
384+
{
385+
if (_pdfView.Document == null)
386+
return;
387+
388+
// Iterate through all pages and hide/show annotations
389+
for (nint i = 0; i < _pdfView.Document.PageCount; i++)
390+
{
391+
var page = _pdfView.Document.GetPage(i);
392+
if (page?.Annotations != null)
393+
{
394+
foreach (var annotation in page.Annotations)
395+
{
396+
// Set annotation to hidden or visible
397+
annotation.ShouldDisplay = _enableAnnotationRendering;
398+
}
399+
}
400+
}
401+
402+
// Force refresh the view
403+
_pdfView.SetNeedsDisplay();
404+
}
405+
366406
private void OnPageChangedNotification(NSNotification notification)
367407
{
368408
if (_pdfView.Document != null && _pdfView.CurrentPage != null)

0 commit comments

Comments
 (0)