-
Notifications
You must be signed in to change notification settings - Fork 468
Add Support for Multiple ItemViews in MediaElement #2807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4d9cd35
61ea60e
e3293f4
9dead1c
f67c3e6
9c47153
e76acda
0313e75
500c53b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| using System; | ||
| using Foundation; | ||
| using Microsoft.Maui; | ||
| using ObjCRuntime; | ||
| using UIKit; | ||
|
|
||
| namespace CommunityToolkit.Maui.Sample.Platforms.MacCatalyst; | ||
|
|
||
| [Register("SceneDelegate")] | ||
| public class SceneDelegate : MauiUISceneDelegate | ||
| { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| using System; | ||
| using Foundation; | ||
| using Microsoft.Maui; | ||
| using ObjCRuntime; | ||
| using UIKit; | ||
|
|
||
| namespace CommunityToolkit.Maui.Sample.Platforms.iOS; | ||
|
|
||
| [Register("SceneDelegate")] | ||
| public class SceneDelegate : MauiUISceneDelegate | ||
| { | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,4 @@ | ||||||||||||||||||||||
| using System.Diagnostics.CodeAnalysis; | ||||||||||||||||||||||
| using System.Reflection; | ||||||||||||||||||||||
| using AVKit; | ||||||||||||||||||||||
| using CommunityToolkit.Maui.Extensions; | ||||||||||||||||||||||
| using CommunityToolkit.Maui.Views; | ||||||||||||||||||||||
|
|
@@ -28,7 +27,7 @@ public MauiMediaElement(AVPlayerViewController playerViewController, MediaElemen | |||||||||||||||||||||
| #if IOS16_0_OR_GREATER || MACCATALYST16_1_OR_GREATER | ||||||||||||||||||||||
| // On iOS 16+ and macOS 13+ the AVPlayerViewController has to be added to a parent ViewController, otherwise the transport controls won't be displayed. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| UIViewController? viewController; | ||||||||||||||||||||||
| UIViewController? viewController = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // If any of the Parents in the VisualTree of MediaElement uses a UIViewController for their PlatformView, use it as the child ViewController | ||||||||||||||||||||||
| // This enables support for UI controls like CommunityToolkit.Maui.Popup whose PlatformView is a UIViewController (e.g. `public class MauiPopup : UIViewController`) | ||||||||||||||||||||||
|
|
@@ -58,48 +57,17 @@ public MauiMediaElement(AVPlayerViewController playerViewController, MediaElemen | |||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // look for an ItemsView (e.g. CarouselView or CollectionView) on page | ||||||||||||||||||||||
| if (TryGetItemsViewOnPage(currentPage, out var itemsView)) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| var parentViewController = itemsView.Handler switch | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| CarouselViewHandler carouselViewHandler => carouselViewHandler.ViewController ?? GetInternalControllerForItemsView(carouselViewHandler), | ||||||||||||||||||||||
| CarouselViewHandler2 carouselViewHandler2 => carouselViewHandler2.ViewController ?? GetInternalControllerForItemsView2(carouselViewHandler2), | ||||||||||||||||||||||
| CollectionViewHandler collectionViewHandler => collectionViewHandler.ViewController ?? GetInternalControllerForItemsView(collectionViewHandler), | ||||||||||||||||||||||
| CollectionViewHandler2 collectionViewHandler2 => collectionViewHandler2.ViewController ?? GetInternalControllerForItemsView2(collectionViewHandler2), | ||||||||||||||||||||||
| null => throw new InvalidOperationException("Handler cannot be null"), | ||||||||||||||||||||||
| _ => throw new NotSupportedException($"{itemsView.Handler.GetType()} not yet supported") | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| viewController = parentViewController; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // The Controller we need is a `protected internal` property called ItemsViewController in the ItemsViewHandler class: https://github.com/dotnet/maui/blob/cf002538cb73db4bf187a51e4786d7478a7025ee/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs#L39 | ||||||||||||||||||||||
| // In this method, we must use reflection to get the value of its backing field | ||||||||||||||||||||||
| static ItemsViewController<TItemsView> GetInternalControllerForItemsView<TItemsView>(ItemsViewHandler<TItemsView> handler) where TItemsView : ItemsView | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| var nonPublicInstanceFields = typeof(ItemsViewHandler<TItemsView>).GetFields(BindingFlags.NonPublic | BindingFlags.Instance); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| var controllerProperty = nonPublicInstanceFields.Single(x => x.FieldType == typeof(ItemsViewController<TItemsView>)); | ||||||||||||||||||||||
| return (ItemsViewController<TItemsView>)(controllerProperty.GetValue(handler) ?? throw new InvalidOperationException($"Unable to get the value for the Controller property on {handler.GetType()}")); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // The Controller we need is a `protected internal` property called ItemsViewController in the ItemsViewHandler2 class: https://github.com/dotnet/maui/blob/70e8ddfd4bd494bc71aa7afb812cc09161cf0c72/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs#L64 | ||||||||||||||||||||||
| // In this method, we must use reflection to get the value of its backing field | ||||||||||||||||||||||
| static ItemsViewController<TItemsView> GetInternalControllerForItemsView2<TItemsView>(ItemsViewHandler2<TItemsView> handler) where TItemsView : ItemsView | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| var nonPublicInstanceFields = typeof(ItemsViewHandler2<TItemsView>).GetFields(BindingFlags.NonPublic | BindingFlags.Instance); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| var controllerProperty = nonPublicInstanceFields.Single(x => x.FieldType == typeof(ItemsViewController2<TItemsView>)); | ||||||||||||||||||||||
| return (ItemsViewController<TItemsView>)(controllerProperty.GetValue(handler) ?? throw new InvalidOperationException($"Unable to get the value for the Controller property on {handler.GetType()}")); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| // If we don't find an ItemsView, default to the current UIViewController | ||||||||||||||||||||||
| else | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| viewController = Platform.GetCurrentUIViewController(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| TryGetItemsViewOnPage(currentPage, out var itemsView); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Set the viewController to the first root view controller. | ||||||||||||||||||||||
| viewController = Platform.GetCurrentUIViewController(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Check to see if there is a ItemsView in a collection view or CarouselView and replace Shell Renderer with the correct handler | ||||||||||||||||||||||
| viewController = itemsView?.Where(item => item.Handler is not null) | ||||||||||||||||||||||
| .Select(item => GetUIViewController(item.Handler)) | ||||||||||||||||||||||
| .FirstOrDefault(viewController => viewController is not null); | ||||||||||||||||||||||
|
Comment on lines
+66
to
+68
|
||||||||||||||||||||||
| viewController = itemsView?.Where(item => item.Handler is not null) | |
| .Select(item => GetUIViewController(item.Handler)) | |
| .FirstOrDefault(viewController => viewController is not null); | |
| var potentialViewController = itemsView?.Where(item => item.Handler is not null) | |
| .Select(item => GetUIViewController(item.Handler)) | |
| .FirstOrDefault(viewController => viewController is not null); | |
| if (potentialViewController is not null) | |
| { | |
| viewController = potentialViewController; | |
| } |
Copilot
AI
Jul 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The out parameter itemsView is initialized but never populated with the discovered items. You should assign the local itemsViewsOnPage list to itemsView (e.g. itemsView = itemsViewsOnPage;).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secondWindowis declared but never initialized in the constructor, soOnAppearingwill always return early. Reintroduce its assignment using your new URL constants.