简易的AutoPlayCarousel 轮播控件
原理是使用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 轮播控件的更多相关文章
- 简易的DragDropCarousel 拖拽轮播控件
上一篇文章有写到 自动轮播的控件 简易的AutoPlayCarousel 轮播控件 - 黄高林 - 博客园 (cnblogs.com) 本章是基于自动轮播的一种衍生,通过拖拽鼠标进切换 直接上代码 ...
- WPF 控件库——轮播控件
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- 第四十六篇、UICollectionView广告轮播控件
这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构. #import <UIKit/UIKit.h> # ...
- Android之仿京东淘宝的自动无限轮播控件
在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...
- Android图片轮播控件
Android广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 使用步骤 Step 1.依赖banner Gradle dependenci ...
- jquery轮播控件
网上找了一个轮播控件,效果不错,而且很容易改,需要的同学去下载咯 地址是:http://download.csdn.net/detail/jine515073/7704143
- Android-----------广告图片轮播控件
Banner广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 很多Android APP中都有广告栏,我也用过很多次了,特来写一篇博文. 先 ...
- 一起写一个Android图片轮播控件
注:本文提到的Android轮播控件Demo地址: Android图片轮播控件 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用 ...
- Android 开发最牛的图片轮播控件,基本什么都包含了。
Android图片轮播控件 源码下载地址: Android 图片轮播 现在的绝大数app都有banner界面,实现循环播放多个广告图片和手动滑动循环等功能.因为ViewPager并不支持循环翻页, ...
随机推荐
- 架构师必备:系统容量现状checklist
正如飞机在起飞前,机长.副机长要过一遍checklist检查,确认没问题了才能起飞.楼主也整理了一个系统容量现状checklist,方便对照检查.本文搭配架构师必备:如何做容量预估和调优,食用更佳. ...
- 使用 DartPad 制作代码实践教程
DartPad 是一个开源的.在浏览器中体验和运行 Dart 编程语言的线上编辑器,目标是为了帮助开发者更好地了解 Dart 编程语言以及 Flutter 应用开发. DartPad 项目起始于 20 ...
- LVGL库入门教程03-布局方式
LVGL布局方式 LVGL的布局 上一节介绍了如何在 LVGL 中创建控件.如果在创建控件时不给控件安排布局,那么控件默认会被放在父容器的左上角. 可以使用 lv_obj_set_pos(obj, x ...
- Xilinx DMA的几种方式与架构
DMA是direct memory access,在FPGA系统中,常用的几种DMA需求: 1. 在PL内部无PS(CPU这里统一称为PS)持续干预搬移数据,常见的接口形态为AXIS与AXI,AXI与 ...
- react native 0.6x 在创建项目时,CocoaPods 的依赖安装步骤卡解决方案
前言 你需要做两件事 gem换源 pod repo 换源 实战 如果你已经成功安装了CocoaPods.那么这里你需要卸载它.gem换源1. 卸载CocoaPods 查看gem安装的东西 gem li ...
- Hexo + VSCode 插入 Markdown 图片解决办法
最近打开 typora 时发现弹窗强更,不让用 beta 版了 想到自己并不是非常需要 WYSIWYG,而且也不是经常使用 typora,于是直接退回到 VSCode 了,而且在 VSCode 里可以 ...
- 内存分析器 (MAT)
内存分析器 (MAT) 1. 内存分析器 (MAT) 1.1 MAT介绍 MAT是Memory Analyzer tool的缩写.指分析工具. 1.2 MAT作用 Eclipse Memory ...
- 边缘计算 KubeEdge+EdgeMash
简介 KubeEdge是面向边缘计算场景.专为边云协同设计的业界首个云原生边缘计算框架,在 Kubernetes 原生的容器编排调度能力之上实现了边云之间的应用协同.资源协同.数据协同和设备协同等能力 ...
- NLM5系列中继采集仪的常见问题
NLM5系列中继采集采发仪常见问题 1.UART 通讯问题使用 UART 接口时一定要确认收发双方的通讯参数完全一致,包括通讯速率.数据位.校验位.停止位参数.NLM 在上电时会主动输出设备基本信息, ...
- freeswitch的话单模块
概述 最近因为业务需要,在看freeswitch中话单相关的一些模块. 在voip的使用过程中,话单是重要的基础模块,涉及到计费和问题查找. 呼叫话单最重要的一点是稳定,不能有错误或遗漏. 本章对fs ...