Before you get started, we recommend you have a look at Microsoft's comprehensive guide on Customizing a ContentPage. It is important that you understand how Xamarin renders the same page on different platforms using ContentPage
, ExportRenderer
and PageRenderer
. In this guide, you will learn how to create a fully featured document viewer and editor as page renderer on each platform.
Complete sample code can be found here:
The rendering process can be taken advantage of to implement platform-specific customization by creating a custom renderer for a ContentPage
on each platform. The process for doing this is as follows:
- Create a Xamarin.Forms page.
- Consume the page from Xamarin.Forms.
- Create the custom renderer for the page on each platform.
An unaltered ContentPage
can be added to the shared Xamarin.Forms project, as shown in the following XAML code example:
XAML
1<?xml version="1.0" encoding="utf-8" ?>
2<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="CustomRenderer.AdvancedViewerPage" Title="Advanced Viewer Page">
3 <ContentPage.Content>
4 </ContentPage.Content>
5</ContentPage>
Similarly, the code-behind file for the ContentPage
should also remain unaltered, as shown in the following code example:
C#
1public partial class AdvancedViewerPage : ContentPage
2 {
3 public AdvancedViewerPage()
4 {
5 // Document viewer contains toolbar, let's hide the global one
6 NavigationPage.SetHasNavigationBar(this, false);
7 InitializeComponent();
8 }
9 }
An instance of the AdvancedViewerPage
will be used to display document viewer on each platform. Customization of the control will be carried out in the custom renderer, so no additional implementation is required in the AdvancedViewerPage
class.
The empty AdvancedViewerPage
must be displayed by the Xamarin.Forms application. This occurs when a button on the MainPage
instance is tapped, which in turn executes the OnOpenAdvancedViewerButtonClicked
method, as shown in the following code example:
C#
1async void OnOpenAdvancedViewerButtonClicked(object sender, EventArgs e)
2{
3 await Navigation.PushAsync(new AdvancedViewerPage());
4}
This code simply navigates to the AdvancedViewerPage
, on which custom renderers will customize the page's appearance on each platform.
The AdvancedViewerPage
instance is rendered by platform-specific AdvancedViewerPageRenderer
classes, which all derive from the PageRenderer
class for that platform. This results in each AdvancedViewerPage
instance being rendered with document viewer, as shown in the following GIF:
Create the Page Renderer on iOS
The following code example shows the page renderer for the iOS platform:
C#
1[assembly: ExportRenderer(typeof(AdvancedViewerPage), typeof(AdvancedViewerPageRenderer))]
2namespace CustomRenderer.iOS
3{
4 public class AdvancedViewerPageRenderer : PageRenderer
5 {
6 private PTTabbedDocumentViewController mTabViewController;
7
8 protected override void OnElementChanged(VisualElementChangedEventArgs e)
9 {
10 base.OnElementChanged(e);
11
12 if (e.OldElement != null || Element == null)
13 {
14 return;
15 }
16
17 try
18 {
19 SetupUserInterface();
20 SetupEventHandlers();
21 }
22 catch (Exception ex)
23 {
24 System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
25 }
26 }
27
28 //...
29 }
30}
where the document viewer can be setup as follows:
C#
1void SetupUserInterface()
2{
3 mTabViewController = new PTTabbedDocumentViewController();
4 UINavigationController navigationController = new UINavigationController(mTabViewController);
5
6 AddChildViewController(navigationController);
7
8 View.AddSubview(navigationController.View);
9
10 navigationController.DidMoveToParentViewController(this);
11
12 NSUrl fileURL = NSBundle.MainBundle.GetUrlForResource("sample", "pdf");
13
14 mTabViewController.OpenDocumentWithURL(fileURL);
15}
Create the Page Renderer on Android
The following code example shows the page renderer for the Android platform:
C#
1[assembly: ExportRenderer(typeof(AdvancedViewerPage), typeof(AdvancedViewerPageRenderer))]
2namespace CustomRenderer.Droid
3{
4 public class AdvancedViewerPageRenderer : PageRenderer
5 {
6 private DocumentView mDocumentView;
7
8 public ViewerPageRenderer(Context context) : base(context)
9 {
10 }
11
12 protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
13 {
14 base.OnElementChanged(e);
15
16 if (e.OldElement != null || Element == null)
17 {
18 return;
19 }
20
21 try
22 {
23 SetupUserInterface();
24 SetupEventHandlers();
25 AddView(view);
26 }
27 catch (Exception ex)
28 {
29 System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
30 }
31 }
32
33 //...
34 }
35}
where the document viewer can be setup as follows:
C#
1void SetupUserInterface()
2{
3 activity = this.Context as Activity;
4 view = activity.LayoutInflater.Inflate(Resource.Layout.AdvancedViewerLayout, this, false);
5
6 mDocumentView = view.FindViewById<DocumentView>(Resource.Id.document_view);
7
8 var context = this.Context;
9 FragmentManager childManager = null;
10 if (context is AppCompatActivity)
11 {
12 var activity = context as AppCompatActivity;
13 var manager = activity.SupportFragmentManager;
14
15 var fragments = manager.Fragments;
16 if (fragments.Count > 0)
17 {
18 childManager = fragments[0].ChildFragmentManager;
19 }
20 if (childManager != null)
21 {
22 mDocumentView.OpenDocument(GetFile(), "", GetConfig(), childManager);
23 }
24 }
25}
Click here for DocumentView
class implementation.
The document viewer is highly customizable and can be configured to remove/modify many components.
- For Android please see this guide.
- For iOS, please see this guide.
Try out the complete sample here: https://github.com/ApryseSDK/xamarin-forms-sample.