原理是使用StackPanel 的margin属性的偏移来实现轮播的效果

废话不多说直接上代码

AutoPlayCarousel核心代码

[ContentProperty(nameof(Children))]
[TemplatePart(Name = "PART_StackPanel", Type = typeof(StackPanel))]
public class AutoPlayCarousel : Control
{
#region Identifier
/// <summary>
/// 视图区域
/// </summary>
private StackPanel _stkMain;
/// <summary>
///
/// </summary>
private DispatcherTimer _dtAutoPlay;
#endregion #region Constructor
static AutoPlayCarousel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoPlayCarousel), new FrameworkPropertyMetadata(typeof(AutoPlayCarousel)));
}
public AutoPlayCarousel()
{
Loaded += AutoScrollCarousel_Loaded;
SizeChanged += AutoScrollCarousel_SizeChanged;
}
#endregion #region RoutedEvent
public static readonly RoutedEvent IndexChangedEvent = EventManager.RegisterRoutedEvent("IndexChanged", RoutingStrategy.Bubble, typeof(IndexChangedEventHandler), typeof(AutoPlayCarousel));
public event IndexChangedEventHandler IndexChanged
{
add => AddHandler(IndexChangedEvent, value);
remove => RemoveHandler(IndexChangedEvent, value);
}
void RaiseIndexChanged(int newValue)
{
var arg = new IndexChangedEventArgs(newValue, IndexChangedEvent);
RaiseEvent(arg);
}
#endregion #region Property
/// <summary>
/// get the children collection.
/// </summary>
public ObservableCollection<FrameworkElement> Children
{
get => (ObservableCollection<FrameworkElement>)GetValue(ChildrenProperty);
private set => SetValue(ChildrenProperty, value);
} public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(ObservableCollection<FrameworkElement>), typeof(AutoPlayCarousel), new PropertyMetadata(new ObservableCollection<FrameworkElement>()));
/// <summary>
/// get or set orientation
/// </summary>
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
} public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(AutoPlayCarousel), new PropertyMetadata(Orientation.Horizontal)); /// <summary>
/// get or set index
/// </summary>
public int Index
{
get => (int)GetValue(IndexProperty);
set => SetValue(IndexProperty, value);
} public static readonly DependencyProperty IndexProperty =
DependencyProperty.Register("Index", typeof(int), typeof(AutoPlayCarousel), new PropertyMetadata(0, OnIndexChanged)); /// <summary>
/// Gets or sets animation duration.
/// </summary>
public TimeSpan AnimateDuration
{
get => (TimeSpan)GetValue(AnimateDurationProperty);
set => SetValue(AnimateDurationProperty, value);
} public static readonly DependencyProperty AnimateDurationProperty =
DependencyProperty.Register("AnimateDuration", typeof(TimeSpan), typeof(AutoPlayCarousel), new PropertyMetadata(TimeSpan.FromSeconds(0.5))); /// <summary>
/// Gets or sets recyclable.
/// </summary>
public bool Recyclable
{
get => (bool)GetValue(RecyclableProperty);
set => SetValue(RecyclableProperty, value);
} public static readonly DependencyProperty RecyclableProperty =
DependencyProperty.Register("Recyclable", typeof(bool), typeof(AutoPlayCarousel), new PropertyMetadata(false)); public TimeSpan AutoPlayInterval
{
get => (TimeSpan)GetValue(AutoPlayIntervalProperty);
set => SetValue(AutoPlayIntervalProperty, value);
} public static readonly DependencyProperty AutoPlayIntervalProperty =
DependencyProperty.Register("AutoPlayInterval", typeof(TimeSpan), typeof(AutoPlayCarousel), new PropertyMetadata(OnAutoPlayIntervalChanged)); #endregion #region Event Handler
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_stkMain = GetTemplateChild("PART_StackPanel") as StackPanel;
}
private void AutoScrollCarousel_SizeChanged(object sender, SizeChangedEventArgs e)
{
foreach (FrameworkElement children in Children)
{
children.Width = ActualWidth;
children.Height = ActualHeight;
}
}
private void AutoScrollCarousel_Loaded(object sender, RoutedEventArgs e)
{
if (Children == null)
return;
Loaded -= AutoScrollCarousel_Loaded;
foreach (FrameworkElement child in Children)
{
child.Width = ActualWidth;
child.Height = ActualHeight;
}
} private static void OnAutoPlayIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var autoScrollCarousel = d as AutoPlayCarousel;
autoScrollCarousel?.RestartAutoPlayTimer();
} private void DispatcherTimerAutoPlay_Tick(object sender, EventArgs e)
{
Index++;
} private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var autoScrollCarousel = d as AutoPlayCarousel;
if (autoScrollCarousel == null || !autoScrollCarousel.IsLoaded)
return; var targetIndex = 0;
if (!autoScrollCarousel.Recyclable)
targetIndex = autoScrollCarousel.Index > (autoScrollCarousel.Children.Count - 1) ? autoScrollCarousel.Children.Count - 1 : (autoScrollCarousel.Index < 0 ? 0 : autoScrollCarousel.Index);
else
targetIndex = autoScrollCarousel.Index > (autoScrollCarousel.Children.Count - 1) ? 0 : (autoScrollCarousel.Index < 0 ? autoScrollCarousel.Children.Count - 1 : autoScrollCarousel.Index); if (targetIndex != autoScrollCarousel.Index)
{
autoScrollCarousel.Index = targetIndex;
return;
} autoScrollCarousel.ResetAutoPlayTimer();
if (autoScrollCarousel.Orientation == Orientation.Vertical)
{
autoScrollCarousel._stkMain.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
{
To = new Thickness(0, -1 * autoScrollCarousel.ActualHeight * autoScrollCarousel.Index, 0, 0),
Duration = autoScrollCarousel.AnimateDuration,
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
});
}
else
{
autoScrollCarousel._stkMain.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
{
To = new Thickness(-1 * autoScrollCarousel.ActualWidth * autoScrollCarousel.Index, 0, 0, 0),
Duration = autoScrollCarousel.AnimateDuration,
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
});
}
autoScrollCarousel.RaiseIndexChanged(targetIndex);
} #endregion #region Function
private void RestartAutoPlayTimer()
{
if (_dtAutoPlay != null)
{
_dtAutoPlay.Stop();
}
if (AutoPlayInterval.TotalSeconds != 0)
{
_dtAutoPlay = new DispatcherTimer()
{
Interval = AutoPlayInterval,
};
_dtAutoPlay.Tick += DispatcherTimerAutoPlay_Tick;
_dtAutoPlay.Start();
}
} private void ResetAutoPlayTimer()
{
if (_dtAutoPlay != null)
{
_dtAutoPlay.Stop();
_dtAutoPlay.Start();
}
} #endregion
}

  一些辅助代码

