WindowsPhone下拉刷新控件 - PullRefreshListBox(二)


 

++++++++++++++++++++++++++++++++++++++++++

本文系本站原創,歡迎轉載! 轉載請注明出處:

http://blog.csdn.net/mr_raptor/article/details/7358226

++++++++++++++++++++++++++++++++++++++++++

前言

  最近一些時間有一些雜事,沒有及時更新Blog,Sorry,現在將下拉刷新更新完。

 上一節講了,下拉刷新的基本框架結構,現在我們在上節的基礎上添加內容。

WindowsPhone下拉刷新控件 - PullRefreshListBox(一)       

在第一節中,解決了:Control選擇問題和樣式模板,本節主要內容包含:

  • 用戶操作及距離計算問題
  • 刷新事件處理問題
  • 動畫效果

思路:

獲得點擊Y坐標startY,在手指移動時將新的移動坐標currentY與startY對比,如果currentY - startY的值大於了一定的坐標值就設置刷新顯示區,同時設置控件的依賴項屬性,同時還開始動畫效果。

1.  用戶操作及距離計算問題

用戶操作主要是重寫了基類里的三個方法:OnManipulationCompleted,OnManipulationStarted,OnMouseMove。

  • OnManipulationCompleted:用於用戶的手勢行為結束時調用。
  • OnManipulationStarted:用於用戶的手勢行為開始時調用。
  • OnMouseMove:用於用戶的手勢行為持續變化時調用 。

通過OnManipulationStarted(ManipulationStartedEventArgs e)參數ManipulationStartedEventArgs 可以獲得Y坐標點

[csharp]  view plain copy
  1.        protected override void OnManipulationStarted(ManipulationStartedEventArgs e)  
  2.        {  
  3.            base.OnManipulationStarted(e);  
  4.            startY = e.ManipulationOrigin.Y;  
  5. ...  

 

通過OnMouseMove(MouseEventArgs e)參數MouseEventArgs 可以獲得當前相對參照控件的坐標點Y

[csharp]  view plain copy
  1.        protected override void OnMouseMove(MouseEventArgs e)  
  2.        {  
  3.            base.OnMouseMove(e);  
  4.            double currentY = e.GetPosition(this.ScrollViewer).Y;  
  5. ...  

在OnManipulationCompleted方法里將下拉顯示關閉掉,同時關閉動畫效果,修改依賴項屬性 PullDownPanel.Visibility = Visibility.Collapsed;

具體代碼如下:

[csharp]  view plain copy
  1. private double startY, endY;  
  2. private double scrolledOffset;  
  3. private bool isShowing = false;  
  4.   
  5. protected override void OnManipulationStarted(ManipulationStartedEventArgs e)  
  6.        {  
  7.            base.OnManipulationStarted(e);  
  8.            startY = e.ManipulationOrigin.Y;  
  9.            scrolledOffset = this.ScrollViewer.VerticalOffset;  
  10.            //Debug.WriteLine("OnManipulationStarted startY = " + startY + " scrolledY = " + scrolledOffset);  
  11.        }  
  12.   
  13.        protected override void OnMouseMove(MouseEventArgs e)  
  14.        {  
  15.            base.OnMouseMove(e);  
  16.            double currentY = e.GetPosition(this.ScrollViewer).Y;  
  17.            double offset = currentY - startY;  
  18.            if (scrolledOffset - offset < -30.0)  
  19.            {  
  20.                setVisible();  
  21.            }  
  22.            else  
  23.            {  
  24.                setInvisible();  
  25.            }  
  26.        }  
  27.   
  28.        private void setInvisible()  
  29.        {  
  30.            if (!isShowing)  
  31.                return;  
  32.            isShowing = false;  
  33.            //Debug.WriteLine("stop show");  
  34.            ShowAnimation.Stop();  
  35.            TransformAnimation.Stop();  
  36.            PullDownPanel.Visibility = Visibility.Collapsed;  
  37.        }  
  38.   
  39.        private void setVisible()  
  40.        {  
  41.            if (isShowing)  
  42.                return;  
  43.            isShowing = true;  
  44.            Debug.WriteLine("show");  
  45.            PullDownPanel.Visibility = Visibility.Visible;  
  46.            ShowAnimation.Begin();  
  47.            TransformAnimation.Begin();  
  48.   
  49.            DataRefreshedEventHandler handler = DataRefreshed;  
  50.            if (handler != null)  
  51.            {  
  52.                handler(thisnull);  
  53.            }  
  54.        }  
[csharp]  view plain copy
  1. <p>        protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)  
  2.         {  
  3.             base.OnManipulationCompleted(e);  
  4.             endY = e.ManipulationOrigin.Y;  
  5.             //Debug.WriteLine("OnManipulationCompleted endY" + endY);</p><p>            setInvisible();  
  6.         }</p>  


這個時候編譯一個工程會發現,我們的下拉能夠被正常識別到,當Y方向拉動超過30像素,就會有顯示下拉顯示區內容。

但是,這時還沒有動畫效果,我們為它添加上動畫效果,其中下拉顯示區有淡進淡出的效果,然后,有一個轉動的就箭頭,表示正在刷新。

 

2.  添加動畫效果

動畫效果是發生在下拉時,所以我們要回去Generic.xaml樣式模板里,在Grid.Resources中添加如下代碼:

[html]  view plain copy
  1. <Setter Property="Template">  
  2.         <Setter.Value>  
  3.                 <ControlTemplate TargetType="local:PullRefreshListBox">  
  4.                     <Grid>  
  5.                         <Grid.Resources>  
  6.                             <Storyboard x:Name="showAnimation">  
  7.                                 <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PullDownPanel">  
  8.                                     <EasingDoubleKeyFrame KeyTime="0" Value="0"/>  
  9.                                     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"/>  
  10.                                 </DoubleAnimationUsingKeyFrames>  
  11.                             </Storyboard>  
  12.                             <Storyboard x:Name="transformAnimation" RepeatBehavior="10x">  
  13.                                 <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)"   
  14.                                            Storyboard.TargetName="RefreshImage" RepeatBehavior="Forever">  
  15.                                     <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="90"/>  
  16.                                     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="180"/>  
  17.                                     <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="270"/>  
  18.                                     <EasingDoubleKeyFrame KeyTime="0:0:1.6" Value="360"/>  
  19.                                 </DoubleAnimationUsingKeyFrames>  
  20.                             </Storyboard>  
  21.                         </Grid.Resources>  


