欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > 内容正文

WP7自定义控件 TabSwitch控件

来源: 开发者 投稿于  被查看 19486 次 评论:182

WP7自定义控件 TabSwitch控件


我在写一个类似tabcontrol的选项控件,在很多网站的Menu的效果,不知道怎么取名字,暂时就叫TabSwitch吧。

 

TabSwitch控件要点
1. 类似横排的单选框组,可以多个选项卡,只能选择一个。
2. 可以点击其中一个选择一个选项,选中后背景图块移动到选中项,背景图块的刷子可以自定义
3. 支持选中事件和选择项的绑定。
4. 为了提高视觉效果,有一个动画过度。
 
实现控件要点的方法描述
1 继承ItemsControl控件可以容纳多个Item,并添加TabSwitchItem类
2 图块用一个Rectangle搞定,为了实现移动位置将RenderTransform设置为CompositeTransform。
3 添加一个Selected的event实现选中数据,添加多个SelectItem依赖属性实现绑定。
4 通过选中位置获取相对的X坐标,通过Item长度计算x所在的index,然后应用动画修改CompositeTransform的TranslateX,TranslateX位置设置为index*Item宽度。
5 DoubleAnimation+EasingFunction 的弹簧效果ElasticEase可以实现动画过度。
 
完整代码
 
  View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace KiminozoStudio
{
    public class TabSwitchItem : ContentControl
    {
        public TabSwitchItem()
        {
            this.DefaultStyleKey = typeof(TabSwitchItem);
        }
    }

    public class TabSwitch : ItemsControl
    {
        #region Propertys

        public static readonly DependencyProperty SelectedWidthProperty =
            DependencyProperty.Register("SelectedWidth", typeof(double), typeof(TabSwitch),
                                        new PropertyMetadata(65.0, SelectedWidthPropertyChanged));
        /// <summary>
        /// 选中项的宽度
        /// </summary>
        public double SelectedWidth
        {
            get { return (double)GetValue(SelectedWidthProperty); }
            set { SetValue(SelectedWidthProperty, value); }
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(TabSwitchItem), typeof(TabSwitch),
                                        new PropertyMetadata(null));

        /// <summary>
        /// 选中的TabSwitchItem控件
        /// </summary>
        public TabSwitchItem SelectedItem
        {
            get { return (TabSwitchItem)GetValue(SelectedItemProperty); }
            private set { SetValue(SelectedItemProperty, value); }
        }

        public static readonly DependencyProperty SelectedValueProperty =
            DependencyProperty.Register("SelectedValue", typeof(object), typeof(TabSwitch),
                                        new PropertyMetadata(null));

        /// <summary>
        /// 选中项的内容值
        /// </summary>
        public object SelectedValue
        {
            get { return GetValue(SelectedValueProperty); }
            private set { SetValue(SelectedValueProperty, value); }
        }

        public static readonly DependencyProperty SelectedIndexProperty =
            DependencyProperty.Register("SelectedIndex", typeof(int), typeof(TabSwitch),
                                        new PropertyMetadata(0, SelectedIndexPropertyChanged));
        /// <summary>
        /// 选中项的序号
        /// </summary>
        public int SelectedIndex
        {
            get { return (int)GetValue(SelectedIndexProperty); }
            set { SetValue(SelectedIndexProperty, value); }
        }

        public static readonly DependencyProperty SelectedBackgroundProperty =
            DependencyProperty.Register("SelectedBackground", typeof(Brush), typeof(TabSwitch),
                                        new PropertyMetadata(new SolidColorBrush(Colors.Red),
                                                             SelectedBackgroundPropertyChanged));
        /// <summary>
        /// 选择项的背景刷子
        /// </summary>
        public Brush SelectedBackground
        {
            get { return (Brush)GetValue(SelectedBackgroundProperty); }
            set { SetValue(SelectedBackgroundProperty, value); }
        }

        private static void SelectedBackgroundPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var sender = o as TabSwitch;
            if (sender == null || e.NewValue == e.OldValue) return;
            sender.SetSelectedBackground(e.NewValue as Brush);
        }

        private static void SelectedIndexPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var sender = o as TabSwitch;
            if (sender == null || e.NewValue == e.OldValue) return;

            sender.SetSelectedIndex((int)e.NewValue);
        }

        private static void SelectedWidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var sender = o as TabSwitch;
            if (sender == null || e.NewValue == e.OldValue) return;

            sender.SetSelectedWidth((double)e.NewValue);
        }
        #endregion

        /// <summary>
        /// 背景的方形
        /// </summary>
        private Rectangle rectangle;
        /// <summary>
        /// 选中事件
        /// </summary>
        public event RoutedEventHandler Selected;

        /// <summary>
        /// 触发选中事件
        /// </summary>
        /// <param name="e"></param>
        private void OnSelected(RoutedEventArgs e)
        {
            RoutedEventHandler handler = Selected;
            if (handler != null) handler(this, e);
        }

        /// <summary>
        /// 改变选中项
        /// </summary>
        /// <param name="index">索引序号</param>
        private void ChangeSelected(int index)
        {
            if (index < 0 || index > Items.Count) return;
            ;
            SelectedIndex = index;
            var switchItem = Items[index] as TabSwitchItem;
            if (switchItem != null)
            {
                SelectedItem = switchItem;
                SelectedValue = switchItem.Content;
            }
            else
            {
                SelectedValue = Items[index];
            }
            OnSelected(new RoutedEventArgs());
        }

        public TabSwitch()
        {
            DefaultStyleKey = typeof(TabSwitch);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            rectangle = (Rectangle)GetTemplateChild("rectangle");
            SetSelectedBackground(SelectedBackground);
            SetSelectedWidth(SelectedWidth);
            SetSelectedIndex(SelectedIndex);
        }

        /// <summary>
        /// 设置选中背景的宽度
        /// </summary>
        /// <param name="itemWidth"></param>
        private void SetSelectedWidth(double itemWidth)
        {
            if (rectangle == null) return;
            rectangle.Width = itemWidth;
        }

        /// <summary>
        /// 设置选中背景的刷子
        /// </summary>
        /// <param name="brush"></param>
        private void SetSelectedBackground(Brush brush)
        {
            if (rectangle == null) return;
            rectangle.Fill = brush;
        }

        /// <summary>
        /// 设置选中的项目
        /// </summary>
        /// <param name="index">索引序号</param>
        private void SetSelectedIndex(int index)
        {
            if (rectangle == null) return;
            if (index < 0 || index > Items.Count) return;

            double x = SelectedWidth * index;
            var compositeTransform = (CompositeTransform)rectangle.RenderTransform;
            if (Math.Abs(compositeTransform.TranslateX - x) > 1)
                compositeTransform.TranslateX = SelectedWidth * index;
        }