public class IndexChangedEventArgs : RoutedEventArgs
{
public IndexChangedEventArgs(int currentIndex, RoutedEvent routedEvent) : base(routedEvent)
{
CurrentIndex = currentIndex;
} public int CurrentIndex { get; set; }
} public delegate void IndexChangedEventHandler(object sender, IndexChangedEventArgs e);

  AutoPlayCarousel默认的样式


<sys:Double x:Key="DefaultFontSize">14</sys:Double>
<sys:Boolean x:Key="DefaultSnapsToDevicePixels">false</sys:Boolean>


<Style TargetType="{x:Type local:AutoPlayCarousel}">
<Setter Property="SnapsToDevicePixels" Value="{StaticResource DefaultSnapsToDevicePixels}" />
<Setter Property="FontSize" Value="{StaticResource DefaultFontSize}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AutoPlayCarousel}">
<StackPanel x:Name="PART_StackPanel" Orientation="{TemplateBinding Orientation}">
<ItemsControl x:Name="PART_ItemsControl" ItemsSource="{TemplateBinding Children}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Orientation="{Binding Orientation,RelativeSource={RelativeSource AncestorType=local:AutoPlayCarousel}}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

  

页面使用

<customControl:AutoPlayCarousel
x:Name="Carousel"
AutoPlayInterval="0:0:3"
Recyclable="True"
Height="1080">
<Grid Background="Red" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="1" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
<Grid Background="Green" > <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="2" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid> </Grid>
<Grid Background="Yellow" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="3" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
<Grid Background="Blue" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="4" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
</customControl:AutoPlayCarousel>

  效果如下:

