顶顶顶顶

This commit is contained in:
tanglong 2025-09-23 10:15:06 +08:00
parent 82d2a5fe6b
commit be337abd61
5 changed files with 132 additions and 164 deletions

View File

@ -2,10 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
Title="CoverFlow Demo" Height="400" Width="800"> Title="Home" Height="400" Width="800">
<Grid> <Grid>
<!--<local:CoverFlowControl x:Name="coverFlow"/>--> <local:CoverFlowControl x:Name="coverFlow" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<local:CoverFlowControl1 x:Name="coverFlow1"/>
</Grid> </Grid>
</Window> </Window>

View File

@ -2,12 +2,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Shapes; using System.Windows.Controls;
using System.IO; using System.Windows.Media;
using System.Windows.Media.Animation;
using Wpf_AiSportsMicrospace.MyUserControl; using Wpf_AiSportsMicrospace.MyUserControl;
namespace Wpf_AiSportsMicrospace namespace Wpf_AiSportsMicrospace
@ -21,20 +23,18 @@ namespace Wpf_AiSportsMicrospace
{ {
InitializeComponent(); InitializeComponent();
string projectRoot = System.IO.Path.Combine(AppContext.BaseDirectory, @"..\..\.."); string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\..");
string albumPath = System.IO.Path.Combine(projectRoot, "Resources", "Img", "Album"); string albumPath = Path.Combine(projectRoot, "Resources", "Img", "Album");
ObservableCollection<CoverImage> images = new ObservableCollection<CoverImage>() // 转换为 Uri
{ coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "1.jpg")));
new CoverImage( System.IO.Path.Combine(albumPath, "1.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/1.jpg")), coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "2.jpg")));
new CoverImage( System.IO.Path.Combine(albumPath, "2.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/2.jpg")), coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "3.jpg")));
new CoverImage( System.IO.Path.Combine(albumPath, "3.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/3.jpg")), coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "4.jpg")));
new CoverImage( System.IO.Path.Combine(albumPath, "4.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/4.jpg")), coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "5.jpg")));
new CoverImage( System.IO.Path.Combine(albumPath, "5.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/5.jpg")),
};
// 设置 CoverFlow 图片s // 默认选中第3张
//coverFlow.SetImages(images, defaultSelectedIndex: 2); coverFlow.SelectedIndex = 2;
} }
} }
} }

View File

