Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dialog animation, Migrate to V11.1 #36

Merged
merged 4 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ Avalonia Inside Shell reduces the complexity of mobile/desktop application devel
A single place to describe the visual hierarchy of an application.
A common navigation user experience.
A URI-based navigation scheme that permits navigation to any page in the application


We welcome feedback, suggestions, and contributions from anyone who is interested in this project. We appreciate your support and patience as we work towards releasing a stable version of this project.


## Screenshots

<img src="https://user-images.githubusercontent.com/956077/226295190-cbe81c7d-4054-4c07-9e5c-7ee7149c1468.png" width="300"/> <img src="https://user-images.githubusercontent.com/956077/226295294-3d4f1f9e-941d-4248-b941-a0c35ca0533a.png" width="300"/>
<img src="https://user-images.githubusercontent.com/956077/226295190-cbe81c7d-4054-4c07-9e5c-7ee7149c1468.png" width="300"/> <img src="https://user-images.githubusercontent.com/956077/226295294-3d4f1f9e-941d-4248-b941-a0c35ca0533a.png" width="300"/>

## Installation

To use AvaloniaInside.Shell in your Avalonia project, you can install the package via NuGet using the following command in the Package Manager Console:

```bash
dotnet add package AvaloniaInside.Shell --version 1.1.3
dotnet add package AvaloniaInside.Shell --version 1.2.0
```

