dcf06627a95bf77a3531e5c62b7e5be0ddd71938
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using Tizen.NUI.BaseComponents;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// PoppedEventArgs is a class to record <see cref="Navigator.Popped"/> event arguments which will be sent to user.
27     /// </summary>
28     /// <since_tizen> 9 </since_tizen>
29     public class PoppedEventArgs : EventArgs
30     {
31         /// <summary>
32         /// Page popped by Navigator.
33         /// </summary>
34         /// <since_tizen> 9 </since_tizen>
35         public Page Page { get; internal set; }
36     }
37
38     /// <summary>
39     /// The Navigator is a class which navigates pages with stack methods such as Push and Pop.
40     /// </summary>
41     /// <remarks>
42     /// With Transition class, Navigator supports smooth transition of View pair between two Pages
43     /// by using <see cref="PushWithTransition(Page)"/> and <see cref="PopWithTransition()"/> methods.
44     /// If current top Page and next top Page have <see cref="View"/>s those have same TransitionTag,
45     /// Navigator creates smooth transition motion for them.
46     /// Navigator.Transition property can be used to set properties of the Transition such as TimePeriod and AlphaFunction.
47     /// When all transitions are finished, Navigator calls a callback methods those connected on the "TransitionFinished" event.
48     /// </remarks>
49     /// <example>
50     /// <code>
51     /// Navigator navigator = new Navigator()
52     /// {
53     ///     TimePeriod = new TimePeriod(500),
54     ///     AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine)
55     /// };
56     ///
57     /// View view = new View()
58     /// {
59     ///     TransitionOptions = new TransitionOptions()
60     ///     {
61     ///         /* Set properties for the transition of this View */
62     ///     }
63     /// };
64     ///
65     /// ContentPage newPage = new ContentPage()
66     /// {
67     ///     Content = view,
68     /// };
69     ///
70     /// Navigator.PushWithTransition(newPage);
71     /// </code>
72     /// </example>
73     /// <since_tizen> 9 </since_tizen>
74     public class Navigator : Control
75     {
76         private const int DefaultTransitionDuration = 500;
77
78         //This will be replaced with view transition class instance.
79         private Animation curAnimation = null;
80
81         //This will be replaced with view transition class instance.
82         private Animation newAnimation = null;
83
84         private TransitionSet transitionSet = null;
85
86         private Transition transition = new Transition()
87         {
88             TimePeriod = new TimePeriod(DefaultTransitionDuration),
89             AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Default),
90         };
91
92         private bool transitionFinished = true;
93
94         //TODO: Needs to consider how to remove disposed window from dictionary.
95         //Two dictionaries are required to remove disposed navigator from dictionary.
96         private static Dictionary<Window, Navigator> windowNavigator = new Dictionary<Window, Navigator>();
97         private static Dictionary<Navigator, Window> navigatorWindow = new Dictionary<Navigator, Window>();
98
99         private List<Page> navigationPages = new List<Page>();
100
101         /// <summary>
102         /// Creates a new instance of a Navigator.
103         /// </summary>
104         /// <since_tizen> 9 </since_tizen>
105         public Navigator() : base()
106         {
107             Layout = new AbsoluteLayout();
108         }
109
110         /// <inheritdoc/>
111         [EditorBrowsable(EditorBrowsableState.Never)]
112         public override void OnInitialize()
113         {
114             base.OnInitialize();
115
116             SetAccessibilityConstructor(Role.PageTabList);
117         }
118
119         /// <summary>
120         /// An event fired when Transition has been finished.
121         /// </summary>
122         /// <since_tizen> 9 </since_tizen>
123         public event EventHandler<EventArgs> TransitionFinished;
124
125         /// <summary>
126         /// An event fired when Pop of a page has been finished.
127         /// </summary>
128         /// <remarks>
129         /// When you free resources in the Popped event handler, please make sure if the popped page is the page you find.
130         /// </remarks>
131         /// <since_tizen> 9 </since_tizen>
132         public event EventHandler<PoppedEventArgs> Popped;
133
134         /// <summary>
135         /// Returns the count of pages in Navigator.
136         /// </summary>
137         /// <since_tizen> 9 </since_tizen>
138         public int PageCount => navigationPages.Count;
139
140         /// <summary>
141         /// Transition properties for the transition of View pair having same transition tag.
142         /// </summary>
143         /// <since_tizen> 9 </since_tizen>
144         public Transition Transition
145         {
146             set
147             {
148                 transition = value;
149             }
150             get
151             {
152                 return transition;
153             }
154         }
155
156         /// <summary>
157         /// Pushes a page to Navigator.
158         /// If the page is already in Navigator, then it is not pushed.
159         /// </summary>
160         /// <param name="page">The page to push to Navigator.</param>
161         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
162         /// <since_tizen> 9 </since_tizen>
163         public void PushWithTransition(Page page)
164         {
165             if (!transitionFinished)
166             {
167                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
168                 return;
169             }
170
171             if (page == null)
172             {
173                 throw new ArgumentNullException(nameof(page), "page should not be null.");
174             }
175
176             //Duplicate page is not pushed.
177             if (navigationPages.Contains(page)) return;
178
179             var topPage = Peek();
180
181             if (!topPage)
182             {
183                 Insert(0, page);
184                 return;
185             }
186
187             navigationPages.Add(page);
188             Add(page);
189             page.Navigator = this;
190
191             //Invoke Page events
192             page.InvokeAppearing();
193             topPage.InvokeDisappearing();
194
195             transitionSet = CreateTransitions(topPage, page, true);
196             transitionSet.Finished += (object sender, EventArgs e) =>
197             {
198                 if (page is DialogPage == false)
199                 {
200                    topPage.SetVisible(false);      
201                 }
202
203                 //Invoke Page events
204                 page.InvokeAppeared();
205                 topPage.InvokeDisappeared();
206             };
207             transitionFinished = false;
208         }
209
210         /// <summary>
211         /// Pops the top page from Navigator.
212         /// </summary>
213         /// <returns>The popped page.</returns>
214         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
215         /// <since_tizen> 9 </since_tizen>
216         public Page PopWithTransition()
217         {
218             if (!transitionFinished)
219             {
220                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
221                 return null;
222             }
223
224             if (navigationPages.Count == 0)
225             {
226                 throw new InvalidOperationException("There is no page in Navigator.");
227             }
228
229             var topPage = Peek();
230
231             if (navigationPages.Count == 1)
232             {
233                 Remove(topPage);
234
235                 //Invoke Popped event
236                 Popped?.Invoke(this, new PoppedEventArgs() { Page = topPage });
237
238                 return topPage;
239             }
240             var newTopPage = navigationPages[navigationPages.Count - 2];
241
242             //Invoke Page events
243             newTopPage.InvokeAppearing();
244             topPage.InvokeDisappearing();
245
246             transitionSet = CreateTransitions(topPage, newTopPage, false);
247             transitionSet.Finished += (object sender, EventArgs e) =>
248             {
249                 Remove(topPage);
250                 topPage.SetVisible(true);
251
252                 //Invoke Page events
253                 newTopPage.InvokeAppeared();
254                 topPage.InvokeDisappeared();
255
256                 //Invoke Popped event
257                 Popped?.Invoke(this, new PoppedEventArgs() { Page = topPage });
258             };
259             transitionFinished = false;
260
261             return topPage;
262         }
263
264         /// <summary>
265         /// Pushes a page to Navigator.
266         /// If the page is already in Navigator, then it is not pushed.
267         /// </summary>
268         /// <param name="page">The page to push to Navigator.</param>
269         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
270         /// <since_tizen> 9 </since_tizen>
271         public void Push(Page page)
272         {
273             if (!transitionFinished)
274             {
275                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
276                 return;
277             }
278
279             if (page == null)
280             {
281                 throw new ArgumentNullException(nameof(page), "page should not be null.");
282             }
283
284             //Duplicate page is not pushed.
285             if (navigationPages.Contains(page)) return;
286
287             var curTop = Peek();
288
289             if (!curTop)
290             {
291                 Insert(0, page);
292                 return;
293             }
294
295             navigationPages.Add(page);
296             Add(page);
297             page.Navigator = this;
298
299             //Invoke Page events
300             page.InvokeAppearing();
301             curTop.InvokeDisappearing();
302
303             //TODO: The following transition codes will be replaced with view transition.
304             InitializeAnimation();
305
306             if (page is DialogPage == false)
307             {
308                 curAnimation = new Animation(1000);
309                 curAnimation.AnimateTo(curTop, "Opacity", 1.0f, 0, 1000);
310                 curAnimation.EndAction = Animation.EndActions.StopFinal;
311                 curAnimation.Finished += (object sender, EventArgs args) =>
312                 {
313                     curTop.SetVisible(false);
314
315                     //Invoke Page events
316                     curTop.InvokeDisappeared();
317                 };
318                 curAnimation.Play();
319
320                 page.Opacity = 0.0f;
321                 page.SetVisible(true);
322                 newAnimation = new Animation(1000);
323                 newAnimation.AnimateTo(page, "Opacity", 1.0f, 0, 1000);
324                 newAnimation.EndAction = Animation.EndActions.StopFinal;
325                 newAnimation.Finished += (object sender, EventArgs e) =>
326                 {
327                     //Invoke Page events
328                     page.InvokeAppeared();
329                 };
330                 newAnimation.Play();
331             }
332         }
333
334         /// <summary>
335         /// Pops the top page from Navigator.
336         /// </summary>
337         /// <returns>The popped page.</returns>
338         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
339         /// <since_tizen> 9 </since_tizen>
340         public Page Pop()
341         {
342             if (!transitionFinished)
343             {
344                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
345                 return null;
346             }
347
348             if (navigationPages.Count == 0)
349             {
350                 throw new InvalidOperationException("There is no page in Navigator.");
351             }
352
353             var curTop = Peek();
354
355             if (navigationPages.Count == 1)
356             {
357                 Remove(curTop);
358
359                 //Invoke Popped event
360                 Popped?.Invoke(this, new PoppedEventArgs() { Page = curTop });
361
362                 return curTop;
363             }
364
365             var newTop = navigationPages[navigationPages.Count - 2];
366
367             //Invoke Page events
368             newTop.InvokeAppearing();
369             curTop.InvokeDisappearing();
370
371             //TODO: The following transition codes will be replaced with view transition.
372             InitializeAnimation();
373
374             if (curTop is DialogPage == false)
375             {
376                 curAnimation = new Animation(1000);
377                 curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
378                 curAnimation.EndAction = Animation.EndActions.StopFinal;
379                 curAnimation.Finished += (object sender, EventArgs e) =>
380                 {
381                     //Removes the current top page after transition is finished.
382                     Remove(curTop);
383                     curTop.Opacity = 1.0f;
384
385                     //Invoke Page events
386                     curTop.InvokeDisappeared();
387
388                     //Invoke Popped event
389                     Popped?.Invoke(this, new PoppedEventArgs() { Page = curTop });
390                 };
391                 curAnimation.Play();
392
393                 newTop.Opacity = 1.0f;
394                 newTop.SetVisible(true);
395                 newAnimation = new Animation(1000);
396                 newAnimation.AnimateTo(newTop, "Opacity", 1.0f, 0, 1000);
397                 newAnimation.EndAction = Animation.EndActions.StopFinal;
398                 newAnimation.Finished += (object sender, EventArgs e) =>
399                 {
400                     //Invoke Page events
401                     newTop.InvokeAppeared();
402                 };
403                 newAnimation.Play();
404             }
405             else
406             {
407                 Remove(curTop);
408             }
409
410             return curTop;
411         }
412
413         /// <summary>
414         /// Returns the page of the given index in Navigator.
415         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
416         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
417         /// </summary>
418         /// <param name="index">The index of a page in Navigator.</param>
419         /// <returns>The page of the given index in Navigator.</returns>
420         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
421         public Page GetPage(int index)
422         {
423             if ((index < 0) || (index > navigationPages.Count))
424             {
425                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
426             }
427
428             return navigationPages[index];
429         }
430
431         /// <summary>
432         /// Returns the current index of the given page in Navigator.
433         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
434         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
435         /// </summary>
436         /// <param name="page">The page in Navigator.</param>
437         /// <returns>The index of the given page in Navigator. If the given page is not in the Navigator, then -1 is returned.</returns>
438         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
439         /// <since_tizen> 9 </since_tizen>
440         public int IndexOf(Page page)
441         {
442             if (page == null)
443             {
444                 throw new ArgumentNullException(nameof(page), "page should not be null.");
445             }
446
447             for (int i = 0; i < navigationPages.Count; i++)
448             {
449                 if (navigationPages[i] == page)
450                 {
451                     return i;
452                 }
453             }
454
455             return -1;
456         }
457
458         /// <summary>
459         /// Inserts a page at the specified index of Navigator.
460         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
461         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
462         /// To find the current index of a page in Navigator, please use IndexOf(page).
463         /// If the page is already in Navigator, then it is not inserted.
464         /// </summary>
465         /// <param name="index">The index of a page in Navigator where the page will be inserted.</param>
466         /// <param name="page">The page to insert to Navigator.</param>
467         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
468         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
469         /// <since_tizen> 9 </since_tizen>
470         public void Insert(int index, Page page)
471         {
472             if ((index < 0) || (index > navigationPages.Count))
473             {
474                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
475             }
476
477             if (page == null)
478             {
479                 throw new ArgumentNullException(nameof(page), "page should not be null.");
480             }
481
482             //Duplicate page is not pushed.
483             if (navigationPages.Contains(page)) return;
484
485             //TODO: The following transition codes will be replaced with view transition.
486             InitializeAnimation();
487
488             if (index == PageCount)
489             {
490                 page.Opacity = 1.0f;
491                 page.SetVisible(true);
492             }
493             else
494             {
495                 page.SetVisible(false);
496                 page.Opacity = 0.0f;
497             }
498
499             navigationPages.Insert(index, page);
500             Add(page);
501             page.Navigator = this;
502         }
503
504         /// <summary>
505         /// Inserts a page to Navigator before an existing page.
506         /// If the page is already in Navigator, then it is not inserted.
507         /// </summary>
508         /// <param name="before">The existing page, before which a page will be inserted.</param>
509         /// <param name="page">The page to insert to Navigator.</param>
510         /// <exception cref="ArgumentNullException">Thrown when the argument before is null.</exception>
511         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
512         /// <exception cref="ArgumentException">Thrown when the argument before does not exist in Navigator.</exception>
513         /// <since_tizen> 9 </since_tizen>
514         public void InsertBefore(Page before, Page page)
515         {
516             if (before == null)
517             {
518                 throw new ArgumentNullException(nameof(before), "before should not be null.");
519             }
520
521             if (page == null)
522             {
523                 throw new ArgumentNullException(nameof(page), "page should not be null.");
524             }
525
526             //Find the index of before page.
527             int beforeIndex = navigationPages.FindIndex(x => x == before);
528
529             //before does not exist in Navigator.
530             if (beforeIndex == -1)
531             {
532                 throw new ArgumentException("before does not exist in Navigator.", nameof(before));
533             }
534
535             Insert(beforeIndex, page);
536         }
537
538         /// <summary>
539         /// Removes a page from Navigator.
540         /// </summary>
541         /// <param name="page">The page to remove from Navigator.</param>
542         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
543         /// <since_tizen> 9 </since_tizen>
544         public void Remove(Page page)
545         {
546             if (page == null)
547             {
548                 throw new ArgumentNullException(nameof(page), "page should not be null.");
549             }
550
551             //TODO: The following transition codes will be replaced with view transition.
552             InitializeAnimation();
553
554             if ((page == Peek()) && (PageCount >= 2))
555             {
556                 navigationPages[PageCount - 2].Opacity = 1.0f;
557                 navigationPages[PageCount - 2].SetVisible(true);
558             }
559
560             page.Navigator = null;
561             navigationPages.Remove(page);
562             base.Remove(page);
563         }
564
565         /// <summary>
566         /// Removes a page at the specified index of Navigator.
567         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
568         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
569         /// To find the current index of a page in Navigator, please use IndexOf(page).
570         /// </summary>
571         /// <param name="index">The index of a page in Navigator where the page will be removed.</param>
572         /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is less than 0, or greater than or equal to the number of pages.</exception>
573         /// <since_tizen> 9 </since_tizen>
574         public void RemoveAt(int index)
575         {
576             if ((index < 0) || (index >= navigationPages.Count))
577             {
578                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than the number of pages.");
579             }
580
581             Remove(navigationPages[index]);
582         }
583
584         /// <summary>
585         /// Returns the page at the top of Navigator.
586         /// </summary>
587         /// <returns>The page at the top of Navigator.</returns>
588         /// <since_tizen> 9 </since_tizen>
589         public Page Peek()
590         {
591             if (navigationPages.Count == 0) return null;
592
593             return navigationPages[navigationPages.Count - 1];
594         }
595
596         /// <summary>
597         /// Disposes Navigator and all children on it.
598         /// </summary>
599         /// <param name="type">Dispose type.</param>
600         [EditorBrowsable(EditorBrowsableState.Never)]
601         protected override void Dispose(DisposeTypes type)
602         {
603             if (disposed)
604             {
605                 return;
606             }
607
608             if (type == DisposeTypes.Explicit)
609             {
610                 foreach (Page page in navigationPages)
611                 {
612                     Utility.Dispose(page);
613                 }
614                 navigationPages.Clear();
615
616                 Window window;
617
618                 if (navigatorWindow.TryGetValue(this, out window) == true)
619                 {
620                     navigatorWindow.Remove(this);
621                     windowNavigator.Remove(window);
622                 }
623             }
624
625             base.Dispose(type);
626         }
627
628         /// <summary>
629         /// Returns the default navigator of the given window.
630         /// </summary>
631         /// <returns>The default navigator of the given window.</returns>
632         /// <exception cref="ArgumentNullException">Thrown when the argument window is null.</exception>
633         /// <since_tizen> 9 </since_tizen>
634         public static Navigator GetDefaultNavigator(Window window)
635         {
636             if (window == null)
637             {
638                 throw new ArgumentNullException(nameof(window), "window should not be null.");
639             }
640
641             if (windowNavigator.ContainsKey(window) == true)
642             {
643                 return windowNavigator[window];
644             }
645
646             var defaultNavigator = new Navigator();
647             defaultNavigator.WidthResizePolicy = ResizePolicyType.FillToParent;
648             defaultNavigator.HeightResizePolicy = ResizePolicyType.FillToParent;
649             window.Add(defaultNavigator);
650             windowNavigator.Add(window, defaultNavigator);
651             navigatorWindow.Add(defaultNavigator, window);
652
653             return defaultNavigator;
654         }
655
656         /// <summary>
657         /// Create Transitions between currentTopPage and newTopPage
658         /// </summary>
659         /// <param name="currentTopPage">The top page of Navigator.</param>
660         /// <param name="newTopPage">The new top page after transition.</param>
661         /// <param name="pushTransition">True if this transition is for push new page</param>
662         private TransitionSet CreateTransitions(Page currentTopPage, Page newTopPage, bool pushTransition)
663         {
664             currentTopPage.SetVisible(true);
665             newTopPage.SetVisible(true);
666
667             List<View> taggedViewsInNewTopPage = new List<View>();
668             RetrieveTaggedViews(taggedViewsInNewTopPage, newTopPage, true);
669             List<View> taggedViewsInCurrentTopPage = new List<View>();
670             RetrieveTaggedViews(taggedViewsInCurrentTopPage, currentTopPage, true);
671
672             List<KeyValuePair<View, View>> sameTaggedViewPair = new List<KeyValuePair<View, View>>();
673             foreach(View currentTopPageView in taggedViewsInCurrentTopPage)
674             {
675                 bool findPair = false;
676                 foreach(View newTopPageView in taggedViewsInNewTopPage)
677                 {
678                     if((currentTopPageView.TransitionOptions != null) && (newTopPageView.TransitionOptions != null) &&
679                         currentTopPageView.TransitionOptions?.TransitionTag == newTopPageView.TransitionOptions?.TransitionTag)
680                     {
681                         sameTaggedViewPair.Add(new KeyValuePair<View, View>(currentTopPageView, newTopPageView));
682                         findPair = true;
683                         break;
684                     }
685                 }
686                 if(findPair)
687                 {
688                     taggedViewsInNewTopPage.Remove(sameTaggedViewPair[sameTaggedViewPair.Count - 1].Value);
689                 }
690             }
691             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
692             {
693                 taggedViewsInCurrentTopPage.Remove(pair.Key);
694             }
695
696             TransitionSet newTransitionSet = new TransitionSet();
697             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
698             {
699                 TransitionItem pairTransition = transition.CreateTransition(pair.Key, pair.Value, pushTransition);
700                 if(pair.Value.TransitionOptions?.TransitionWithChild ?? false)
701                 {
702                     pairTransition.TransitionWithChild = true;
703                 }
704                 newTransitionSet.AddTransition(pairTransition);
705             }
706
707             newTransitionSet.Finished += (object sender, EventArgs e) =>
708             {
709                 if(newTopPage.Layout != null)
710                 {
711                     newTopPage.Layout.RequestLayout();
712                 }
713                 if(currentTopPage.Layout != null)
714                 {
715                     currentTopPage.Layout.RequestLayout();
716                 }
717                 transitionFinished = true;
718                 InvokeTransitionFinished();
719                 transitionSet.Dispose();
720                 currentTopPage.Opacity = 1.0f;
721             };
722
723             if (!pushTransition || newTopPage is DialogPage == false)
724             {
725                 View transitionView = (currentTopPage is ContentPage) ? (currentTopPage as ContentPage).Content : (currentTopPage as DialogPage).Content;
726                 if (currentTopPage.DisappearingTransition != null && transitionView != null)
727                 {
728                     TransitionItemBase disappearingTransition = currentTopPage.DisappearingTransition.CreateTransition(transitionView, false);
729                     disappearingTransition.TransitionWithChild = true;
730                     newTransitionSet.AddTransition(disappearingTransition);
731                 }
732                 else
733                 {
734                     currentTopPage.SetVisible(false);
735                 }
736             }
737             if (pushTransition || currentTopPage is DialogPage == false)
738             {
739                 View transitionView = (newTopPage is ContentPage) ? (newTopPage as ContentPage).Content : (newTopPage as DialogPage).Content;
740                 if (newTopPage.AppearingTransition != null && transitionView != null)
741                 {
742                     TransitionItemBase appearingTransition = newTopPage.AppearingTransition.CreateTransition(transitionView, true);
743                     appearingTransition.TransitionWithChild = true;
744                     newTransitionSet.AddTransition(appearingTransition);
745                 }
746             }
747
748             newTransitionSet.Play();
749
750             return newTransitionSet;
751         }
752
753         /// <summary>
754         /// Retrieve Tagged Views in the view tree.
755         /// </summary>
756         /// <param name="taggedViews">Returned tagged view list..</param>
757         /// <param name="view">Root View to get tagged child View.</param>
758         /// <param name="isPage">Flag to check current View is page or not</param>
759         private void RetrieveTaggedViews(List<View> taggedViews, View view, bool isPage)
760         {
761             if (!isPage)
762             {
763                 if (!string.IsNullOrEmpty(view.TransitionOptions?.TransitionTag))
764                 {
765                     taggedViews.Add((view as View));
766                 }
767
768                 if (view.ChildCount == 0)
769                 {
770                     return;
771                 }
772
773                 if (view.TransitionOptions?.TransitionWithChild ?? false)
774                 {
775                     return;
776                 }
777             }
778             foreach (View child in view.Children)
779             {
780                 RetrieveTaggedViews(taggedViews, child, false);
781             }
782         }
783
784         internal void InvokeTransitionFinished()
785         {
786             TransitionFinished?.Invoke(this, new EventArgs());
787         }
788
789         //TODO: The following transition codes will be replaced with view transition.
790         private void InitializeAnimation()
791         {
792             if (curAnimation != null)
793             {
794                 curAnimation.Stop();
795                 curAnimation.Clear();
796                 curAnimation = null;
797             }
798
799             if (newAnimation != null)
800             {
801                 newAnimation.Stop();
802                 newAnimation.Clear();
803                 newAnimation = null;
804             }
805         }
806     }
807 }