简易的AutoPlayCarousel 轮播控件的更多相关文章

  1. 简易的DragDropCarousel 拖拽轮播控件

    上一篇文章有写到 自动轮播的控件  简易的AutoPlayCarousel 轮播控件 - 黄高林 - 博客园 (cnblogs.com) 本章是基于自动轮播的一种衍生,通过拖拽鼠标进切换 直接上代码 ...

  2. WPF 控件库——轮播控件

    WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...

  3. 第四十六篇、UICollectionView广告轮播控件

    这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构. #import <UIKit/UIKit.h> # ...

  4. Android之仿京东淘宝的自动无限轮播控件

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...

  5. Android图片轮播控件

    Android广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 使用步骤 Step 1.依赖banner Gradle dependenci ...

  6. jquery轮播控件

    网上找了一个轮播控件,效果不错,而且很容易改,需要的同学去下载咯 地址是:http://download.csdn.net/detail/jine515073/7704143

  7. Android-----------广告图片轮播控件

    Banner广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 很多Android APP中都有广告栏,我也用过很多次了,特来写一篇博文. 先 ...

  8. 一起写一个Android图片轮播控件

    注:本文提到的Android轮播控件Demo地址: Android图片轮播控件 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用 ...

  9. Android 开发最牛的图片轮播控件,基本什么都包含了。

    Android图片轮播控件  源码下载地址: Android 图片轮播 现在的绝大数app都有banner界面,实现循环播放多个广告图片和手动滑动循环等功能.因为ViewPager并不支持循环翻页, ...

随机推荐

  1. C语言- 基础数据结构和算法 - 栈的链式存储

    听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友 ...

  2. DS18B20数字温度计 (三) 1-WIRE总线 ROM搜索算法和实际测试

    目录 DS18B20数字温度计 (一) 电气特性, 寄生供电模式和远距离接线 DS18B20数字温度计 (二) 测温, ROM和CRC算法 DS18B20数字温度计 (三) 1-WIRE总线 ROM搜 ...

  3. 【Java面试】Mybatis中#{}和${}的区别是什么?

    一个工作2年的粉丝,被问到一个Mybatis里面的基础问题. 他跑过来调戏我,说Mic老师,你要是能把这个问题回答到一定高度,请我和一个月奶茶. 这个问题是: "Mybatis里面#{}和$ ...

  4. Django——模板应用

    一.前言 前提:已经用命令提前创建好了项目DjangoTest,以下是基于该项目进行实战演练. 二.项目下创建templates文件夹 1.创建templates文件夹 2.创建HelloWorld. ...

  5. 27.MySQL 索引、事务与存储引擎

    MySQL 索引.事务与存储引擎 目录 MySQL 索引.事务与存储引擎 MySQL 索引 索引的概念 索引的作用及副作用 索引的作用 索引的副作用 创建索引的原则依据 索引的分类和创建 普通索引 唯 ...

  6. numpy学习笔记 01

    NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库. NumPy 是一个运行速度非常快的数学库 ...

  7. Windows下MySQL的安装和删除

    Windows下MySQL的安装和删除 安装Mysql 1 下载mysql 地址 2 安装教程 2.1配置环境变量 变量名:MYSQL_HOME 变量值:D:\software\programming ...

  8. 【主流技术】Redis 在 Spring 框架中的实践

    前言 在Java Spring 项目中,数据与远程数据库的频繁交互对服务器的内存消耗比较大,而 Redis 的特性可以有效解决这样的问题. Redis 的几个特性: Redis 以内存作为数据存储介质 ...

  9. 小白对Java的呐喊

    1 public class Hello{ 2 public static void main(string[] args){ 3 System.out.print("hello world ...

  10. 各大厂的语音识别Speech To Text API使用体验

    最近发现有声读物能极大促进我的睡眠,但每个前面都有一段开场语,想把它剪掉,但是有多个开场语,所以就要用到语音识别判断一下再剪. 前两年在本地搭建过识别的环境,奈何识别准确率不行,只能找找API了,后面 ...