31 KiB
MASpotlightTour API Reference
Complete API documentation for the MASpotlightTour library.
Table of Contents
- Namespace
- OnboardingHost
- Onboarding (Attached Properties)
- OnboardingStep
- OnboardingScanner
- Enumerations
- Events
Namespace
using MarketAlly.SpotlightTour.Maui;
XAML namespace:
xmlns:tour="clr-namespace:MarketAlly.SpotlightTour.Maui;assembly=MarketAlly.SpotlightTour.Maui"
OnboardingHost
The main host control that orchestrates the onboarding tour experience. Add this as an overlay on your page to enable spotlight tours.
Inheritance: Grid → OnboardingHost
Properties
Display & Mode Properties
| Property | Type | Default | Description |
|---|---|---|---|
DisplayMode |
TourDisplayMode |
SpotlightWithCallout |
The display mode for the tour. |
Theme |
TourTheme |
Light |
Visual theme (Light, Dark, or System). |
TourFlowDirection |
FlowDirection |
MatchParent |
RTL support: MatchParent, LeftToRight, or RightToLeft. |
AnimationsEnabled |
bool |
true |
Whether animations are enabled. |
AnimationDuration |
uint |
250 |
Animation duration in milliseconds. |
Overlay Properties
| Property | Type | Default | Description |
|---|---|---|---|
DimOpacity |
double |
0.6 |
Opacity of the dimmed overlay (0.0 - 1.0). |
DimColor |
Color |
Colors.Black |
Color of the dimmed overlay. |
Callout Properties
| Property | Type | Default | Description |
|---|---|---|---|
CalloutPositionMode |
CalloutPositionMode |
Following |
Positioning strategy for the callout card. |
CalloutCorner |
CalloutCorner |
BottomLeft |
Corner to use when CalloutPositionMode is FixedCorner. |
CalloutCornerMargin |
double |
16.0 |
Margin from screen edge when using corner positioning. |
Navigator Properties
| Property | Type | Default | Description |
|---|---|---|---|
ShowCornerNavigator |
bool |
true |
Whether to show the corner navigator control. |
CornerNavigatorPlacement |
CornerNavigatorPlacement |
BottomRight |
Position of the corner navigator. |
ShowSkipButton |
bool |
true |
Whether to show the skip/done button in navigator. |
ShowArrow |
bool |
true |
Whether to show the arrow indicator pointing to spotlight. |
Auto Features
| Property | Type | Default | Description |
|---|---|---|---|
AutoStartDelay |
int |
0 |
Delay in ms before auto-starting. 0 = disabled. |
AutoStartGroup |
string? |
null |
Group to use for auto-start. |
AutoAdvanceDelay |
int |
0 |
Delay in ms before auto-advancing. 0 = disabled. |
AutoLoop |
int |
0 |
Number of times to repeat the tour. 0 = disabled. |
Intro View
| Property | Type | Default | Description |
|---|---|---|---|
IntroView |
View? |
null |
Custom intro/welcome view displayed before tour starts. |
ShowIntro |
bool |
true |
Controls whether intro view is displayed. Set to false to skip intro (useful for returning users). |
AllowTapAnywhereToDismissIntro |
bool |
false |
When true, tapping anywhere on the dimmed overlay while intro is shown will skip the tour. |
Read-Only Properties
| Property | Type | Description |
|---|---|---|
IsRunning |
bool |
Whether a tour is currently running. |
CurrentStepIndex |
int |
Current step index (0-based). -1 if not running. |
TotalSteps |
int |
Total number of steps in the tour. |
CurrentStep |
OnboardingStep? |
Current step, or null if no tour is running. |
IsShowingIntro |
bool |
Whether the intro view is currently displayed. |
Methods
Starting Tours
Task<TourResult> StartTourAsync(VisualElement root, string? group = null)
Starts the onboarding tour by scanning for tagged elements. Returns when the tour ends.
Parameters:
root: The root element to scan (typicallythis.Contentor a layout).group: Optional group filter. If null, includes all steps.
Returns: TourResult indicating how the tour ended.
Task<TourResult> StartTourFromStepAsync(VisualElement root, string stepKey, string? group = null)
Starts the tour from a specific step identified by its key.
Parameters:
root: The root element to scan.stepKey: The step key to start from.group: Optional group filter.
Returns: TourResult indicating how the tour ended.
Task<TourResult> StartTourWithIntroAsync(VisualElement root, string? group = null, bool showIntro = true)
Starts the tour, optionally showing the intro view first.
Parameters:
root: The root element to scan.group: Optional group filter.showIntro: Whether to show the intro view (if configured).
Returns: TourResult indicating how the tour ended.
Navigation
Task GoToStepAsync(int index)
Navigates to a specific step by index.
void GoToNextStep()
Advances to the next step. Completes the tour if on the last step.
void GoToPreviousStep()
Returns to the previous step. Does nothing if on the first step.
Ending Tours
void CompleteTour()
Completes the tour (user finished all steps). Triggers TourCompleted event.
void SkipTour()
Skips/cancels the tour. Triggers TourSkipped event.
void StopTour()
Stops any currently running tour. Sets result to Cancelled.
Intro View
void DisplayIntroView()
Displays the intro view. Called automatically by StartTourWithIntroAsync when ShowIntro property is true.
void DismissIntro()
Dismisses the intro view and continues with the tour.
Events
| Event | Args | Description |
|---|---|---|
TourStarted |
EventArgs |
Raised when the tour starts. |
TourCompleted |
EventArgs |
Raised when the user completes all steps. |
TourSkipped |
EventArgs |
Raised when the user skips the tour. |
TourEnded |
EventArgs |
Raised when the tour ends (any reason). |
StepEntering |
StepActionEventArgs |
Raised before entering a step. Async. Can set Skip = true. |
StepEntered |
StepActionEventArgs |
Raised after step is fully visible (after animations). |
StepLeaving |
StepActionEventArgs |
Raised before leaving the current step. Async. |
StepChanged |
OnboardingStepEventArgs |
Raised when moving to a new step. |
IntroShown |
EventArgs |
Raised when the intro view is shown. |
IntroDismissed |
EventArgs |
Raised when the intro view is dismissed. |
Step Action Registration
void RegisterStepEnteringAction(string stepKey, Func<OnboardingStep, CancellationToken, Task> action)
Registers an action to execute when entering a specific step (by StepKey). The action runs before the spotlight animates to the step.
void RegisterStepLeavingAction(string stepKey, Func<OnboardingStep, CancellationToken, Task> action)
Registers an action to execute when leaving a specific step (by StepKey). The action runs before navigating away.
bool UnregisterStepEnteringAction(string stepKey)
Removes a registered entering action for a step. Returns true if the action was removed.
bool UnregisterStepLeavingAction(string stepKey)
Removes a registered leaving action for a step. Returns true if the action was removed.
void ClearStepActions()
Clears all registered step actions (both entering and leaving).
Usage Example
<tour:OnboardingHost
x:Name="TourHost"
DisplayMode="SpotlightWithCallout"
Theme="System"
ShowCornerNavigator="True"
CornerNavigatorPlacement="Auto"
CalloutPositionMode="AutoCorner"
DimOpacity="0.7"
AnimationDuration="300" />
var result = await TourHost.StartTourAsync(this.Content);
if (result == TourResult.Completed)
{
// Tour completed successfully
}
Onboarding (Attached Properties)
Static class providing attached properties for tagging UI elements as onboarding/tour steps.
Attached Properties
Identification
| Property | Type | Default | Description |
|---|---|---|---|
StepKey |
string? |
null |
Unique key identifying the step. Falls back to AutomationId if not set. |
Group |
string? |
null |
Group name for organizing multiple tours. |
Order |
int |
0 |
Sequence number within the group. Lower numbers appear first. |
Content
| Property | Type | Default | Description |
|---|---|---|---|
Title |
string? |
null |
Title text displayed in the callout. |
Description |
string? |
null |
Description text displayed in the callout. |
Spotlight Appearance
| Property | Type | Default | Description |
|---|---|---|---|
SpotlightEnabled |
bool |
true |
Whether this element participates in spotlight cutouts. |
SpotlightShape |
SpotlightShape |
RoundedRectangle |
Shape of the spotlight cutout. |
SpotlightPadding |
Thickness |
8 |
Padding around the target element. |
SpotlightCornerRadius |
double |
8.0 |
Corner radius for RoundedRectangle shape. |
Behavior
| Property | Type | Default | Description |
|---|---|---|---|
Placement |
CalloutPlacement |
Auto |
Where to place the callout relative to this element. |
TapBehavior |
SpotlightTapBehavior |
None |
Behavior when user taps the spotlight. |
Step Actions
| Property | Type | Default | Description |
|---|---|---|---|
OnEntering |
Func<OnboardingStep, CancellationToken, Task>? |
null |
Action to execute when entering this step. Runs before spotlight animation. |
OnLeaving |
Func<OnboardingStep, CancellationToken, Task>? |
null |
Action to execute when leaving this step. Runs before navigating away. |
Static Methods
string? GetEffectiveStepKey(BindableObject view)
Gets the step key, falling back to AutomationId if StepKey is not set.
bool IsOnboardingStep(BindableObject view)
Returns true if the element is tagged as an onboarding step (has StepKey, Title, or Description).
XAML Usage
<Button
Text="Click Me"
tour:Onboarding.StepKey="my-button"
tour:Onboarding.Title="Button Title"
tour:Onboarding.Description="This is the button description."
tour:Onboarding.Order="1"
tour:Onboarding.Group="main-tour"
tour:Onboarding.SpotlightShape="RoundedRectangle"
tour:Onboarding.SpotlightPadding="12"
tour:Onboarding.SpotlightCornerRadius="16"
tour:Onboarding.Placement="Bottom"
tour:Onboarding.TapBehavior="Advance" />
C# Usage
// Set properties programmatically
Onboarding.SetStepKey(myButton, "my-button");
Onboarding.SetTitle(myButton, "Button Title");
Onboarding.SetDescription(myButton, "Description text");
Onboarding.SetOrder(myButton, 1);
Onboarding.SetSpotlightShape(myButton, SpotlightShape.Circle);
// Read properties
var key = Onboarding.GetStepKey(myButton);
var title = Onboarding.GetTitle(myButton);
// Set step actions (async actions that run when entering/leaving this step)
Onboarding.SetOnEntering(myButton, async (step, cancellationToken) =>
{
// Prepare UI before spotlight appears (e.g., switch tabs, open drawer)
MainTabView.SelectedIndex = 2;
await Task.Delay(100);
});
Onboarding.SetOnLeaving(myButton, async (step, cancellationToken) =>
{
// Cleanup when leaving this step
});
OnboardingStep
Represents a single step in an onboarding tour. Created automatically from tagged elements or can be created programmatically.
Properties
| Property | Type | Description |
|---|---|---|
Target |
VisualElement |
The target visual element for this step. Required. |
StepKey |
string? |
Unique key identifying this step. |
Title |
string? |
Title text displayed in the callout. |
Description |
string? |
Description text displayed in the callout. |
Order |
int |
Sequence number within the group. |
Group |
string? |
Group name for organizing multiple tours. |
SpotlightEnabled |
bool |
Whether spotlight cutout is enabled. Default: true. |
Placement |
CalloutPlacement |
Callout placement relative to spotlight. Default: Auto. |
SpotlightShape |
SpotlightShape |
Shape of the spotlight cutout. Default: RoundedRectangle. |
SpotlightPadding |
Thickness |
Padding around target. Default: 8. |
SpotlightCornerRadius |
double |
Corner radius for rounded rectangle. Default: 8.0. |
TapBehavior |
SpotlightTapBehavior |
Behavior when tapping spotlight. Default: None. |
OnEntering |
Func<OnboardingStep, CancellationToken, Task>? |
Action to execute when entering this step. |
OnLeaving |
Func<OnboardingStep, CancellationToken, Task>? |
Action to execute when leaving this step. |
Static Methods
OnboardingStep FromElement(VisualElement element)
Creates an OnboardingStep from a tagged VisualElement by reading its attached properties.
Usage Example
// Create from element
var step = OnboardingStep.FromElement(myButton);
// Create programmatically
var step = new OnboardingStep
{
Target = myButton,
StepKey = "welcome",
Title = "Welcome",
Description = "This is the welcome step.",
Order = 1,
SpotlightShape = SpotlightShape.RoundedRectangle
};
OnboardingScanner
Static utility class for scanning the visual tree to find elements tagged with onboarding properties.
Methods
IReadOnlyList<OnboardingStep> FindSteps(Element root, string? group = null)
Finds all onboarding steps within the given root element.
Parameters:
root: The root element to scan.group: Optional group filter. If null, returns all steps.
Returns: Ordered list of OnboardingStep objects.
OnboardingStep? FindStepByKey(Element root, string stepKey)
Finds a specific step by its key.
Parameters:
root: The root element to scan.stepKey: The step key to find (case-insensitive).
Returns: The matching OnboardingStep or null if not found.
IReadOnlyList<string> GetGroups(Element root)
Gets all unique group names found in the visual tree.
Returns: Alphabetically sorted list of group names.
int CountSteps(Element root, string? group = null)
Counts the total number of steps, optionally filtered by group.
Usage Example
// Find all steps
var allSteps = OnboardingScanner.FindSteps(this.Content);
// Find steps in a specific group
var basicSteps = OnboardingScanner.FindSteps(this.Content, "basics");
// Find a specific step
var welcomeStep = OnboardingScanner.FindStepByKey(this.Content, "welcome");
// Get all groups
var groups = OnboardingScanner.GetGroups(this.Content);
// Returns: ["advanced", "basics", "settings"]
// Count steps
var totalCount = OnboardingScanner.CountSteps(this.Content);
var groupCount = OnboardingScanner.CountSteps(this.Content, "basics");
Enumerations
TourDisplayMode
Specifies the display mode for the onboarding tour.
| Value | Description |
|---|---|
SpotlightWithCallout |
Full experience: dimmed overlay + spotlight cutout + callout card with nav buttons. |
CalloutOnly |
Callout cards only - no dimming. Good for light-touch guidance. |
SpotlightWithInlineLabel |
Dimmed overlay with spotlight, inline labels instead of callout card. Use with corner navigator. |
TourTheme
Specifies the visual theme for tour components.
| Value | Description |
|---|---|
Light |
Light theme with white backgrounds and dark text. |
Dark |
Dark theme with dark backgrounds and light text. |
System |
Automatically follows the system theme. |
CalloutPlacement
Specifies where the callout card is positioned relative to the spotlight.
| Value | Description |
|---|---|
Auto |
Automatically determine placement based on available space. |
Top |
Position callout above the spotlight. |
Bottom |
Position callout below the spotlight. |
Left |
Position callout to the left of the spotlight. |
Right |
Position callout to the right of the spotlight. |
CalloutPositionMode
Specifies the positioning strategy for the callout card.
| Value | Description |
|---|---|
Following |
Callout positions relative to the highlighted element. Uses CalloutPlacement. |
FixedCorner |
Callout stays in a fixed screen corner. Uses CalloutCorner. |
AutoCorner |
Callout auto-positions in the corner that least interferes with the spotlight. |
CalloutCorner
Specifies which screen corner for fixed/auto corner positioning.
| Value | Description |
|---|---|
TopLeft |
Top-left corner of the screen. |
TopRight |
Top-right corner of the screen. |
BottomLeft |
Bottom-left corner of the screen. |
BottomRight |
Bottom-right corner of the screen. |
CornerNavigatorPlacement
Specifies the corner position for the navigator control.
| Value | Description |
|---|---|
TopLeft |
Top-left corner of the screen. |
TopRight |
Top-right corner of the screen. |
BottomLeft |
Bottom-left corner of the screen. |
BottomRight |
Bottom-right corner of the screen. |
Auto |
Automatically positions to avoid overlapping with spotlight and callout. |
SpotlightShape
Specifies the shape of the spotlight cutout.
| Value | Description |
|---|---|
Rectangle |
Rectangular cutout matching the element bounds. |
RoundedRectangle |
Rounded rectangle with configurable corner radius. |
Circle |
Circular cutout centered on the element. |
SpotlightTapBehavior
Specifies behavior when the user taps on the spotlighted element.
| Value | Description |
|---|---|
None |
Tapping does nothing; only nav buttons work. |
Advance |
Tapping advances to the next step. |
Close |
Tapping closes/ends the tour. |
AllowInteraction |
Allow interaction with the underlying element (pass-through). |
TourResult
Specifies how a tour ended. Returned by StartTourAsync methods.
| Value | Description |
|---|---|
Completed |
The tour completed successfully (user went through all steps). |
Skipped |
The tour was skipped by the user. |
Cancelled |
The tour was cancelled programmatically. |
NoSteps |
No steps were found to show. |
Events
OnboardingStepEventArgs
Event arguments for the StepChanged event.
| Property | Type | Description |
|---|---|---|
Step |
OnboardingStep |
The current step. |
StepIndex |
int |
Zero-based index of the current step. |
TotalSteps |
int |
Total number of steps in the tour. |
Usage Example
TourHost.StepChanged += (sender, e) =>
{
Console.WriteLine($"Now on step {e.StepIndex + 1} of {e.TotalSteps}");
Console.WriteLine($"Title: {e.Step.Title}");
Console.WriteLine($"Key: {e.Step.StepKey}");
};
StepActionEventArgs
Event arguments for step action events (StepEntering, StepEntered, StepLeaving).
| Property | Type | Description |
|---|---|---|
Step |
OnboardingStep |
The step being entered or left. |
StepIndex |
int |
Zero-based index of the step. |
TotalSteps |
int |
Total number of steps in the tour. |
PreviousStepIndex |
int |
Index of the previous step (-1 if first step). |
IsForward |
bool |
Whether navigation is moving forward (true) or backward (false). |
Skip |
bool |
Set to true to skip this step (only applies to StepEntering). |
CancellationToken |
CancellationToken |
Cancellation token for the current operation. |
Step Action Usage Example
// Register action by StepKey
TourHost.RegisterStepEnteringAction("settings-tab", async (step, token) =>
{
// Switch to settings tab before spotlight appears
SettingsTabView.SelectedIndex = 1;
await Task.Delay(150); // Wait for tab transition
});
// Use event for conditional skipping
TourHost.StepEntering += async (sender, e) =>
{
// Skip premium-only steps for free users
if (e.Step.StepKey?.StartsWith("premium-") == true && !User.IsPremium)
{
e.Skip = true;
}
};
// Track when steps are viewed
TourHost.StepEntered += (sender, e) =>
{
Analytics.Track("tour_step_viewed", new {
step_key = e.Step.StepKey,
step_index = e.StepIndex,
is_forward = e.IsForward
});
};
// Cleanup when leaving steps
TourHost.StepLeaving += async (sender, e) =>
{
if (e.Step.StepKey == "drawer-step")
{
Shell.Current.FlyoutIsPresented = false;
await Task.Delay(200);
}
};
Complete Integration Example
XAML (MainPage.xaml)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tour="clr-namespace:MarketAlly.SpotlightTour.Maui;assembly=MarketAlly.SpotlightTour.Maui"
x:Class="MyApp.MainPage"
Title="Home">
<Grid>
<!-- Main Content -->
<ScrollView>
<VerticalStackLayout Padding="20" Spacing="16">
<!-- Step 1: Profile Image -->
<Border
StrokeShape="RoundRectangle 50"
WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
tour:Onboarding.StepKey="profile-image"
tour:Onboarding.Title="Your Profile"
tour:Onboarding.Description="Tap here to view and edit your profile picture."
tour:Onboarding.Order="1"
tour:Onboarding.SpotlightShape="Circle">
<Image Source="profile.png" Aspect="AspectFill" />
</Border>
<!-- Step 2: Search Bar -->
<SearchBar
Placeholder="Search..."
tour:Onboarding.StepKey="search"
tour:Onboarding.Title="Quick Search"
tour:Onboarding.Description="Find anything in the app instantly."
tour:Onboarding.Order="2"
tour:Onboarding.SpotlightPadding="4" />
<!-- Step 3: Feature Cards (Grouped) -->
<Label Text="Features" FontSize="20" FontAttributes="Bold" />
<Frame
BackgroundColor="#E3F2FD"
Padding="16"
CornerRadius="12"
tour:Onboarding.StepKey="feature-analytics"
tour:Onboarding.Title="Analytics Dashboard"
tour:Onboarding.Description="View detailed analytics and reports."
tour:Onboarding.Order="3"
tour:Onboarding.Group="features">
<Label Text="Analytics" FontAttributes="Bold" />
</Frame>
<Frame
BackgroundColor="#E8F5E9"
Padding="16"
CornerRadius="12"
tour:Onboarding.StepKey="feature-settings"
tour:Onboarding.Title="Settings"
tour:Onboarding.Description="Customize your experience."
tour:Onboarding.Order="4"
tour:Onboarding.Group="features">
<Label Text="Settings" FontAttributes="Bold" />
</Frame>
<!-- Step 4: Action Button -->
<Button
Text="Get Started"
BackgroundColor="#007AFF"
TextColor="White"
CornerRadius="8"
tour:Onboarding.StepKey="get-started"
tour:Onboarding.Title="Ready to Go!"
tour:Onboarding.Description="Tap this button to begin using the app."
tour:Onboarding.Order="5"
tour:Onboarding.TapBehavior="Advance"
Clicked="OnGetStartedClicked" />
</VerticalStackLayout>
</ScrollView>
<!-- Onboarding Host (Overlay) -->
<tour:OnboardingHost
x:Name="TourHost"
DisplayMode="SpotlightWithCallout"
Theme="System"
ShowCornerNavigator="True"
CornerNavigatorPlacement="Auto"
CalloutPositionMode="AutoCorner"
DimOpacity="0.75"
AnimationDuration="300">
<!-- Intro View -->
<tour:OnboardingHost.IntroView>
<Frame
BackgroundColor="White"
CornerRadius="20"
Padding="32"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="320">
<VerticalStackLayout Spacing="24">
<Image
Source="app_logo.png"
HeightRequest="80"
Aspect="AspectFit" />
<Label
Text="Welcome to MyApp!"
FontSize="24"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />
<Label
Text="Let's take a quick tour to help you get started."
FontSize="14"
TextColor="Gray"
HorizontalTextAlignment="Center" />
<Button
Text="Start Tour"
BackgroundColor="#007AFF"
TextColor="White"
CornerRadius="8"
Clicked="OnStartTourClicked" />
<Button
Text="Skip"
BackgroundColor="Transparent"
TextColor="Gray"
Clicked="OnSkipIntroClicked" />
</VerticalStackLayout>
</Frame>
</tour:OnboardingHost.IntroView>
</tour:OnboardingHost>
</Grid>
</ContentPage>
Code-Behind (MainPage.xaml.cs)
using MarketAlly.SpotlightTour.Maui;
namespace MyApp;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// Subscribe to events
TourHost.TourStarted += OnTourStarted;
TourHost.StepChanged += OnStepChanged;
TourHost.TourCompleted += OnTourCompleted;
TourHost.TourSkipped += OnTourSkipped;
}
protected override async void OnAppearing()
{
base.OnAppearing();
// Show tour for first-time users
if (!Preferences.Get("HasCompletedTour", false))
{
// Small delay for page to fully load
await Task.Delay(500);
await StartOnboardingAsync();
}
}
private async Task StartOnboardingAsync()
{
var result = await TourHost.StartTourWithIntroAsync(this.Content);
if (result == TourResult.Completed)
{
Preferences.Set("HasCompletedTour", true);
await DisplayAlert("All Done!", "You've completed the tour. Enjoy the app!", "OK");
}
}
private void OnStartTourClicked(object sender, EventArgs e)
{
TourHost.DismissIntro();
}
private async void OnSkipIntroClicked(object sender, EventArgs e)
{
TourHost.SkipTour();
await DisplayAlert("Tour Skipped", "You can restart the tour from Settings.", "OK");
}
private void OnTourStarted(object? sender, EventArgs e)
{
Console.WriteLine("Tour started!");
}
private void OnStepChanged(object? sender, OnboardingStepEventArgs e)
{
Console.WriteLine($"Step {e.StepIndex + 1}/{e.TotalSteps}: {e.Step.Title}");
// Track analytics
Analytics.TrackEvent("TourStep", new Dictionary<string, string>
{
{ "StepKey", e.Step.StepKey ?? "unknown" },
{ "StepIndex", e.StepIndex.ToString() }
});
}
private void OnTourCompleted(object? sender, EventArgs e)
{
Console.WriteLine("Tour completed!");
}
private void OnTourSkipped(object? sender, EventArgs e)
{
Console.WriteLine("Tour skipped.");
}
private void OnGetStartedClicked(object sender, EventArgs e)
{
// Handle button click
// If tour is running, TapBehavior="Advance" will auto-advance
}
// Method to restart tour (e.g., from Settings)
public async void RestartTour()
{
await TourHost.StartTourAsync(this.Content);
}
}
Best Practices
1. Element Ordering
Use explicit Order values to ensure consistent step sequence:
tour:Onboarding.Order="1"
tour:Onboarding.Order="2"
2. Meaningful Step Keys
Use descriptive, unique keys for programmatic access:
tour:Onboarding.StepKey="profile-settings-button"
3. Concise Content
Keep titles short (2-5 words) and descriptions clear (1-2 sentences):
tour:Onboarding.Title="Quick Actions"
tour:Onboarding.Description="Access frequently used features with one tap."
4. Appropriate Spotlight Shapes
- Use
Circlefor icons, avatars, and circular elements - Use
RoundedRectanglefor buttons, cards, and inputs - Use
Rectanglefor full-width elements or tables
5. Group Related Tours
Use groups to organize multiple tours:
tour:Onboarding.Group="onboarding"
tour:Onboarding.Group="new-features"
tour:Onboarding.Group="pro-tips"
6. Persist Tour Completion
Always save tour completion state:
if (result == TourResult.Completed)
{
Preferences.Set("HasSeenTour_v1", true);
}
7. Auto-Positioning
Use Auto placement modes for responsive layouts:
CalloutPositionMode="AutoCorner"
CornerNavigatorPlacement="Auto"
Troubleshooting
Tour doesn't start
- Ensure
OnboardingHostis added as the last child (overlay) - Verify elements have
StepKey,Title, orDescriptionset - Check that the root element passed to
StartTourAsynccontains the tagged elements
Steps appear in wrong order
- Verify
Ordervalues are set correctly - Steps with the same
Orderare sorted by visual tree position
Callout positioning issues
- Try different
CalloutPositionModevalues - Increase
CalloutCornerMarginif callout is too close to edges - Use
CalloutPlacementper-element for specific positioning
Spotlight not visible
- Check
DimOpacityis greater than 0 - Verify
SpotlightEnabledis not set tofalse - Ensure the target element is visible and has non-zero dimensions
For additional support, visit the repository.