Alternatively, you can also install the package through Visual Studio's NuGet Package Manager.
Expand Down Expand Up @@ -80,7 +80,7 @@ And to navigate to a specific page, we can use the Navigator property of the She
await MyShellView.Navigator.NavigateAsync("/main/home/confirmation", cancellationToken);
```

### NavigationBar
### NavigationBar
![image](https://user-images.githubusercontent.com/956077/227613963-9b1a10b5-c2b0-4dcb-ba43-cd72f3a27333.png)

Each page that is currently on top of the navigation stack has access to the navigation bar's title and navigation item. In hierarchical hosts, the currently selected item in the host will be the one that has access to the navigation bar. For example, in the case of /home/pets/cat, the page associated with the cat would be able to modify the navigation bar. This can be done by setting the NavigationBar.Header and NavigationBar.Item properties, as shown in the code snippet below:
Expand Down Expand Up @@ -108,7 +108,7 @@ Each page that is currently on top of the navigation stack has access to the nav
#### Host

`Host` can be used to group pages under a common root, such as a `TabControl`.
It has a `Page` property that specifies the view associated with the host, as well as an optional `Default` property that specifies the default child route. as well as a `Children` property that specifies any child `Route` objects.
It has a `Page` property that specifies the view associated with the host, as well as an optional `Default` property that specifies the default child route. as well as a `Children` property that specifies any child `Route` objects.

#### SideMenuItem

Expand All @@ -128,7 +128,7 @@ It has a `Page` property that specifies the view associated with the host, as we

<ShellView Name="ShellViewMain" DefaultRoute="/main">
<Host Path="main" Page="views:MainTabControl"> ... </Host>

<!-- Side Menu Header -->
<ShellView.SideMenuHeader>
<widgets:UserProfileWidgetView></widgets:UserProfileWidgetView>
Expand All @@ -141,13 +141,13 @@ It has a `Page` property that specifies the view associated with the host, as we
<SideMenuItem Path="/main/product" Title="Products" Icon="/Assets/Icons/tag-solid.png"></SideMenuItem>
<SideMenuItem Path="/main/setting" Title="Settings" Icon="/Assets/Icons/user-solid.png"></SideMenuItem>
<SideMenuItem Path="/second" Title="Second Click" Icon="/Assets/Icons/check-solid.png"></SideMenuItem>

<!-- SideMenu Content -->
<ShellView.SideMenuContents>
<widgets:WeatherView Margin="0, 20, 0, 0" />
<widgets:CalendarWidgetView Margin="0, 20, 0, 0" />
</ShellView.SideMenuContents>

<!-- SideMenu Footer -->
<ShellView.SideMenuFooter>
<Border Background="#11000000" Height="25">
Expand Down
4 changes: 2 additions & 2 deletions src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<Version>1.1.3</Version>
<Version>1.2.0</Version>
<Title>Shell view for Avalonia</Title>
<Description>Shell reduces the complexity of mobile/desktop application development by providing the fundamental features that most applications require</Description>
<Copyright>AvaloniaInside</Copyright>
Expand Down
68 changes: 28 additions & 40 deletions src/AvaloniaInside.Shell/Default.axaml
Original file line number Diff line number Diff line change
@@ -1,41 +1,20 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="StackContentView">
<Setter Property="Template">
<ControlTemplate>
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ItemsPresenter Name="PART_ItemsPresenter"
ItemsPanel="{TemplateBinding ItemsPanel}" />
</Border>
</ControlTemplate>
</Setter>
<Setter Property="ItemsPanel">
<ItemsPanelTemplate>
<StackContentViewPanel></StackContentViewPanel>
</ItemsPanelTemplate>
</Setter>
</Style>

<Style Selector="StackContentViewItem">
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}" />
</ControlTemplate>
</Setter>
</Style>
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key='Light'>
<SolidColorBrush x:Key='AppBackground' Color="{OnPlatform White, iOS=Black}"></SolidColorBrush>
<SolidColorBrush x:Key='PageBackground'>White</SolidColorBrush>
</ResourceDictionary>
<ResourceDictionary x:Key='Dark'>
<SolidColorBrush x:Key='AppBackground'>Black</SolidColorBrush>
<SolidColorBrush x:Key='PageBackground'>Black</SolidColorBrush>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Styles.Resources>

<Style Selector="NavigationBar">
<Setter Property="Template">
Expand Down Expand Up @@ -67,7 +46,7 @@
<Style Selector="ShellView">
<Setter Property="Template">
<ControlTemplate>
<Panel>
<Panel Background="{TemplateBinding Background}">
<SplitView Name="PART_SplitView" DisplayMode="Inline">
<SplitView.Pane>
<SideMenu Name="PART_SideMenu"
Expand All @@ -84,7 +63,7 @@
TopSafePadding="{TemplateBinding TopSafePadding}"
TopSafeSpace="{TemplateBinding TopSafeSpace}"
ApplyTopSafePadding="{TemplateBinding ApplyTopSafePadding}"/>
<StackContentView Name="PART_ContentView"
<StackContentView Name="PART_ContentView"
Grid.Row="1"
PageTransition="{TemplateBinding DefaultPageTransition}"></StackContentView>
<Border Grid.Row="2"
Expand Down Expand Up @@ -122,7 +101,8 @@
</Rectangle>

<StackContentView Name="PART_Modal"
IsVisible="{Binding ElementName=PART_Modal, Path=HasContent}">
IsVisible="{Binding ElementName=PART_Modal, Path=HasContent}"
PageTransition="{TemplateBinding ModalPageTransition}">
</StackContentView>
</Panel>
</ControlTemplate>
Expand Down Expand Up @@ -182,8 +162,8 @@
<ControlTemplate>
<Viewbox Stretch="UniformToFill">
<Canvas Width="16" Height="16" Margin="5" Background="#00000000">
<Line StartPoint="7,2" EndPoint="2,7" StrokeThickness="3" Stroke="{DynamicResource ButtonForeground}"></Line>
<Line StartPoint="2,7" EndPoint="7,12" StrokeThickness="3" Stroke="{DynamicResource ButtonForeground}"></Line>
<Line StartPoint="7,2" EndPoint="2,8" StrokeThickness="3" Stroke="{DynamicResource ButtonForeground}"></Line>
<Line StartPoint="2,6" EndPoint="7,12" StrokeThickness="3" Stroke="{DynamicResource ButtonForeground}"></Line>
</Canvas>
</Viewbox>
</ControlTemplate>
Expand All @@ -203,4 +183,12 @@
</ControlTemplate>
</Setter>
</Style>

<Style Selector="Page">
<Setter Property="Background" Value="{DynamicResource PageBackground}" />
</Style>

<Style Selector="ShellView">
<Setter Property="Background" Value="{DynamicResource AppBackground}" />
</Style>
</Styles>
5 changes: 4 additions & 1 deletion src/AvaloniaInside.Shell/Page.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Avalonia.Controls;
using System;
using Avalonia.Controls;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -8,6 +9,8 @@ public class Page : UserControl, INavigationLifecycle, INavigatorLifecycle
public ShellView? Shell { get; internal set; }
public INavigator? Navigator => Shell?.Navigator;

protected override Type StyleKeyOverride => typeof(Page);

public virtual Task AppearAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public virtual Task ArgumentAsync(object args, CancellationToken cancellationToken) => Task.CompletedTask;
public virtual Task DisappearAsync(CancellationToken cancellationToken) => Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class AndroidDefaultPageSlide : PlatformBasePageTransition
/// </summary>
public override Easing Easing { get; set; } = new FastOutExtraSlowInEasing();

protected override CompositionAnimationGroup GetOrCreateEnteranceAnimation(CompositionVisual element, double widthDistance, double heightDistance)
protected override CompositionAnimationGroup GetOrCreateEntranceAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class MaterialListPageSlide : PlatformBasePageTransition
/// </summary>
public override Easing Easing { get; set; } = new FastOutExtraSlowInEasing();

protected override CompositionAnimationGroup GetOrCreateEnteranceAnimation(CompositionVisual element, double widthDistance, double heightDistance)
protected override CompositionAnimationGroup GetOrCreateEntranceAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

Expand Down
143 changes: 143 additions & 0 deletions src/AvaloniaInside.Shell/Platform/Ios/AlertTransition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Animation.Easings;
using Avalonia.Rendering.Composition;
using Avalonia.Rendering.Composition.Animations;

namespace AvaloniaInside.Shell.Platform.Ios;

public class AlertTransition : PlatformBasePageTransition
{
public static readonly AlertTransition Instance = new();

private const float EndingCue = 0.9f;
private const float StartingCue = 0.1f;

/// <summary>
/// Gets the duration of the animation.
/// </summary>
public override TimeSpan Duration { get; set; } = TimeSpan.FromSeconds(.25);

/// <summary>
/// Scale factor to animate in
/// </summary>
public float ZoomInFactor { get; set; } = 1f;

/// <summary>
/// Scale factor to animate out
/// </summary>
public float ZoomOutFactor { get; set; } = 1.1f;

/// <summary>
/// Gets or sets element entrance easing.
/// </summary>
public override Easing Easing { get; set; } = Easing.Parse("1.0, 0.0, 0.0, 0.85");

protected override CompositionAnimationGroup GetOrCreateEntranceAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

var scaleAnimation = compositor.CreateVector3DKeyFrameAnimation();
scaleAnimation.Duration = Duration;
scaleAnimation.Target = nameof(element.Scale);
scaleAnimation.InsertKeyFrame(StartingCue, new Vector3D(ZoomOutFactor, ZoomOutFactor, 1), Easing);
scaleAnimation.InsertKeyFrame(1.0f, new Vector3D(1, 1, 1), Easing);

var fadeAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeAnimation.Duration = Duration;
fadeAnimation.Target = nameof(element.Opacity);
fadeAnimation.InsertKeyFrame(StartingCue, 0f, Easing);
fadeAnimation.InsertKeyFrame(1.0f, 1f, Easing);

var enteranceAnimation = compositor.CreateAnimationGroup();
enteranceAnimation.Add(scaleAnimation);
enteranceAnimation.Add(fadeAnimation);
return enteranceAnimation;
}

protected override CompositionAnimationGroup GetOrCreateExitAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

var scaleAnimation = compositor.CreateVector3DKeyFrameAnimation();
scaleAnimation.Duration = Duration;
scaleAnimation.Target = nameof(element.Scale);
scaleAnimation.InsertKeyFrame(0f, new Vector3D(1, 1, 1), Easing);
scaleAnimation.InsertKeyFrame(EndingCue, new Vector3D(ZoomOutFactor, ZoomOutFactor, 1), Easing);

var fadeAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeAnimation.Duration = Duration;
fadeAnimation.Target = nameof(element.Opacity);
fadeAnimation.InsertKeyFrame(0f, 1f, Easing);
fadeAnimation.InsertKeyFrame(EndingCue, 0f, Easing);

var exitAnimation = compositor.CreateAnimationGroup();
exitAnimation.Add(scaleAnimation);
exitAnimation.Add(fadeAnimation);
return exitAnimation;
}

protected override CompositionAnimationGroup GetOrCreateSendBackAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

var scaleAnimation = compositor.CreateVector3DKeyFrameAnimation();
scaleAnimation.Duration = Duration;
scaleAnimation.Target = nameof(element.Scale);
scaleAnimation.InsertKeyFrame(0f, new Vector3D(1, 1, 1), Easing);
scaleAnimation.InsertKeyFrame(EndingCue, new Vector3D(ZoomInFactor, ZoomInFactor, 1), Easing);

var fadeAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeAnimation.Duration = Duration;
fadeAnimation.Target = nameof(element.Opacity);
fadeAnimation.InsertKeyFrame(0f, 1f, Easing);
fadeAnimation.InsertKeyFrame(EndingCue, 0f, Easing);

var sendBackAnimation = compositor.CreateAnimationGroup();
sendBackAnimation.Add(scaleAnimation);
sendBackAnimation.Add(fadeAnimation);
return sendBackAnimation;
}

protected override CompositionAnimationGroup GetOrCreateBringBackAnimation(CompositionVisual element, double widthDistance, double heightDistance)
{
var compositor = element.Compositor;

var scaleAnimation = compositor.CreateVector3DKeyFrameAnimation();
scaleAnimation.Duration = Duration;
scaleAnimation.Target = nameof(element.Scale);
scaleAnimation.InsertKeyFrame(StartingCue, new Vector3D(ZoomInFactor, ZoomInFactor, 1), Easing);
scaleAnimation.InsertKeyFrame(1f, new Vector3D(1, 1, 1), Easing);

var fadeAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeAnimation.Duration = Duration;
fadeAnimation.Target = nameof(element.Opacity);
fadeAnimation.InsertKeyFrame(StartingCue, 0f, Easing);
fadeAnimation.InsertKeyFrame(1f, 1f, Easing);

var bringBackAnimation = compositor.CreateAnimationGroup();
bringBackAnimation.Add(scaleAnimation);
bringBackAnimation.Add(fadeAnimation);
return bringBackAnimation;
}

protected override Task RunAnimationAsync(
CompositionVisual parentComposition,
CompositionVisual? fromElement,
CompositionVisual? toElement,
bool forward,
double distance,
double heightDistance,
CancellationToken cancellationToken)
{
if (toElement != null)
toElement.CenterPoint = new Vector3D(parentComposition.Size.X * 0.5, parentComposition.Size.Y * 0.5, 0);

if (fromElement != null)
fromElement.CenterPoint = new Vector3D(parentComposition.Size.X * 0.5, parentComposition.Size.Y * 0.5, 0);

return base.RunAnimationAsync(parentComposition, fromElement, toElement, forward, distance, heightDistance, cancellationToken);
}
}
Loading
Loading