WP8 FlipView_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > WP8 FlipView

WP8 FlipView

 2014/8/1 15:18:35  戴眼镜的杀手  程序员俱乐部  我要评论(0)
  • 摘要:一直想写点东西,直到今天才真正动笔,唯一的原因就是太懒,太懒...大家肯定熟悉安卓各种客户端首页联动图片广告(比如淘宝),可以自动滚动,可以手动滑动,当然是循环的。但是在wp上我看到的做的最好的最早的当属爱壁纸了。写在wp8.1的filpview马上来临之际。上代码吧。[TemplatePart(Name=InnerBorderName,Type=typeof(Border))][TemplatePart(Name=InnerItemsPresenterName,Type=typeof
  • 标签:view

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

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

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

class="brush:csharp;collapse:true;;gutter:true;">    [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;
        }
    }

  如果有4张图片 应该在最前面加上最后一张 再在最后面加上第一张 这样当到最前面或者最后面的时候 直接修改 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;
            }

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

 


                    
                
上一篇: Android -- 程序判断手机ROOT状态,获取ROOT权限 下一篇: 没有下一篇了!
发表评论
用户名: 匿名