zoukankan      html  css  js  c++  java
  • WP8 FlipView

      一直想写点东西,直到今天才真正动笔,唯一的原因就是太懒,太懒...

      大家肯定熟悉安卓各种客户端首页联动图片广告(比如淘宝),可以自动滚动,可以手动滑动,当然是循环的。但是在wp上我看到的做的最好的最早的当属爱壁纸了。

      写在wp8.1的filpview马上来临之际。上代码吧。

        [TemplatePart(Name = InnerBorderName, Type = typeof(Border))]
        [TemplatePart(Name = InnerItemsPresenterName, Type = typeof(ItemsPresenter))]
        [TemplatePart(Name = listMaskerName, Type = typeof(ListBox))]
        public class SlideView : ItemsControl, INotifyPropertyChanged
        {
            private const string InnerBorderName = "InnerBorder";
    
            private const string InnerItemsPresenterName = "InnerItemsPresenter";
    
            private const string listMaskerName = "listMasker";
    
            //视觉树根元素
            Border border = null;
    
            //滑动元素
            ItemsPresenter itemsPresenter = null;
    
            ListBox listBox = null;
    
            //是否正在滑动
            private bool isBusy = false;
    
            //滑动故事版
            Storyboard sb = null;
    
            //滑动动画
            DoubleAnimation da = null;
    
            //缓动函数
            CircleEase ease = null;
    
            // 计数器
            private DispatcherTimer timer = null;
    
            //标记索引
            private int index = 1;
    
            private int selectIndex = 0;
    
            private double borderWidth = 0;
    
    
            // MarkSource
            public static readonly DependencyProperty MarkSourceProperty =
               DependencyProperty.Register("MarkSource", typeof(IEnumerable), typeof(SlideView), new PropertyMetadata(null));
    
            /// <summary>
            /// 当前位置索引
            /// </summary>
            public int SelectIndex
            {
                get
                {
                    return selectIndex;
                }
                set
                {
                    selectIndex = value;
                    OnPropertyChanged("SelectIndex");
                }
            }
    
            /// <summary>
            /// 页码数据源
            /// </summary>
            public IEnumerable MarkSource
            {
                get
                {
                    return (IEnumerable)GetValue(MarkSourceProperty);
                }
                set
                {
                    SetValue(MarkSourceProperty, value);
                }
            }
    
            /// <summary>
            /// Border宽度
            /// </summary>
            public double BorderWidth
            {
                get
                {
                    return borderWidth;
                }
                set
                {
                    borderWidth = value;
                    OnPropertyChanged("BorderWidth");
                }
            }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            public SlideView()
            {
                this.DefaultStyleKey = typeof(SlideView);
                this.Loaded += SlideView_Loaded;
                this.Unloaded += SlideView_Unloaded;
            }
    
            protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                BorderWidth = this.Width * this.Items.Count;
                if (this.Items.Count >= 4)
                {
                    InitParams();
                    if (itemsPresenter == null) 
                    {
                        itemsPresenter = this.GetTemplateChild(InnerItemsPresenterName) as ItemsPresenter;
                    }
                    (itemsPresenter.RenderTransform as CompositeTransform).TranslateX = this.Width * (-1);
                    StartMove();
                }
                base.OnItemsChanged(e);
            }
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
                border = this.GetTemplateChild(InnerBorderName) as Border;
                if (listBox != null)
                {
                    listBox.LayoutUpdated -= listBox_LayoutUpdated;
                }
                listBox = this.GetTemplateChild(listMaskerName) as ListBox;
                if (listBox != null)
                {
                    listBox.LayoutUpdated += listBox_LayoutUpdated;
                }
                if (border != null)
                {
                    Binding bind = new Binding();
                    bind.Path = new PropertyPath("BorderWidth");
                    bind.Source = this;
                    border.SetBinding(WidthProperty, bind);
                }
                if (itemsPresenter != null)
                {
                    itemsPresenter.ManipulationStarted -= itemsPresenter_ManipulationStarted;
                    itemsPresenter.ManipulationDelta -= items_ManipulationDelta;
                    itemsPresenter.ManipulationCompleted -= items_ManipulationCompleted;
                }
                itemsPresenter = this.GetTemplateChild(InnerItemsPresenterName) as ItemsPresenter;
                if (itemsPresenter != null)
                {
                    itemsPresenter.ManipulationStarted += itemsPresenter_ManipulationStarted;
                    itemsPresenter.ManipulationDelta += items_ManipulationDelta;
                    itemsPresenter.ManipulationCompleted += items_ManipulationCompleted;
                }
            }
    
            void listBox_LayoutUpdated(object sender, EventArgs e)
            {
                if (listBox.Items.Count > 0) 
                {
                    List<Ellipse> ellipseList = FindChildOfType<Ellipse>(listBox);
                    if (ellipseList.Count > 0) 
                    {
                        foreach (var item in ellipseList) 
                        {
                            if (item.GetValue(Shape.FillProperty) != null) 
                            {
                                continue;
                            }
                            Binding bind = new Binding();
                            bind.Path = new PropertyPath("SelectIndex");
                            bind.Source = this;
                            bind.Converter = new SlideViewMarkColorConverter();
                            bind.ConverterParameter = item.Tag;
                            item.SetBinding(Shape.FillProperty, bind);
                        }
                    }
                }
            }
    
            private void SlideView_Loaded(object sender, System.Windows.RoutedEventArgs e)
            {
                if (itemsPresenter != null)
                {
                    InitParams();
                    da.Duration = TimeSpan.FromMilliseconds(500);
                    ease.EasingMode = EasingMode.EaseOut;
                    da.EasingFunction = ease;
                    Storyboard.SetTarget(da, itemsPresenter);
                    Storyboard.SetTargetProperty(da, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateX)"));
                    sb.Children.Add(da);
                    sb.Completed += sb_Completed;
                    timer.Interval = TimeSpan.FromMilliseconds(3000);
                    timer.Tick += timer_Tick;
                    StartMove();
                }
            }
    
            private void SlideView_Unloaded(object sender, RoutedEventArgs e)
            {
                StopMove();
                timer = null;
                if (sb != null)
                {
                    sb.Stop();
                    sb = null;
                }
                if (da != null)
                {
                    da = null;
                }
                if (ease != null)
                {
                    ease = null;
                }
            }
    
            /// <summary>
            /// 初始化参数
            /// </summary>
            private void InitParams()
            {
                index = 1;
                SelectIndex = 0;
                isBusy = false;
                if (sb == null) 
                {
                    sb = new Storyboard();
                }
                if (da == null) 
                {
                    da = new DoubleAnimation();
                }
                if (ease == null) 
                {
                    ease = new CircleEase();
                }
                if (timer == null) 
                {
                    timer = new DispatcherTimer();
                }
            }
    
            /// <summary>
            /// 计数器事件--自动滚动
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void timer_Tick(object sender, EventArgs e)
            {
                timer.Stop();
                MoveToNext();
            }
    
            /// <summary>
            /// 滑动开始事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void itemsPresenter_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
            {
                //如果还在滑动过程中或者items的数量小于2 则禁止滑动 
                if (isBusy || this.Items.Count < 4)
                {
                    e.Complete();
                    e.Handled = true;
                    return;
                }
            }
    
            /// <summary>
            /// 滑动过程事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void items_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
            {
                //如果还在滑动过程中 则禁止滑动
                if (isBusy || this.Items.Count < 4)
                {
                    e.Complete();
                    e.Handled = true;
                    return;
                }
                StopMove();
                ItemsPresenter b = sender as ItemsPresenter;
                (b.RenderTransform as CompositeTransform).TranslateX += e.DeltaManipulation.Translation.X;
            }
    
            /// <summary>
            /// 滑动结束事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void items_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
            {
                //如果还在滑动过程中 则禁止滑动
                if (isBusy || this.Items.Count < 4)
                {
                    e.Handled = true;
                    return;
                }
                if (e.TotalManipulation.Translation.X < 0)
                {
                    if (!e.IsInertial && Math.Abs(e.TotalManipulation.Translation.X) < this.Width / 3)
                    {
                        MoveToCurrent();
                    }
                    else
                    {
                        MoveToNext();
                    }
                }
                else if (e.TotalManipulation.Translation.X > 0)
                {
                    if (!e.IsInertial && Math.Abs(e.TotalManipulation.Translation.X) < this.Width / 3)
                    {
                        MoveToCurrent();
                    }
                    else
                    {
                        MoveToPre();
                    }
                }
            }
    
            /// <summary>
            /// 动画完成事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void sb_Completed(object sender, EventArgs e)
            {
                if (index == 0)
                {
                    index = this.Items.Count - 1 - 1;
                    (itemsPresenter.RenderTransform as CompositeTransform).TranslateX = index * (-1) * this.Width;
                }
                else if (index == this.Items.Count - 1)
                {
                    index = 1;
                    (itemsPresenter.RenderTransform as CompositeTransform).TranslateX = (-1) * this.Width;
                }
                CalcIndex();
                isBusy = false;
                StartMove();
            }
    
            /// <summary>
            /// 切换到下一页
            /// </summary>
            public void MoveToNext()
            {
                if (index + 1 > this.Items.Count)
                {
                    return;
                }
                index++;
                da.To = index * (-1) * this.Width;
                isBusy = true;
                sb.Begin();
            }
    
            /// <summary>
            /// 切换到上一页
            /// </summary>
            public void MoveToPre()
            {
                if (index - 1 < 0)
                {
                    return;
                }
                index--;
                da.To = index * (-1) * this.Width;
                isBusy = true;
                sb.Begin();
            }
    
            /// <summary>
            /// 切换到当前页
            /// </summary>
            private void MoveToCurrent()
            {
                da.To = index * (-1) * this.Width;
                isBusy = true;
                sb.Begin();
            }
    
            /// <summary>
            /// 重置标记位
            /// </summary>
            private void CalcIndex()
            {
                if (index == 0)
                {
                    SelectIndex = this.Items.Count - 2 - 1;
                }
                else if (index == this.Items.Count - 1)
                {
                    SelectIndex = 0;
                }
                else
                {
                    SelectIndex = index - 1;
                }
            }
    
            /// <summary>
            /// 开始自动翻动
            /// </summary>
            public void StartMove()
            {
                if (timer != null && !timer.IsEnabled)
                {
                    timer.Start();
                }
            }
    
            /// <summary>
            /// 停止自动翻动
            /// </summary>
            public void StopMove()
            {
                if (timer != null && timer.IsEnabled)
                {
                    timer.Stop();
                }
            }
    
            /// <summary>
            /// 针对属性更改通知的多播事件。
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
    
            /// <summary>
            /// 向侦听器通知已更改了某个属性值。
            /// </summary>
            /// <param name="propertyName">用于通知侦听器的属性的名称。此
            /// 值是可选的,可以在从支持
            /// <see cref="CallerMemberNameAttribute"/> 的编译器调用时自动提供。</param>
            protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                var eventHandler = this.PropertyChanged;
                if (eventHandler != null)
                {
                    eventHandler(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            static List<T> FindChildOfType<T>(DependencyObject root) where T : class
            {
                List<T> retList = new List<T>();
                var queue = new Queue<DependencyObject>();
                queue.Enqueue(root);
    
                while (queue.Count > 0)
                {
                    DependencyObject current = queue.Dequeue();
                    for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
                    {
                        var child = VisualTreeHelper.GetChild(current, i);
                        var typedChild = child as T;
                        if (typedChild != null)
                        {
                            retList.Add(typedChild);
                        }
                        queue.Enqueue(child);
                    }
                }
                return retList;
            }
        }
    

      如果图片多于2张 应该在最前面加上最后一张 再在最后面加上第一张 这样当到最前面或者最后面的时候 直接修改 TranslateX 达到循环的效果。

       样式:

    <Style TargetType="snControls:SlideView">
            <Setter Property="Background" Value="{x:Null}" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="TabNavigation" Value="Once" />
            <Setter Property="IsTabStop" Value="False" />
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="snControls:SlideView">
                        <Grid Background="{TemplateBinding Background}"
                              Height="{TemplateBinding Height}"
                              Width="{TemplateBinding Width}">
                            <Border Height="{TemplateBinding Height}"
                                    BorderThickness="{TemplateBinding BorderThickness}"
                                    x:Name="InnerBorder">
                                <ItemsPresenter x:Name="InnerItemsPresenter">
                                    <ItemsPresenter.RenderTransform>
                                        <CompositeTransform/>
                                    </ItemsPresenter.RenderTransform>
                                </ItemsPresenter>
                            </Border>
                            <ListBox VerticalAlignment="Bottom"
                                     HorizontalAlignment="Center"
                                     x:Name="listMasker"
                                     ItemsSource="{TemplateBinding MarkSource}">
                                <ListBox.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <VirtualizingStackPanel Orientation="Horizontal" />
                                    </ItemsPanelTemplate>
                                </ListBox.ItemsPanel>
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <Ellipse Margin="0 0 4 12"
                                                 Width="8"
                                                 Height="8"
                                                 Tag="{Binding MarkIndex}">
                                        </Ellipse>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    颜色转换器:

      

     public class SlideViewMarkColorConverter : IValueConverter
        {
            private SolidColorBrush brush = new SolidColorBrush();
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if ((int)value == (int)parameter)
                {
                    brush.Opacity = 1;
                    brush.Color = Colors.White;
                }
                else 
                {
                    brush.Opacity = 0.4;
                    brush.Color = Colors.Black;
                }
                return brush;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

      MarkSource绑定实体,其中MarkIndex修改为实体的sn,如果实体数量大于1 ItemsSource前insert最后一个 ItemsSource后add第一个。

    最后如果将控件放在枢轴里面 是无法滑动的。

    在页面后置代码loadevent里面加上

     slideview.UseOptimizedManipulationRouting = false;
                slideview.AddHandler(PivotItem.ManipulationStartedEvent, new EventHandler<ManipulationStartedEventArgs>(myPivotItem_ManipulationStarted), true);
                slideview.AddHandler(PivotItem.ManipulationDeltaEvent, new EventHandler<ManipulationDeltaEventArgs>(myPivotItem_ManipulationDelta), true);
                slideview.AddHandler(PivotItem.ManipulationCompletedEvent, new EventHandler<ManipulationCompletedEventArgs>(myPivotItem_ManipulationCompleted), true);

    myPivotItem_ManipulationStarted
    myPivotItem_ManipulationDelta
    myPivotItem_ManipulationCompleted 事件里面判断
    if (e.OriginalSource.GetType() == typeof(Image))
                {
                    e.Handled = true;
                }

    这个判断确保如果是图片 就阻止枢轴滑动 如果页面还有其他图片 也可以用坐标 等等...

    
    
  • 相关阅读:
    ssh实现免密码登录和文件传输
    linux后台执行程序相关命令
    orchestrator
    curl下载安装与使用
    goland使用
    mysql集群
    consul理解
    my.cnf
    数据库的表设计
    项目常见面试问题
  • 原文地址:https://www.cnblogs.com/dingge38/p/3884716.html
Copyright © 2011-2022 走看看