@ -4,103 +4,29 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
mc:Ignorable="d" > Height="300" Width="600">
<UserControl.Resources> <Grid ClipToBounds="True" Background="Transparent">
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <ItemsControl x:Name="ItemsHost" ItemsSource="{Binding Images, RelativeSource={RelativeSource AncestorType=UserControl}}">
<Style x:Key="ImageBorderStyle" TargetType="Border">
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
To="1.2" Duration="0:0:0.3"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
To="1.2" Duration="0:0:0.3"/>
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color"
To="Red" Duration="0:0:0.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
To="0.8" Duration="0:0:0.3"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
To="0.8" Duration="0:0:0.3"/>
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color"
To="Transparent" Duration="0:0:0.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl x:Name="VisibleImagesControl">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/> <Canvas/>
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ItemsControl.ItemsPanel> </ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid> <Border x:Name="ImageContainer" RenderTransformOrigin="0.5,0.5"
<!-- 主图片 --> MouseLeftButtonDown="Image_MouseLeftButtonDown">
<Border Style="{StaticResource ImageBorderStyle}" MouseLeftButtonDown="Image_MouseLeftButtonDown"> <Border.RenderTransform>
<Image Source="{Binding Path}" Width="150" Height="200"/> <TransformGroup>
<ScaleTransform x:Name="scale" ScaleX="1" ScaleY="1"/>
<TranslateTransform x:Name="translate" X="0" Y="0"/>
</TransformGroup>
</Border.RenderTransform>
<Image Source="{Binding}" Stretch="UniformToFill" Width="150" Height="200"/>
</Border> </Border>
<!-- 小徽章 logo添加淡入淡出动画 -->
<Image Source="{Binding BadgePath}" Width="50" Height="50"
HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="0,-25,0,0">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="1" Duration="0:0:0.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0" Duration="0:0:0.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Grid>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
</StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -11,6 +12,7 @@ using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
@ -22,77 +24,118 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
/// </summary> /// </summary>
public partial class CoverFlowControl : UserControl public partial class CoverFlowControl : UserControl
{ {
public ObservableCollection<CoverImage> AllImages { get; set; } = new ObservableCollection<CoverImage>(); public ObservableCollection<Uri> Images { get; set; } = new ObservableCollection<Uri>();
public ObservableCollection<CoverImage> VisibleImages { get; set; } = new ObservableCollection<CoverImage>();
private int selectedIndex = 0; private int _selectedIndex = 0;
public int SelectedIndex
{
get => _selectedIndex;
set
{
if (value < 0 || value >= Images.Count) return;
_selectedIndex = value;
UpdateLayoutWithAnimation();
}
}
public CoverFlowControl() public CoverFlowControl()
{ {
InitializeComponent(); InitializeComponent();
VisibleImagesControl.ItemsSource = VisibleImages; DataContext = this;
Loaded += (s, e) => UpdateLayoutWithAnimation(true);
} }
#region Public Methods
public void SetImages(ObservableCollection<CoverImage> images, int defaultSelectedIndex = 0)
{
AllImages = images;
selectedIndex = defaultSelectedIndex;
UpdateVisibleImages();
}
#endregion
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ {
if (sender is Border border && border.DataContext is CoverImage img) if (sender is Border border)
{ {
int index = AllImages.IndexOf(img); var container = ItemsHost.ItemContainerGenerator.ContainerFromItem(border.DataContext) as ContentPresenter;
if (index >= 0) if (container != null)
{ {
selectedIndex = index; int index = ItemsHost.ItemContainerGenerator.IndexFromContainer(container);
UpdateVisibleImages(); SelectedIndex = index;
} }
} }
} }
private void UpdateVisibleImages() private void UpdateLayoutWithAnimation(bool instant = false)
{ {
VisibleImages.Clear(); double centerX = ActualWidth / 2;
for (int offset = -1; offset <= 1; offset++) double spacing = 180;
double sideScale = 0.8;
double centerScale = 1.2;
for (int i = 0; i < ItemsHost.Items.Count; i++)
{ {
int idx = selectedIndex + offset; var container = ItemsHost.ItemContainerGenerator.ContainerFromIndex(i) as ContentPresenter;
if (idx >= 0 && idx < AllImages.Count) if (container == null) continue;
var border = FindVisualChild<Border>(container);
if (border == null) continue;
var transformGroup = border.RenderTransform as TransformGroup;
var scale = transformGroup.Children[0] as ScaleTransform;
var translate = transformGroup.Children[1] as TranslateTransform;
double targetX;
double targetScale;
double targetOpacity;
if (i == SelectedIndex)
{ {
var img = AllImages[idx]; targetX = centerX - 75;
img.IsSelected = offset == 0; targetScale = centerScale;
VisibleImages.Add(img); targetOpacity = 1.0;
} }
else if (i == SelectedIndex - 1)
{
targetX = centerX - spacing - 75;
targetScale = sideScale;
targetOpacity = 1.0;
}
else if (i == SelectedIndex + 1)
{
targetX = centerX + spacing - 75;
targetScale = sideScale;
targetOpacity = 1.0;
}
else
{
targetX = centerX - 75;
targetScale = sideScale;
targetOpacity = 0.0;
}
if (instant)
{
translate.X = targetX;
scale.ScaleX = scale.ScaleY = targetScale;
border.Opacity = targetOpacity;
}
else
{
translate.BeginAnimation(TranslateTransform.XProperty,
new DoubleAnimation(targetX, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() });
scale.BeginAnimation(ScaleTransform.ScaleXProperty,
new DoubleAnimation(targetScale, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() });
scale.BeginAnimation(ScaleTransform.ScaleYProperty,
new DoubleAnimation(targetScale, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() });
border.BeginAnimation(Border.OpacityProperty,
new DoubleAnimation(targetOpacity, TimeSpan.FromMilliseconds(400)));
} }
} }
} }
public class CoverImage : INotifyPropertyChanged private static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{ {
public string Path { get; set; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
public string BadgePath { get; set; }
private bool _isSelected;
public bool IsSelected
{ {
get => _isSelected; var child = VisualTreeHelper.GetChild(obj, i);
set { _isSelected = value; OnPropertyChanged(nameof(IsSelected)); } if (child is T target) return target;
var result = FindVisualChild<T>(child);
if (result != null) return result;
} }
return null;
public CoverImage(string path, string badgePath = null)
{
Path = path;
BadgePath = badgePath;
} }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
} }
} }

View File

@ -32,6 +32,7 @@
<PackageReference Include="FFmpeg.AutoGen" Version="7.1.1" /> <PackageReference Include="FFmpeg.AutoGen" Version="7.1.1" />
<PackageReference Include="FFmpeg.AutoGen.Abstractions" Version="7.1.1" /> <PackageReference Include="FFmpeg.AutoGen.Abstractions" Version="7.1.1" />
<PackageReference Include="FFmpeg.AutoGen.Bindings.DynamicallyLoaded" Version="7.1.1" /> <PackageReference Include="FFmpeg.AutoGen.Bindings.DynamicallyLoaded" Version="7.1.1" />
<PackageReference Include="HandyControl" Version="3.5.1" />
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
<PackageReference Include="Microsoft.ML" Version="4.0.2" /> <PackageReference Include="Microsoft.ML" Version="4.0.2" />
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.22.1" /> <PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.22.1" />