| File: Platform\ViewExtensions.cs | Web Access |
| Project: src\src\Core\src\Core.csproj (Microsoft.Maui) |
using System; using System.Numerics; using Microsoft.Maui.Graphics; using System.Threading.Tasks; using Microsoft.Maui.Media; using System.IO; using System.Collections.Generic; #if (NETSTANDARD || !PLATFORM) || (NET6_0_OR_GREATER && !IOS && !ANDROID) using IPlatformViewHandler = Microsoft.Maui.IViewHandler; #endif #if IOS || MACCATALYST using PlatformView = UIKit.UIView; using ParentView = UIKit.UIView; #elif ANDROID using PlatformView = Android.Views.View; using ParentView = Android.Views.IViewParent; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; using ParentView = Microsoft.UI.Xaml.DependencyObject; #elif TIZEN using PlatformView = Tizen.NUI.BaseComponents.View; using ParentView = Tizen.NUI.BaseComponents.View; #else using PlatformView = System.Object; using ParentView = System.Object; #endif namespace Microsoft.Maui.Platform { /// <include file="../../docs/Microsoft.Maui/ViewExtensions.xml" path="Type[@FullName='Microsoft.Maui.ViewExtensions']/Docs/*" /> public static partial class ViewExtensions { internal static Vector3 ExtractPosition(this Matrix4x4 matrix) => matrix.Translation; internal static Vector3 ExtractScale(this Matrix4x4 matrix) => new Vector3(matrix.M11, matrix.M22, matrix.M33); internal static double ExtractAngleInRadians(this Matrix4x4 matrix) => Math.Atan2(matrix.M21, matrix.M11); internal static double ExtractAngleInDegrees(this Matrix4x4 matrix) => ExtractAngleInRadians(matrix) * 180 / Math.PI; public static IPlatformViewHandler ToHandler(this IView view, IMauiContext context) => (IPlatformViewHandler)ElementExtensions.ToHandler(view, context); internal static T? GetParentOfType<T>(this ParentView? view) #if ANDROID where T : class, ParentView #elif PLATFORM where T : ParentView #else where T : class #endif { if (view is T t) return t; while (view != null) { T? parent = view?.GetParent() as T; if (parent != null) return parent; view = view?.GetParent() as ParentView; } return default; } // Only Windows and Android have different types for the Parent type #if WINDOWS || ANDROID internal static ParentView? FindParent(this PlatformView? view, Func<ParentView?, bool> searchExpression) { if (view?.Parent is ParentView pv) { if (searchExpression(pv)) return pv; return pv.FindParent(searchExpression); } return default; } #else internal #endif static ParentView? FindParent(this ParentView? view, Func<ParentView?, bool> searchExpression) { while (view != null) { var parent = view?.GetParent() as ParentView; if (searchExpression(parent)) return parent; view = view?.GetParent() as ParentView; } return default; } #if WINDOWS || ANDROID internal static T? GetParentOfType<T>(this PlatformView view) #if ANDROID where T : class, ParentView #elif PLATFORM where T : ParentView #else where T : class #endif { if (view is T t) return t; return view.GetParent()?.GetParentOfType<T>(); } #endif internal static bool IsThisMyPlatformView(this IElement? element, PlatformView platformView) { if (element is not null && element.Handler is IPlatformViewHandler pvh) { return pvh.PlatformView == platformView || pvh.ContainerView == platformView; } return false; } internal static IDisposable OnUnloaded(this IElement element, Action action) { #if PLATFORM if (element.Handler is IPlatformViewHandler platformViewHandler && platformViewHandler.PlatformView is not null) { #if IOS if (platformViewHandler.ContainerView is IUIViewLifeCycleEvents) return platformViewHandler.ContainerView.OnUnloaded(action); #endif return platformViewHandler.PlatformView.OnUnloaded(action); } throw new InvalidOperationException("Handler is not set on element"); #else throw new NotImplementedException(); #endif } internal static IDisposable OnLoaded(this IElement element, Action action) { #if PLATFORM if (element.Handler is IPlatformViewHandler platformViewHandler && platformViewHandler.PlatformView is not null) { #if IOS if (platformViewHandler.ContainerView is IUIViewLifeCycleEvents) return platformViewHandler.ContainerView.OnLoaded(action); #endif return platformViewHandler.PlatformView.OnLoaded(action); } throw new InvalidOperationException("Handler is not set on element"); #else throw new NotImplementedException(); #endif } #if PLATFORM internal static Task OnUnloadedAsync(this PlatformView platformView, TimeSpan? timeOut = null) { timeOut = timeOut ?? TimeSpan.FromSeconds(2); TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>(); IDisposable? token = null; token = platformView.OnUnloaded(() => { taskCompletionSource.SetResult(true); token?.Dispose(); token = null; }); return taskCompletionSource.Task.WaitAsync(timeOut.Value); } internal static Task OnLoadedAsync(this PlatformView platformView, TimeSpan? timeOut = null) { timeOut = timeOut ?? TimeSpan.FromSeconds(2); TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>(); IDisposable? token = null; token = platformView.OnLoaded(() => { taskCompletionSource.SetResult(true); token?.Dispose(); token = null; }); return taskCompletionSource.Task.WaitAsync(timeOut.Value); } #endif internal static bool IsLoadedOnPlatform(this IElement element) { if (element.Handler is not IPlatformViewHandler pvh) return false; #if PLATFORM return pvh.PlatformView?.IsLoaded() == true; #else return true; #endif } #if PLATFORM internal static T? FindDescendantView<T>(this PlatformView view, Func<PlatformView, bool> predicate) where T : PlatformView { var queue = new Queue<PlatformView>(); queue.Enqueue(view); while (queue.Count > 0) { var descendantView = queue.Dequeue(); if (descendantView is T result && predicate.Invoke(result)) return result; int i = 0; PlatformView? child; while ((child = descendantView?.GetChildAt<PlatformView>(i)) is not null) { #if TIZEN // I had to add this check for Tizen to compile. // I think Tizen isn't accounting for the null check // in the while loop correctly if (child is null) break; #endif queue.Enqueue(child); i++; } } return null; } #endif } }