其中,showAnimation動畫為在0.8秒內其透明度由0到1從全透明到不透明,從而實現淡進淡出的效果,transformAnimation動畫為小轉輪在0.4秒里順時針重復轉動90度,實現轉動效果。

由於我們要在下拉條件成立時,開啟動畫,因此要在OnApplyTemplate方法中得到兩個動畫的引用:

[csharp]  view plain copy
  1. public override void OnApplyTemplate()  
  2. {  
  3.    // the Animation of the Image and RefreshText  
  4.     TransformAnimation = this.GetTemplateChild(TransformAnimationName) as Storyboard;  
  5.     ShowAnimation = this.GetTemplateChild(ShowAnimationName) as Storyboard;  

這樣,在setInvisible和setVisible方法里分別開啟和關閉動畫效果就可以了。

編譯當前代碼,再執行,會發現,下拉時,動畫效果已經實現,但是下拉列表基本的點擊事件不能使用了。

這是因為我們的下拉控件繼承自ItemsControl控件,對於ItemsControl控件里的列表內容,要自己添加其列表項的點擊行為。

 

3.  添加Item點擊事件

當用戶在列表中選擇一個item時,我們希望將所有的Item都放到一個棧里,然后從Tap事件里找到被Tap的對象,然后從棧里遍歷該對象,如果找到,就將SelectedItem與SelectedIndex設置為其對應的值,在其屬性改變事件里響應點擊行為。

在OnApplyTemplate方法里注冊Tap 事件:

[csharp]  view plain copy
  1.    public override void OnApplyTemplate()  
  2.    {  
  3. // add the Event handler for the Tap action on ScrollViewer  
  4.        this.ScrollViewer.Tap += new EventHandler<GestureEventArgs>(ScrollViewer_Tap);  

Tap事件處理:

[csharp]  view plain copy
  1. void ScrollViewer_Tap(object sender, GestureEventArgs e)  
  2. {  
  3.     DependencyObject dpendObj = e.OriginalSource as DependencyObject;  
  4.     object obj;  
  5.   
  6.     // get StackPanel of the listbox  
  7.     StackPanel itemsStack = VisualTreeHelper.GetChild(_ItemsContainer, 0) as StackPanel;  
  8.     if ((obj = RetriveElementOfTree<ItemsPresenter>(dpendObj)) != null)  
  9.     {  
  10.         //ItemsPresenter itemsGroup = obj as ItemsPresenter;  
  11.   
  12.         if (childObjStack != null)  
  13.         {  
  14.             // pop StackPanel  
  15.             childObjStack.Pop();  
  16.             // the event Element  
  17.             obj = childObjStack.Pop();  
  18.         }  
  19.   
  20.         for(int i = 0; i < itemsStack.Children.Count; i++)  
  21.         {  
  22.             if (object.Equals(obj, itemsStack.Children[i]))  
  23.             {  
  24.                 // found the Taped obj  
  25.                 saveSelectedItem = itemsStack.Children[i];  
  26.                 SelectedIndex = i;  
  27.                 SelectedItem = saveSelectedItem;  
  28.                 OnSelectedItem(SelectedItem);  
  29.                 break;  
  30.             }  
  31.         }  
  32.         Debug.WriteLine("ScrollViewer_Tap::"+VisualTreeHelper.GetChildrenCount(itemsStack));  
  33.     }  
  34. }  

VisualTreeHelper.GetChild是個很牛B的東西,它可以從指定的控件里獲得對應的子控件引用。
VisualTreeHelper.GetChildVisualTreeHelper.GetChild這里我們從裝有所有Items的控件父控件_ItemsContainer里得到依次得到每一個子控件放到childObjStack棧里,如下圖所示。

具體的入棧如下代碼所示:

[csharp]  view plain copy
  1. private Stack<DependencyObject> childObjStack;  
  2. private object RetriveElementOfTree<T>(DependencyObject tree)  
  3. {  
  4.     if (childObjStack == null)  
  5.         childObjStack = new Stack<DependencyObject>();  
  6.     else  
  7.         childObjStack.Clear();  
  8.   
  9.     while (tree != null)  
  10.     {  
  11.         if (tree is T)  
  12.         {  
  13.             return tree;  
  14.         }  
  15.         childObjStack.Push(tree);  
  16.         tree = VisualTreeHelper.GetParent(tree);  
  17.     }  
  18.     return null;  
  19. }  

在獲得了被點擊的Item之后,主動回調SelectionChangedEvent事件,響應用戶點擊Item操作。

[csharp]  view plain copy
  1. private void OnSelectedItem(object obj)  
  2. {  
  3.     SelectionChangedEventHandler handler = SelectionChanged;  
  4.     if (handler != null)  
  5.     {  
  6.         _selectionList[0] = obj;  
  7.         // Call back user define Event  
  8.         handler(thisnew SelectionChangedEventArgs(EmptyList, _selectionList));  
  9.     }  
  10. }  

現在來看我們的控件看似沒有問題了,但是不要忘記了本控件的最初目的,即,用戶下拉列表時,要去刷新其數據源,所以在用戶下拉條件成立時,調用用戶的回調方法。


 3.  添加下拉刷新處理事件


 首先添加一個代理和事件

[csharp]  view plain copy
  1. // user pull down the list delegate event  
  2. public delegate void DataRefreshedEventHandler(object sender, RoutedEventArgs e);  
  3. // pull down refresh the ItemSource Event  
  4. public event DataRefreshedEventHandler DataRefreshed;  

然后在setVisible()里回調用戶注冊的事件方法:

[csharp]  view plain copy
  1. private void setVisible()  
  2. {  
  3.     ...  
  4.     DataRefreshedEventHandler handler = DataRefreshed;  
  5.     if (handler != null)  
  6.     {  
  7.         handler(thisnull);  
  8.     }  
  9. }  


至此,自定義下拉控件完篇,有問題請跟評論,作者第一時間看到回復。

++++++++++++++++++++++++++++++++++++++++++

本文系本站原創,歡迎轉載! 轉載請注明出處:

http://blog.csdn.net/mr_raptor/article/details/7358226

++++++++++++++++++++++++++++++++++++++++++


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM