Annotations show additional information in a document. PDF annotations can be grouped and showcased in a list view at the application level based on the pages in which they are present. We can also easily navigate to the selected annotations in a PDF.
In this blog, we will see how to showcase the annotations in a list view and navigate to them based on our selection using our Syncfusion Xamarin PDF Viewer control.
Create a Xamarin app and add dependencies
First, create a new Xamarin app and install the following NuGet packages in it:
Create a list view item data template
Then, create a content view in the ListViewItem.xaml file to display the annotations data with the name and corresponding icon in each list view cell.
Refer to the following code example.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AnnotationsListView.ListViewItem">
<ContentView.Content>
<StackLayout HeightRequest="40" Orientation="Horizontal">
<Label x:Name="annotationFontIcon" Margin="10,0,0,0" VerticalOptions="Center" InputTransparent="true" BackgroundColor="Transparent" TextColor="#0076FF" FontSize="16"/>
<Label x:Name="annotationLabel" FontSize="Medium" TextColor="Black" Padding="10,0,0,0" VerticalOptions="Center"/>
</StackLayout>
</ContentView.Content>
</ContentView>
Add the annotation name and its corresponding icon when the list view item’s binding context changes. This logic can be implemented in the ListViewItem partial class in the ListViewItem.xaml.cs file.
Refer to the following code example.
public partial class ListViewItem : ContentView
{
public ListViewItem()
{
InitializeComponent();
BindingContextChanged += ListViewItem_BindingContextChanged;
}
private void ListViewItem_BindingContextChanged(object sender, EventArgs e)
{
if (BindingContext == null)
return;
annotationFontIcon.FontFamily = FontMappingHelper.FontFamily;
if (BindingContext is ShapeAnnotation annotation)
{
annotationLabel.Text = annotation.ShapeAnnotationType.ToString();
if (annotation.ShapeAnnotationType == ShapeAnnotationType.Line)
{
annotationFontIcon.Text = FontMappingHelper.Line;
}
else if (annotation.ShapeAnnotationType == ShapeAnnotationType.Rectangle)
{
annotationFontIcon.Text = FontMappingHelper.Rectangle;
}
else if (annotation.ShapeAnnotationType == ShapeAnnotationType.Circle)
{
annotationFontIcon.Text = FontMappingHelper.Circle;
}
else if (annotation.ShapeAnnotationType == ShapeAnnotationType.Arrow)
{
annotationFontIcon.Text = FontMappingHelper.Arrow;
}
else if (annotation.ShapeAnnotationType == ShapeAnnotationType.Polygon)
{
annotationFontIcon.Text = FontMappingHelper.Polygon;
}
}
else if (BindingContext is TextMarkupAnnotation textMarkup)
{
annotationLabel.Text = textMarkup.TextMarkupAnnotationType.ToString();
if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Highlight)
{
annotationFontIcon.Text = FontMappingHelper.Highlight;
}
else if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Strikethrough)
{
annotationFontIcon.Text = FontMappingHelper.StrikeThrough;
}
else if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Underline)
{
annotationFontIcon.Text = FontMappingHelper.Underline;
}
}
else if (BindingContext is FreeTextAnnotation freeText)
{
annotationLabel.Text = "Free Text";
annotationFontIcon.Text = FontMappingHelper.EditText;
}
else if (BindingContext is InkAnnotation ink)
{
annotationLabel.Text = "Ink";
annotationFontIcon.Text = FontMappingHelper.Ink;
}
}
}
In the following code example, the FontMappingHelper class represents the font icon text for the available annotations.
/// <summary>
/// Represents the font text of the annotations.
/// </summary>
public class FontMappingHelper
{
public static string FontFamily = Device.RuntimePlatform == Device.Android ? "Final_PDFViewer_Android_FontUpdate.ttf#"
: Device.RuntimePlatform == Device.iOS ? "Final_PDFViewer_IOS_FontUpdate"
: "/Assets/Fonts/Final_PDFViewer_UWP_FontUpdate.ttf#Final_PDFViewer_UWP_FontUpdate";
public static string Underline = Device.RuntimePlatform == Device.Android ? "\uE70d" : Device.RuntimePlatform == Device.iOS ? "\uE70c" : "\uE721";
public static string StrikeThrough = Device.RuntimePlatform == Device.Android ? "\uE711" : Device.RuntimePlatform == Device.iOS ? "\uE71e" : "\uE709";
public static string Highlight = Device.RuntimePlatform == Device.Android ? "\uE715" : Device.RuntimePlatform == Device.iOS ? "\uE710" : "\uE70c";
public static string Ink = Device.RuntimePlatform == Device.Android ? "\uE71d" : Device.RuntimePlatform == Device.iOS ? "\uE704" : "\uE704";
public static string EditText = Device.RuntimePlatform == Device.Android ? "\uE71f" : Device.RuntimePlatform == Device.iOS ? "\uE700" : "\uE71A";
public static string Rectangle = Device.RuntimePlatform == Device.Android ? "\uE710" : Device.RuntimePlatform == Device.iOS ? "\uE705" : "\uE70e";
public static string Circle = Device.RuntimePlatform == Device.Android ? "\uE714" : Device.RuntimePlatform == Device.iOS ? "\uE71f" : "\uE717";
public static string Line = Device.RuntimePlatform == Device.Android ? "\uE703" : Device.RuntimePlatform == Device.iOS ? "\uE717" : "\uE71b";
public static string Arrow = Device.RuntimePlatform == Device.Android ? "\uE701" : Device.RuntimePlatform == Device.iOS ? "\uE712" : "\uE70a";
public static string Polygon = Device.RuntimePlatform == Device.Android ? "\uE712" : Device.RuntimePlatform == Device.iOS ? "\uE70D" : "\uE715";
}
Refer to the following screenshot.
Note: The listed font files are shipped with the GitHub example.
Organize PDF Viewer, Navigation Drawer, and ListView
Let’s create a main content page in the MainPage.xaml and add the Xamarin.Forms PDF Viewer and Navigation Drawer components as the children to it. Then, we add the Xamarin.Forms ListView component as a child to the Navigation Drawer and set the appearance for each cell in the list view with the created data template.
Next, set the PDF Viewer component as the binding context for the ListView component and bind the PDF Viewer’s Annotations collection property as the ItemSource to it.
Refer to the following code example.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:AnnotationsListView"
xmlns:navigationdrawer="clr-namespace:Syncfusion.SfNavigationDrawer.XForms;assembly=Syncfusion.SfNavigationDrawer.XForms"
xmlns:pdfviewer="clr-namespace:Syncfusion.SfPdfViewer.XForms;assembly=Syncfusion.SfPdfViewer.XForms"
xmlns:listView="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
x:Class="AnnotationsListView.MainPage">
<ContentPage.BindingContext>
<local:AnnotationsListViewModel x:Name="viewmodel"></local:AnnotationsListViewModel>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<local:ImageSourceConverter x:Key="ImageSourceConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<navigationdrawer:SfNavigationDrawer x:Name="navigationDrawer" DrawerFooterHeight="0" DrawerHeaderHeight="50">
<navigationdrawer:SfNavigationDrawer.ContentView>
<Grid x:Name="mainContentView" BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackLayout BackgroundColor="#1aa1d6" Orientation="Horizontal">
<Button x:Name="hamburgerButton" HeightRequest="50" WidthRequest="50"
HorizontalOptions="Center" FontSize="14"
BackgroundColor="#1aa1d6"
Clicked="hamburgerButton_Clicked"
Margin="5,0,0,0"/>
<Label x:Name="headerLabel" HeightRequest="50" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Text="Annotaions ListView" FontSize="20" TextColor="White" BackgroundColor="#1aa1d6"/>
</StackLayout>
<pdfviewer:SfPdfViewer x:Name="pdfViewer" Grid.Row="1" InputFileStream="{Binding PdfDocumentStream}"></pdfviewer:SfPdfViewer>
</Grid>
</navigationdrawer:SfNavigationDrawer.ContentView>
<navigationdrawer:SfNavigationDrawer.DrawerHeaderView>
<Grid BackgroundColor="#1aa1d6">
<StackLayout Orientation="Horizontal" HorizontalOptions="Start"
VerticalOptions="Center" >
<Label Text="Annotations" FontSize="20" TextColor="White" Margin="10,0,0,0"/>
<Label Text="(" FontSize="20" TextColor="White" Margin="5,0,0,0"/>
<Label BindingContext="{x:Reference Name=pdfViewer}" Text="{Binding Annotations.Count}" TextColor="White" FontSize="20"/>
<Label Text=")" FontSize="20" TextColor="White"/>
</StackLayout>
</Grid>
</navigationdrawer:SfNavigationDrawer.DrawerHeaderView>
<navigationdrawer:SfNavigationDrawer.DrawerContentView>
<listView:SfListView BackgroundColor="White" x:Name="listView" AllowGroupExpandCollapse="True"
ItemTapped="listView_ItemTapped"
BindingContext="{x:Reference Name=pdfViewer}"
ItemsSource="{Binding Annotations}">
<listView:SfListView.GroupHeaderTemplate>
<DataTemplate>
<Grid BackgroundColor="#E4E4E4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout Orientation="Horizontal" HorizontalOptions="Start"
VerticalOptions="Center" >
<Label Text="{Binding Key}" TextColor="Black" FontSize="Medium" Margin="10,0,0,0"/>
</StackLayout>
<StackLayout Orientation="Horizontal" Grid.Column="1"
HorizontalOptions="EndAndExpand" VerticalOptions="Center" Margin="0,0,5,0">
<Label Text="{Binding Count}" FontSize="Medium" TextColor="Black" />
<Image VerticalOptions="Center" HeightRequest="15"
WidthRequest="15"
Source="{Binding IsExpand, Converter={StaticResource ImageSourceConverter}}">
</Image>
</StackLayout>
</Grid>
</DataTemplate>
</listView:SfListView.GroupHeaderTemplate>
<listView:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:ListViewItem />
</ViewCell>
</DataTemplate>
</listView:SfListView.ItemTemplate>
</listView:SfListView>
</navigationdrawer:SfNavigationDrawer.DrawerContentView>
</navigationdrawer:SfNavigationDrawer>
</ContentPage>
In the following code example, the ImageSourceConverter class changes the expand and collapse images displayed in the list view’s page grouped header.
public class ImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
return ImageSource.FromResource("AnnotationsListView.Assets.Expand.png");
else
return ImageSource.FromResource("AnnotationsListView.Assets.Collapse.png");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Implement navigation on annotation selection
Next, select an annotation that will navigate you to its corresponding position in the PDF. This is done by passing the required annotation data as a parameter to the PDF Viewer component’s SelectAnnotation method and setting the VerticalOffset property with the selected annotation’s y- position concerning the scroll point.
Implement the following code logic to navigate to the selected annotation in the listView_ItemTapped event handler of the MainPage partial class in the MainPage.xaml.cs file.
private void listView_ItemTapped(object sender, Syncfusion.ListView.XForms.ItemTappedEventArgs e)
{
double x = 0;
double y = 0;
if (e.ItemType != Syncfusion.ListView.XForms.ItemType.GroupHeader)
{
pdfViewer.AnnotationMode = AnnotationMode.None;
IAnnotation annotation = e.ItemData as IAnnotation;
pdfViewer.SelectAnnotation(annotation);
if (annotation is ShapeAnnotation shape)
{
x = shape.Bounds.X;
y = shape.Bounds.Y;
}
else if (annotation is TextMarkupAnnotation textMarkup)
{
x = textMarkup.Bounds[0].X;
y = textMarkup.Bounds[0].Y;
}
else if (annotation is FreeTextAnnotation freeText)
{
x = freeText.Bounds.X;
y = freeText.Bounds.Y;
}
else if (annotation is InkAnnotation ink)
{
x = ink.Bounds.X;
y = ink.Bounds.Y;
}
var points = pdfViewer.ConvertPagePointToScrollPoint(new Point(x, y), annotation.PageNumber);
pdfViewer.VerticalOffset = (float)points.Y - 30;
navigationDrawer.ToggleDrawer();
}
}
GitHub reference
Check out the example to view PDF annotations as a list and navigate to them using Syncfusion Xamarin.Forms PDF Viewer component. Execution of this example app will provide output like in the following GIF image.
Achieve more
You can add more functionalities, like removing specific and all annotations, locking, exporting, and importing annotations into your app. To learn more about the functionalities supported in the Xamarin PDF Viewer component, refer to the getting started documentation.
Conclusion
Thanks for reading! I hope you have a clear idea of how to view annotations as a list and navigate to them using Syncfusion’s Xamarin.Forms PDF Viewer component. Try this in your app and share your feedback in the comment section below!
If you aren’t a customer, you can try our 30-day free trial to check out these features. Also, try our other Xamarin examples from this GitHub location.
You can contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!