这里的ItemsControl指的是Xaml里的集合控件,包括ListView,GridView等,此篇博客主要参考MSDN Blog的一篇文章,具体出处为:http://blogs.msdn.com/b/mim/archive/2013/04/16/winrt-create-a-custom-itemspanel-for-an-itemscontrol.aspx ,同时做了对Windows Phone的一些修改和适配。
首先,正常的GridView,和ListView的样式我就不在这里列出了,今天我们重点谈的就是如何实现一个圆形布局的ListView/Gridview。
自定义圆形ItemsControl
Windows Phone 8.1 Windows
这里我填充的Item只是简单的Image,但是并不妨碍其实现效果,这样的布局完全可以带来更惊艳的交互体验。
同时如原文所说这里提供的源码只是实现基本布局,并未提供更多的动画,手势,交互等功能,大家可以自行填充。
为了实现自定义的布局,我们需要自定义ItemsPanel来替换ItemsControl的模版,我们自定义的ItemsPanel必须继承于Panel类。
下面我们需要重写以下两个方法 :
- MeasureOverride :使用MeasureOverride方法来报告你所需空间的数量
- ArrangeOverride : 使用ArrangeOverride方法在你的ItemsPanel中真实的布局Item
//CircleItemsPanel.cs
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml; namespace CustomItemsPanel
{
public class CircleItemsPanel :Panel
{
public double Radius {
get {
return (Double)GetValue(RadiusProperty);
}
set {
SetValue(RadiusProperty, value);
} }
public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register(
"Radius", typeof(Double),typeof(CircleItemsPanel),new PropertyMetadata(100d,RadiusCallBack)); private static void RadiusCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var radialPanel = (CircleItemsPanel)d;
radialPanel.InvalidateArrange();
} protected override Size MeasureOverride(Size availableSize)
{
var s= base.MeasureOverride(availableSize);
foreach (var element in this.Children)
{
element.Measure(availableSize);
}
return s;
}
protected override Size ArrangeOverride(Size finalSize)
{
this.Clip = new RectangleGeometry {Rect=new Rect (,,finalSize.Width,finalSize.Height) };
var i = ;
var degreesOffset = 360.0 / this.Children.Count;
foreach(var elemet in this.Children)
{
var centerX = elemet.DesiredSize.Width / 2.0;
var centerY = elemet.DesiredSize.Height / 2.0;
var degreesAngle = degreesOffset * i++;
var transform = new RotateTransform { CenterX=centerX,CenterY=centerY,Angle=degreesAngle };
elemet.RenderTransform = transform;
var radianAngle = (Math.PI * degreesAngle) / 180.0;
var x = this.Radius * Math.Cos(radianAngle);
var y = this.Radius * Math.Sin(radianAngle);
var rectX = x + finalSize.Width / - centerX;
var rectY = y + finalSize.Height / - centerY;
elemet.Arrange(new Rect(rectX,rectY,elemet.DesiredSize.Width,elemet.DesiredSize.Height));
}
return finalSize;
}
}
}
至于里面数学知识的应用我就不细说,我大天朝的基础教育还是杠杠滴,贴张图大家就会明白的。
在Xaml中使用我们的圆形Panel,到此就大功告成啦。
<Page
x:Class="CustomItemsPsnnel.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CustomItemsPsnnel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" DataContext="{Binding Path=Main, Source={StaticResource Locator}}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid>
<TextBlock HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}" Text="{Binding Title}"/>
<GridView HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:CircleItemsPanel Radius="" Height="" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.Items>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
<Image Width="" Source="iTunesArtwork.png"/>
</GridView.Items>
</GridView>
</Grid>
</Page>
总结了一下,发现原来Xaml下的自定义控件可以这么简单,这么*,实在给我后续的开发打开了一扇新的大门,以前的自定义都只是限于定制Style,Template,相信以后回有更多好玩app会诞生,最后贴张图。