chore: add avalonia TabControlSliding demo.
This commit is contained in:
1 parent
045ced1c73
commit
3e2869865d
6 files changed
+423
-12
No files matched your search
@@ -9,6 +9,93 @@
|
||||
ItemHeight="200"
|
||||
MaxWidth="832"
|
||||
ChildWrapping="Wrap">
|
||||
<TabControl SelectedIndex="3"
|
||||
Theme="{StaticResource TabControlSliding}">
|
||||
<TabItem Header="Title1">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="1" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title22">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="2" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title333">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="3" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title4444">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="4" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title55555">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="5" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
<TabControl Theme="{StaticResource TabControlSliding}"
|
||||
TabStripPlacement="Bottom">
|
||||
<TabItem Header="Title1">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="1" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title22"
|
||||
IsEnabled="False">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="2" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title333">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="3" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title4444">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="4" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
<TabItem Header="Title55555">
|
||||
<Border>
|
||||
<TextBlock Theme="{StaticResource TextBlockLargeBold}">
|
||||
<Run Text="Text" />
|
||||
<Run Text="5" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
<TabControl TabStripPlacement="Right">
|
||||
<TabItem Header="Title1">
|
||||
<Border>
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementSliding, Type = typeof(Layoutable))]
|
||||
public class SlidingTabContainer : ContentControl
|
||||
{
|
||||
private const string ElementSliding = "PART_Sliding";
|
||||
|
||||
private Control? _sliding;
|
||||
private TabControl? _tabControl;
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
OnSelectionChanged(null, null!);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
if (_tabControl is not null)
|
||||
{
|
||||
_tabControl.SelectionChanged -= OnSelectionChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
_tabControl = VisualHelper.GetParent<TabControl>(this);
|
||||
if (_tabControl is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tabControl.SelectionChanged += OnSelectionChanged;
|
||||
|
||||
_sliding = e.NameScope.Find<Control>(ElementSliding);
|
||||
if (_sliding is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
OnSelectionChanged(null, null!);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(SizeChangedEventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
|
||||
if (_tabControl is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnSelectionChanged(null, null!);
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
const int animationSpeed = 200;
|
||||
|
||||
if (_sliding is null || _tabControl?.SelectedItem is null || !IsLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tabControl.ContainerFromItem(_tabControl.SelectedItem) is not TabItem tabItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var padding = Padding;
|
||||
Point? offset = tabItem.TranslatePoint(new Point(-padding.Left, -padding.Top), this);
|
||||
if (offset is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
new Animation
|
||||
{
|
||||
FillMode = FillMode.Forward,
|
||||
Duration = TimeSpan.FromMilliseconds(animationSpeed),
|
||||
Easing = new QuadraticEaseOut(),
|
||||
Children =
|
||||
{
|
||||
new KeyFrame
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter(WidthProperty, tabItem.Bounds.Width),
|
||||
new Setter(HeightProperty, tabItem.Bounds.Height),
|
||||
new Setter(TranslateTransform.XProperty, offset.Value.X),
|
||||
new Setter(TranslateTransform.YProperty, offset.Value.Y),
|
||||
},
|
||||
Cue = new Cue(1),
|
||||
}
|
||||
}
|
||||
}.RunAsync(_sliding);
|
||||
}
|
||||
}
|
||||
@@ -402,4 +402,196 @@
|
||||
Value="{DynamicResource TextIconBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="SlidingTabContainerBaseStyle"
|
||||
TargetType="hc:SlidingTabContainer">
|
||||
<Setter Property="Focusable"
|
||||
Value="False" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="HorizontalAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="Padding"
|
||||
Value="2" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Border HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Panel>
|
||||
<Border x:Name="PART_Sliding"
|
||||
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Width="0"
|
||||
Height="0"
|
||||
Effect="{StaticResource EffectShadow1}"
|
||||
Background="{Binding Path=(hc:TitleElement.Background),RelativeSource={RelativeSource TemplatedParent}}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top" />
|
||||
<ContentPresenter Content="{TemplateBinding Content}" />
|
||||
</Panel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="{x:Type hc:SlidingTabContainer}"
|
||||
BasedOn="{StaticResource SlidingTabContainerBaseStyle}"
|
||||
TargetType="hc:SlidingTabContainer" />
|
||||
|
||||
<ControlTheme x:Key="TabItemSliding"
|
||||
TargetType="TabItem">
|
||||
<Setter Property="BorderBrush"
|
||||
Value="{DynamicResource BorderBrush}" />
|
||||
<Setter Property="Background"
|
||||
Value="Transparent" />
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource PrimaryTextBrush}" />
|
||||
<Setter Property="BorderThickness"
|
||||
Value="0" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="{StaticResource DefaultControlHeight}" />
|
||||
<Setter Property="Padding"
|
||||
Value="10,0" />
|
||||
<Setter Property="CornerRadius"
|
||||
Value="{Binding $self.(hc:BorderElement.CornerRadius)}" />
|
||||
<Setter Property="hc:BorderElement.CornerRadius"
|
||||
Value="{StaticResource DefaultCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Border x:Name="rootBorder"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}">
|
||||
<ContentPresenter Name="PART_ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
RecognizesAccessKey="True" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style Selector="^:disabled">
|
||||
<Setter Property="Opacity"
|
||||
Value="0.4" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:pointerover">
|
||||
<Setter Property="Opacity"
|
||||
Value="0.9" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding $self.(hc:TitleElement.Foreground)}" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="TabControlSliding"
|
||||
TargetType="TabControl">
|
||||
<Setter Property="BorderThickness"
|
||||
Value="1" />
|
||||
<Setter Property="BorderBrush"
|
||||
Value="{DynamicResource BorderBrush}" />
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource SecondaryRegionBrush}" />
|
||||
<Setter Property="ItemContainerTheme"
|
||||
Value="{StaticResource TabItemSliding}" />
|
||||
<Setter Property="CornerRadius"
|
||||
Value="{Binding $self.(hc:BorderElement.CornerRadius)}" />
|
||||
<Setter Property="hc:BorderElement.CornerRadius"
|
||||
Value="{StaticResource DefaultCornerRadius}" />
|
||||
<Setter Property="hc:TitleElement.Background"
|
||||
Value="{DynamicResource RegionBrush}" />
|
||||
<Setter Property="hc:TitleElement.Foreground"
|
||||
Value="{DynamicResource PrimaryTextBrush}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<DockPanel>
|
||||
<hc:SlidingTabContainer x:Name="tabContainer"
|
||||
Background="{TemplateBinding Background}">
|
||||
<ItemsPresenter Name="PART_ItemsPresenter"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" />
|
||||
</hc:SlidingTabContainer>
|
||||
<Border Padding="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter Name="PART_SelectedContentHost"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding SelectedContent}"
|
||||
ContentTemplate="{TemplateBinding SelectedContentTemplate}" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Top] /template/ hc|SlidingTabContainer#tabContainer">
|
||||
<Setter Property="DockPanel.Dock"
|
||||
Value="Top" />
|
||||
<Setter Property="Margin"
|
||||
Value="0,0,0,6" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Bottom] /template/ hc|SlidingTabContainer#tabContainer">
|
||||
<Setter Property="DockPanel.Dock"
|
||||
Value="Bottom" />
|
||||
<Setter Property="Margin"
|
||||
Value="0,6,0,0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Left] /template/ hc|SlidingTabContainer#tabContainer">
|
||||
<Setter Property="DockPanel.Dock"
|
||||
Value="Left" />
|
||||
<Setter Property="Margin"
|
||||
Value="0,0,6,0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Right] /template/ hc|SlidingTabContainer#tabContainer">
|
||||
<Setter Property="DockPanel.Dock"
|
||||
Value="Right" />
|
||||
<Setter Property="Margin"
|
||||
Value="6,0,0,0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Left], ^[TabStripPlacement=Right]">
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[TabStripPlacement=Top], ^[TabStripPlacement=Bottom]">
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,17 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace HandyControl.Tools;
|
||||
|
||||
public static class VisualHelper
|
||||
{
|
||||
public static T? GetParent<T>(Visual? visual) where T : Visual =>
|
||||
visual switch
|
||||
{
|
||||
null => default,
|
||||
T t => t,
|
||||
Window _ => null,
|
||||
_ => GetParent<T>(visual.GetVisualParent())
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -9,7 +9,7 @@ public class TabItemCapsuleThemeSelector : ThemeSelector
|
||||
{
|
||||
public override ControlTheme? SelectTheme(object? item, AvaloniaObject? container)
|
||||
{
|
||||
if (container is not TabItem { Parent: TabControl tabControl } tabItem)
|
||||
if (container is not TabItem tabItem || VisualHelper.GetParent<TabControl>(tabItem) is not { } tabControl)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -37,14 +37,16 @@ public class SlidingTabContainer : ContentControl
|
||||
_tabControl = VisualHelper.GetParent<System.Windows.Controls.TabControl>(this);
|
||||
_sliding = GetTemplateChild(ElementSliding) as FrameworkElement;
|
||||
|
||||
if (_tabControl is not null)
|
||||
if (_tabControl is null)
|
||||
{
|
||||
_tabControl.SelectionChanged += OnSelectionChanged;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
OnSelectionChanged(null, null);
|
||||
}
|
||||
_tabControl.SelectionChanged += OnSelectionChanged;
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
OnSelectionChanged(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,31 +82,31 @@ public class SlidingTabContainer : ContentControl
|
||||
if (useAnimation)
|
||||
{
|
||||
var storyboard = new Storyboard();
|
||||
var easingFuction = new PowerEase
|
||||
var easingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut,
|
||||
};
|
||||
|
||||
var widthAnimation = AnimationHelper.CreateAnimation(tabWidth);
|
||||
widthAnimation.EasingFunction = easingFuction;
|
||||
widthAnimation.EasingFunction = easingFunction;
|
||||
Storyboard.SetTarget(widthAnimation, _sliding);
|
||||
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(WidthProperty.Name));
|
||||
storyboard.Children.Add(widthAnimation);
|
||||
|
||||
var heightAnimation = AnimationHelper.CreateAnimation(tabHeight);
|
||||
heightAnimation.EasingFunction = easingFuction;
|
||||
heightAnimation.EasingFunction = easingFunction;
|
||||
Storyboard.SetTarget(heightAnimation, _sliding);
|
||||
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(HeightProperty.Name));
|
||||
storyboard.Children.Add(heightAnimation);
|
||||
|
||||
var xAnimation = AnimationHelper.CreateAnimation(offset.X);
|
||||
xAnimation.EasingFunction = easingFuction;
|
||||
xAnimation.EasingFunction = easingFunction;
|
||||
Storyboard.SetTarget(xAnimation, _sliding);
|
||||
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
|
||||
storyboard.Children.Add(xAnimation);
|
||||
|
||||
var yAnimation = AnimationHelper.CreateAnimation(offset.Y);
|
||||
yAnimation.EasingFunction = easingFuction;
|
||||
yAnimation.EasingFunction = easingFunction;
|
||||
Storyboard.SetTarget(yAnimation, _sliding);
|
||||
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));
|
||||
storyboard.Children.Add(yAnimation);
|
||||
|
||||
Reference in new issue
Block a user