#if SILVERLIGHT
        /// <summary>
        /// 重写鼠标左键放开事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(this);
            var x = (int)(point.X / SelectedWidth) * SelectedWidth;
            int index = (int)(x / SelectedWidth);
            ShowAnimation(x);
            ChangeSelected(index);

            base.OnMouseLeftButtonUp(e);
        }

#else

        /// <summary>
        /// 重写触摸点中事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTap(GestureEventArgs e)
        {
            Point point = e.GetPosition(this);

            var x = (int) (point.X/SelectedWidth)*SelectedWidth;
            int index = (int) (x/SelectedWidth);
            ShowAnimation(x);
            ChangeSelected(index);
            base.OnTap(e);
        }
#endif

        /// <summary>
        /// 选中后的动画
        /// </summary>
        /// <param name="x"></param>
        private void ShowAnimation(double x)
        {
            //移动X坐标,并使用EasingFunction的弹簧特效
            var animation = new DoubleAnimation
                                {
                                    Duration = new Duration(new TimeSpan(0, 0, 0, 0, 500)),
                                    To = x,
                                    EasingFunction =
                                        new ElasticEase { EasingMode = EasingMode.EaseOut, Oscillations = 1, Springiness = 5 }
                                };
            Storyboard.SetTarget(animation, rectangle);
            Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateX)"));
            var storyboard = new Storyboard();
            storyboard.Children.Add(animation);
            storyboard.Begin();
        }
    }
}

 
对应的Generic.xaml
 
  View Code
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:KiminozoStudio">

    <Style TargetType="local:TabSwitch">
        <Setter Property="Width" Value="400"/>
        <Setter Property="Height" Value="50"/>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TabSwitch">
                    <Grid>
                        <Rectangle x:Name="rectangle" Width="65" Height="40" RadiusY="5" RadiusX="5"
                                Fill="Red" HorizontalAlignment="Left">
                            <Rectangle.RenderTransform>
                                <CompositeTransform/>
                            </Rectangle.RenderTransform>
                        </Rectangle>
                        <ItemsPresenter/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="local:TabSwitchItem">
        <Setter Property="Width" Value="65"/>
        <Setter Property="Height" Value="40"/>
        <Setter Property="Margin" Value="0,10,0,3"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TabSwitchItem">
                    <TextBlock Text="{TemplateBinding Content}" TextAlignment="Center" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

 
测试代码:
<my:TabSwitch Height="56" HorizontalAlignment="Left" Margin="52,21,0,0" x:Name="tabSwitch1" VerticalAlignment="Top" Width="349" d:IsHidden="True" FontSize="16">
            <my:TabSwitchItem Content="选项1"/>
            <my:TabSwitchItem Content="选项2"/>
            <my:TabSwitchItem Content="选项3"/>
            <my:TabSwitchItem Content="选项4"/>
            <my:TabSwitchItem Content="选项5"/>
        </my:TabSwitch>


 摘自  Kiminozo's Tech Blog 

相关文章

    暂无相关文章
相关频道:

用户评论