From be337abd61fac15467b1f1d69ceef144b87475ff Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Tue, 23 Sep 2025 10:15:06 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B6=E9=A1=B6=E9=A1=B6=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Wpf_AiSportsMicrospace/Home.xaml | 6 +- Wpf_AiSportsMicrospace/Home.xaml.cs | 30 ++-- .../MyUserControl/CoverFlowControl.xaml | 120 +++------------ .../MyUserControl/CoverFlowControl.xaml.cs | 139 ++++++++++++------ .../Wpf_AiSportsMicrospace.csproj | 1 + 5 files changed, 132 insertions(+), 164 deletions(-) diff --git a/Wpf_AiSportsMicrospace/Home.xaml b/Wpf_AiSportsMicrospace/Home.xaml index 3532627..8e8d7ab 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml +++ b/Wpf_AiSportsMicrospace/Home.xaml @@ -2,10 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" - Title="CoverFlow Demo" Height="400" Width="800"> + Title="Home" Height="400" Width="800"> - - - + diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs index f56b0d9..b24d4d1 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Home.xaml.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; -using System.Windows.Shapes; -using System.IO; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; using Wpf_AiSportsMicrospace.MyUserControl; namespace Wpf_AiSportsMicrospace @@ -21,20 +23,18 @@ namespace Wpf_AiSportsMicrospace { InitializeComponent(); - string projectRoot = System.IO.Path.Combine(AppContext.BaseDirectory, @"..\..\.."); - string albumPath = System.IO.Path.Combine(projectRoot, "Resources", "Img", "Album"); + string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\.."); + string albumPath = Path.Combine(projectRoot, "Resources", "Img", "Album"); - ObservableCollection images = new ObservableCollection() - { - new CoverImage( System.IO.Path.Combine(albumPath, "1.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/1.jpg")), - new CoverImage( System.IO.Path.Combine(albumPath, "2.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/2.jpg")), - new CoverImage( System.IO.Path.Combine(albumPath, "3.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/3.jpg")), - new CoverImage( System.IO.Path.Combine(albumPath, "4.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/4.jpg")), - new CoverImage( System.IO.Path.Combine(albumPath, "5.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/5.jpg")), - }; + // 转换为 Uri + coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "1.jpg"))); + coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "2.jpg"))); + coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "3.jpg"))); + coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "4.jpg"))); + coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "5.jpg"))); - // 设置 CoverFlow 图片s - //coverFlow.SetImages(images, defaultSelectedIndex: 2); + // 默认选中第3张 + coverFlow.SelectedIndex = 2; } } -} \ No newline at end of file +} diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml index 20a55b1..279a0d2 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml @@ -4,103 +4,29 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" - mc:Ignorable="d" > - - + Height="300" Width="600"> + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs index a66f488..c4e437f 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -11,6 +12,7 @@ using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; @@ -22,77 +24,118 @@ namespace Wpf_AiSportsMicrospace.MyUserControl /// public partial class CoverFlowControl : UserControl { - public ObservableCollection AllImages { get; set; } = new ObservableCollection(); - public ObservableCollection VisibleImages { get; set; } = new ObservableCollection(); + public ObservableCollection Images { get; set; } = new ObservableCollection(); - 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() { InitializeComponent(); - VisibleImagesControl.ItemsSource = VisibleImages; + DataContext = this; + Loaded += (s, e) => UpdateLayoutWithAnimation(true); } - #region Public Methods - - public void SetImages(ObservableCollection images, int defaultSelectedIndex = 0) - { - AllImages = images; - selectedIndex = defaultSelectedIndex; - UpdateVisibleImages(); - } - - #endregion - 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); - if (index >= 0) + var container = ItemsHost.ItemContainerGenerator.ContainerFromItem(border.DataContext) as ContentPresenter; + if (container != null) { - selectedIndex = index; - UpdateVisibleImages(); + int index = ItemsHost.ItemContainerGenerator.IndexFromContainer(container); + SelectedIndex = index; } } } - private void UpdateVisibleImages() + private void UpdateLayoutWithAnimation(bool instant = false) { - VisibleImages.Clear(); - for (int offset = -1; offset <= 1; offset++) + double centerX = ActualWidth / 2; + double spacing = 180; + double sideScale = 0.8; + double centerScale = 1.2; + + for (int i = 0; i < ItemsHost.Items.Count; i++) { - int idx = selectedIndex + offset; - if (idx >= 0 && idx < AllImages.Count) + var container = ItemsHost.ItemContainerGenerator.ContainerFromIndex(i) as ContentPresenter; + if (container == null) continue; + + var border = FindVisualChild(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]; - img.IsSelected = offset == 0; - VisibleImages.Add(img); + targetX = centerX - 75; + targetScale = centerScale; + 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 - { - public string Path { get; set; } - public string BadgePath { get; set; } - - private bool _isSelected; - public bool IsSelected + private static T FindVisualChild(DependencyObject obj) where T : DependencyObject { - get => _isSelected; - set { _isSelected = value; OnPropertyChanged(nameof(IsSelected)); } + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) + { + var child = VisualTreeHelper.GetChild(obj, i); + if (child is T target) return target; + var result = FindVisualChild(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)); } } diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index 202d83a..b0f7d6a 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -32,6 +32,7 @@ +