İşleyicileri kullanarak özel denetim oluşturma
Uygulamalar için standart bir gereksinim, video oynatabilmektir. Bu makalede, platformlar arası denetim API'sini Video oynatan Android, iOS ve Mac Catalyst'daki yerel görünümlerle eşlemek için işleyici kullanan bir .NET Çok platformlu Uygulama Kullanıcı Arabirimi (.NET MAUI) Video
platformlar arası denetimin nasıl oluşturulacağı incelenmektedir. Bu denetim üç kaynaktan video oynatabilir:
- Uzak bir videosunu temsil eden URL.
- Uygulamaya eklenmiş bir dosya olan kaynak.
- Cihazın video kitaplığından bir dosya.
Video denetimleri, videoyu oynatmaya ve duraklatmaya yönelik düğmeler olan aktarım denetimlerini ve videodaki ilerlemeyi gösteren ve kullanıcının farklı bir konuma hızla geçiş yapmasını sağlayan bir konumlandırma çubuğu gerektirir. Denetim Video
, platform tarafından sağlanan aktarım denetimlerini ve konumlandırma çubuğunu kullanabilir veya özel aktarım denetimleri ve bir konumlandırma çubuğu sağlayabilirsiniz. Aşağıdaki ekran görüntüleri, özel aktarım denetimleri olan ve olmayan iOS üzerindeki denetimi gösterir:
Daha gelişmiş bir video denetiminin ses denetimi, çağrı alındığında video kayıttan yürütmeyi kesintiye uğratma mekanizması ve kayıttan yürütme sırasında ekranı etkin tutma yöntemi gibi ek özellikleri olabilir.
Denetimin Video
mimarisi aşağıdaki diyagramda gösterilmiştir:
sınıfı, Video
denetim için platformlar arası API sağlar. Platformlar arası API'nin yerel görünüm API'lerine eşlemesi, sınıfı sınıfa eşleyen Video
her platformdaki sınıf MauiVideoPlayer
tarafından VideoHandler
gerçekleştirilir. iOS ve Mac Catalyst'te MauiVideoPlayer
sınıfı, video kayıttan yürütme sağlamak için türünü kullanır AVPlayer
. Android'de MauiVideoPlayer
sınıfı, video kayıttan yürütme sağlamak için türünü kullanır VideoView
. Windows'da MauiVideoPlayer
sınıfı, video kayıttan yürütme sağlamak için türünü kullanır MediaPlayerElement
.
Önemli
.NET MAUI, işleyicilerini arabirimler aracılığıyla platformlar arası denetimlerinden ayırır. Bu, .NET MAUI'nin işleyicilerini kullanmaya devam ederken arabirimleri uygulayan Comet ve Fabulous gibi deneysel çerçevelerin kendi platformlar arası denetimlerini sağlamasına olanak tanır. Platformlar arası denetiminiz için bir arabirim oluşturmak, yalnızca işleyicinizi benzer bir amaçla veya test amacıyla platformlar arası denetiminden ayırmanız gerekiyorsa gereklidir.
Platform uygulamaları işleyiciler tarafından sağlanan platformlar arası bir .NET MAUI özel denetimi oluşturma işlemi aşağıdaki gibidir:
- Denetimin genel API'sini sağlayan platformlar arası denetim için bir sınıf oluşturun. Daha fazla bilgi için bkz . Platformlar arası denetim oluşturma.
- Gerekli ek platformlar arası türleri oluşturun.
- İşleyici
partial
sınıfı oluşturun. Daha fazla bilgi için bkz . İşleyiciyi oluşturma. - İşleyici sınıfında, platformlar arası özellik değişiklikleri gerçekleştiğinde gerçekleştirecek eylemleri tanımlayan bir PropertyMapper sözlük oluşturun. Daha fazla bilgi için bkz . Özellik eşleyicisini oluşturma.
- İsteğe bağlı olarak, işleyici sınıfınızda, platformlar arası denetim, platformlar arası denetimi uygulayan yerel görünümlere yönergeler gönderdiğinde gerçekleştirilecek eylemleri tanımlayan bir CommandMapper sözlük oluşturun. Daha fazla bilgi için bkz . Komut eşleyicisini oluşturma.
- Platformlar arası denetimi uygulayan yerel görünümleri oluşturan her platform için işleyici sınıfları oluşturun
partial
. Daha fazla bilgi için bkz . Platform denetimleri oluşturma. - uygulamanızın
MauiProgram
sınıfında ve AddHandler yöntemlerini kullanarak ConfigureMauiHandlers işleyiciyi kaydedin. Daha fazla bilgi için bkz . İşleyiciyi kaydetme.
Daha sonra platformlar arası denetim kullanılabilir. Daha fazla bilgi için bkz . Platformlar arası denetimi kullanma.
Platformlar arası denetim oluşturma
Platformlar arası denetim oluşturmak için, öğesinden Viewtüretilen bir sınıf oluşturmanız gerekir:
using System.ComponentModel;
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
public static readonly BindableProperty AreTransportControlsEnabledProperty =
BindableProperty.Create(nameof(AreTransportControlsEnabled), typeof(bool), typeof(Video), true);
public static readonly BindableProperty SourceProperty =
BindableProperty.Create(nameof(Source), typeof(VideoSource), typeof(Video), null);
public static readonly BindableProperty AutoPlayProperty =
BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(Video), true);
public static readonly BindableProperty IsLoopingProperty =
BindableProperty.Create(nameof(IsLooping), typeof(bool), typeof(Video), false);
public bool AreTransportControlsEnabled
{
get { return (bool)GetValue(AreTransportControlsEnabledProperty); }
set { SetValue(AreTransportControlsEnabledProperty, value); }
}
[TypeConverter(typeof(VideoSourceConverter))]
public VideoSource Source
{
get { return (VideoSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public bool AutoPlay
{
get { return (bool)GetValue(AutoPlayProperty); }
set { SetValue(AutoPlayProperty, value); }
}
public bool IsLooping
{
get { return (bool)GetValue(IsLoopingProperty); }
set { SetValue(IsLoopingProperty, value); }
}
...
}
}
Denetim, işleyicisi tarafından erişilecek bir genel API sağlamalı ve tüketicileri denetlemelidir. Platformlar arası denetimler, düzenleri ve görünümleri ekrana yerleştirmek için kullanılan bir görsel öğeyi temsil eden öğesinden Viewtüretilmelidir.
İşleyiciyi oluşturma
Platformlar arası denetiminizi oluşturduktan sonra işleyiciniz için bir partial
sınıf oluşturmanız gerekir:
#if IOS || MACCATALYST
using PlatformView = VideoDemos.Platforms.MaciOS.MauiVideoPlayer;
#elif ANDROID
using PlatformView = VideoDemos.Platforms.Android.MauiVideoPlayer;
#elif WINDOWS
using PlatformView = VideoDemos.Platforms.Windows.MauiVideoPlayer;
#elif (NETSTANDARD || !PLATFORM) || (NET6_0_OR_GREATER && !IOS && !ANDROID)
using PlatformView = System.Object;
#endif
using VideoDemos.Controls;
using Microsoft.Maui.Handlers;
namespace VideoDemos.Handlers
{
public partial class VideoHandler
{
}
}
İşleyici sınıfı, uygulaması ek bir kısmi sınıfla her platformda tamamlanacak kısmi bir sınıftır.
Koşullu using
deyimler, her platformda türü tanımlar PlatformView
. Android, iOS, Mac Catalyst ve Windows'da yerel görünümler özel MauiVideoPlayer
sınıf tarafından sağlanır. Son koşullu using
deyim, değerine System.Object
eşit olduğunu tanımlarPlatformView
. Bu, türün tüm platformlardaki PlatformView
kullanım için işleyici içinde kullanılabilmesi için gereklidir. Alternatif olarak, koşullu derleme kullanarak özelliği platform başına bir kez tanımlamanız PlatformView
gerekir.
Özellik eşleyicisi oluşturma
Her işleyici genellikle platformlar arası denetimde bir özellik değişikliği gerçekleştiğinde hangi Eylemlerin gerçekleştireceğini tanımlayan bir özellik eşleyicisi sağlar. Tür PropertyMapper , platformlar arası denetimin özelliklerini ilişkili Eylemleriyle eşleyen bir Dictionary
türdür.
PropertyMapper .NET MAUI ViewHandler<TVirtualView,TPlatformView> sınıfında tanımlanır ve iki genel bağımsız değişkenin sağlanmasını gerektirir:
- platformlar arası denetimin sınıfından Viewtüretilir.
- İşleyici için sınıfı.
Aşağıdaki kod örneği, tanımıyla PropertyMapper genişletilmiş sınıfı gösterirVideoHandler
:
public partial class VideoHandler
{
public static IPropertyMapper<Video, VideoHandler> PropertyMapper = new PropertyMapper<Video, VideoHandler>(ViewHandler.ViewMapper)
{
[nameof(Video.AreTransportControlsEnabled)] = MapAreTransportControlsEnabled,
[nameof(Video.Source)] = MapSource,
[nameof(Video.IsLooping)] = MapIsLooping,
[nameof(Video.Position)] = MapPosition
};
public VideoHandler() : base(PropertyMapper)
{
}
}
PropertyMapper, Dictionary
anahtarı a string
olan ve değeri genel Action
olan bir değeridir. , string
platformlar arası denetimin özellik adını, Action
işleyici ve platformlar arası denetimi bağımsız değişken olarak gerektiren bir static
yöntemi temsil eder. Örneğin, yönteminin MapSource
imzası şeklindedir public static void MapSource(VideoHandler handler, Video video)
.
Her platform işleyicisi, yerel görünüm API'lerini işleyen Eylemlerin uygulamalarını sağlamalıdır. Bu, bir özellik platformlar arası denetimde ayarlandığında temel alınan yerel görünümün gerektiği gibi güncelleştirilmesini sağlar. Bu yaklaşımın avantajı, özellik eşleyicisi alt sınıflama olmadan platformlar arası denetim tüketicileri tarafından değiştirilebildiği için kolay platformlar arası denetim özelleştirmesine olanak sağlamasıdır.
Komut eşleyicisi oluşturma
Her işleyici, platformlar arası denetim komutları yerel görünümlere gönderdiğinde hangi Eylemlerin gerçekleştirebileceğini tanımlayan bir komut eşleyici de sağlayabilir. Komut eşleyicileri özellik eşleyicilerine benzer, ancak ek verilerin geçirilmesine izin verir. Bu bağlamda, komut bir yönergedir ve isteğe bağlı olarak verileri yerel görünüme gönderilir. Tür CommandMapper , platformlar arası denetim üyelerini ilişkili Eylemleriyle eşleyen bir Dictionary
türdür.
CommandMapper .NET MAUI ViewHandler<TVirtualView,TPlatformView> sınıfında tanımlanır ve iki genel bağımsız değişkenin sağlanmasını gerektirir:
- platformlar arası denetimin sınıfından Viewtüretilir.
- İşleyici için sınıfı.
Aşağıdaki kod örneği, tanımıyla CommandMapper genişletilmiş sınıfı gösterirVideoHandler
:
public partial class VideoHandler
{
public static IPropertyMapper<Video, VideoHandler> PropertyMapper = new PropertyMapper<Video, VideoHandler>(ViewHandler.ViewMapper)
{
[nameof(Video.AreTransportControlsEnabled)] = MapAreTransportControlsEnabled,
[nameof(Video.Source)] = MapSource,
[nameof(Video.IsLooping)] = MapIsLooping,
[nameof(Video.Position)] = MapPosition
};
public static CommandMapper<Video, VideoHandler> CommandMapper = new(ViewCommandMapper)
{
[nameof(Video.UpdateStatus)] = MapUpdateStatus,
[nameof(Video.PlayRequested)] = MapPlayRequested,
[nameof(Video.PauseRequested)] = MapPauseRequested,
[nameof(Video.StopRequested)] = MapStopRequested
};
public VideoHandler() : base(PropertyMapper, CommandMapper)
{
}
}
CommandMapper, Dictionary
anahtarı a string
olan ve değeri genel Action
olan bir değeridir. , string
platformlar arası denetimin komut adını temsil eder ve Action
işleyici, platformlar arası denetim ve isteğe bağlı verileri bağımsız değişken olarak gerektiren bir static
yöntemi temsil eder. Örneğin, yönteminin MapPlayRequested
imzası şeklindedir public static void MapPlayRequested(VideoHandler handler, Video video, object? args)
.
Her platform işleyicisi, yerel görünüm API'lerini işleyen Eylemlerin uygulamalarını sağlamalıdır. Bu, platformlar arası denetimden bir komut gönderildiğinde, temel alınan yerel görünümün gerektiği gibi işlendiğinden emin olur. Bu yaklaşımın avantajı, yerel görünümlerin platformlar arası denetim olaylarına abone olma ve abonelikten çıkma gereksinimini ortadan kaldırmasıdır. Ayrıca, komut eşleyicisi alt sınıflama olmadan platformlar arası denetim tüketicileri tarafından değiştirilebildiği için kolay özelleştirmeye olanak tanır.
Platform denetimlerini oluşturma
İşleyiciniz için eşleyicileri oluşturduktan sonra tüm platformlarda işleyici uygulamaları sağlamanız gerekir. Bu, Platforms klasörünün alt klasörlerine kısmi sınıf işleyicisi uygulamaları eklenerek gerçekleştirilebilir. Alternatif olarak projenizi dosya adı tabanlı çoklu hedeflemeyi veya klasör tabanlı çoklu hedeflemeyi ya da her ikisini de destekleyecek şekilde yapılandırabilirsiniz.
Örnek uygulama, dosya adı tabanlı çoklu hedeflemeyi destekleyecek şekilde yapılandırılır, böylece işleyici sınıflarının tümü tek bir klasörde bulunur:
VideoHandler
Eşleyicileri içeren sınıf VideoHandler.cs olarak adlandırılır. Platform uygulamaları VideoHandler.Android.cs, VideoHandler.MaciOS.cs ve VideoHandler.Windows.cs dosyalarında bulunur. Bu dosya adı tabanlı çoklu hedefleme, düğümün alt öğeleri <Project>
olarak proje dosyasına aşağıdaki XML eklenerek yapılandırılır:
<!-- Android -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-android')) != true">
<Compile Remove="**\*.Android.cs" />
<None Include="**\*.Android.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- iOS and Mac Catalyst -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-ios')) != true AND $(TargetFramework.StartsWith('net8.0-maccatalyst')) != true">
<Compile Remove="**\*.MaciOS.cs" />
<None Include="**\*.MaciOS.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- Windows -->
<ItemGroup Condition="$(TargetFramework.Contains('-windows')) != true ">
<Compile Remove="**\*.Windows.cs" />
<None Include="**\*.Windows.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
Çoklu hedeflemeyi yapılandırma hakkında daha fazla bilgi için bkz . Çoklu hedeflemeyi yapılandırma.
Her platform işleyici sınıfı kısmi bir sınıf olmalı ve iki tür bağımsız değişken gerektiren sınıfından ViewHandler<TVirtualView,TPlatformView> türetilmelidir:
- platformlar arası denetimin sınıfından Viewtüretilir.
- Platformda platformlar arası denetimi uygulayan yerel görünümün türü. Bu, işleyicideki özelliğin
PlatformView
türüyle aynı olmalıdır.
Önemli
ViewHandler<TVirtualView,TPlatformView> sınıfı ve PlatformView özellikleri sağlarVirtualView. VirtualView özelliği, işleyicisinden platformlar arası denetime erişmek için kullanılır. PlatformView özelliği, platformlar arası denetimi uygulayan her platformda yerel görünüme erişmek için kullanılır.
Platform işleyicisi uygulamalarının her biri aşağıdaki yöntemleri geçersiz kılmalıdır:
- CreatePlatformView, platformlar arası denetimi uygulayan yerel görünümü oluşturup döndürmelidir.
- ConnectHandler, yerel görünümü başlatma ve olay aboneliklerini gerçekleştirme gibi herhangi bir yerel görünüm kurulumu gerçekleştirmelidir.
- DisconnectHandler, olaylardan aboneliği kaldırma ve nesneleri yok etme gibi herhangi bir yerel görünüm temizlemesi gerçekleştirmelidir.
Önemli
DisconnectHandler yöntemi kasıtlı olarak .NET MAUI tarafından çağrılmıyor. Bunun yerine, uygulamanızın yaşam döngüsünde uygun bir konumdan kendiniz çağırmanız gerekir. Daha fazla bilgi için bkz . Yerel görünüm temizleme.
Önemli
Yöntem DisconnectHandler varsayılan olarak .NET MAUI tarafından otomatik olarak çağrılır, ancak bu davranış değiştirilebilir. Daha fazla bilgi için bkz . Denetim işleyicisi bağlantısını kesme.
Her platform işleyicisi, eşleyici sözlüklerinde tanımlanan Eylemleri de uygulamalıdır.
Ayrıca her platform işleyicisi, platform üzerinde platformlar arası denetimin işlevselliğini uygulamak için gerektiği gibi kod sağlamalıdır. Alternatif olarak, bu, burada benimsenen yaklaşım olan ek bir tür tarafından sağlanabilir.
Android
Android'de bir VideoView
ile video oynatılır. Ancak burada, VideoView
yerel görünümü işleyicisinden ayrı tutmak için türü MauiVideoPlayer
kapsüllenmiştir. Aşağıdaki örnekte, android için kısmi sınıfı üç geçersiz kılmayla gösterilmiştir VideoHandler
:
#nullable enable
using Microsoft.Maui.Handlers;
using VideoDemos.Controls;
using VideoDemos.Platforms.Android;
namespace VideoDemos.Handlers
{
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
protected override MauiVideoPlayer CreatePlatformView() => new MauiVideoPlayer(Context, VirtualView);
protected override void ConnectHandler(MauiVideoPlayer platformView)
{
base.ConnectHandler(platformView);
// Perform any control setup here
}
protected override void DisconnectHandler(MauiVideoPlayer platformView)
{
platformView.Dispose();
base.DisconnectHandler(platformView);
}
...
}
}
VideoHandler
sınıfından ViewHandler<TVirtualView,TPlatformView> türetilir ve Video
genel bağımsız değişken platformlar arası denetim türünü belirtir ve MauiVideoPlayer
bağımsız değişken yerel görünümü kapsülleyen VideoView
türü belirtir.
Geçersiz CreatePlatformView kılma bir MauiVideoPlayer
nesne oluşturur ve döndürür. Geçersiz ConnectHandler kılma, gerekli yerel görünüm ayarlarını gerçekleştirmek için konumdur. Geçersiz DisconnectHandler kılma, herhangi bir yerel görünüm temizleme işlemini gerçekleştirmek için konumdur ve bu nedenle örnekte yöntemini MauiVideoPlayer
çağırırDispose
.
Platform işleyicisinin ayrıca özellik eşleyici sözlüğünde tanımlanan Eylemleri uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapAreTransportControlsEnabled(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateTransportControlsEnabled();
}
public static void MapSource(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateSource();
}
public static void MapIsLooping(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateIsLooping();
}
public static void MapPosition(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdatePosition();
}
...
}
Her Eylem, platformlar arası denetimde değişen bir özelliğe yanıt olarak yürütülür ve bağımsız değişken olarak işleyici ve platformlar arası denetim örnekleri gerektiren bir static
yöntemdir. Her durumda, Eylem türünde tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
Platform işleyicisinin komut eşleyici sözlüğünde tanımlanan Eylemleri de uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapUpdateStatus(VideoHandler handler, Video video, object? args)
{
handler.PlatformView?.UpdateStatus();
}
public static void MapPlayRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PlayRequested(position);
}
public static void MapPauseRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PauseRequested(position);
}
public static void MapStopRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.StopRequested(position);
}
...
}
Her Eylem, platformlar arası denetimden gönderilen bir komuta yanıt olarak yürütülür ve işleyici ve platformlar arası denetim örnekleri ile isteğe bağlı verileri bağımsız değişken olarak gerektiren bir static
yöntemdir. Her durumda, Eylem isteğe bağlı verileri ayıkladıktan sonra sınıfında tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
Android'de MauiVideoPlayer
sınıfı, yerel görünümü işleyicisinden ayrı tutmak için öğesini kapsüller VideoView
:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
MediaController _mediaController;
bool _isPrepared;
Context _context;
Video _video;
public MauiVideoPlayer(Context context, Video video) : base(context)
{
_context = context;
_video = video;
SetBackgroundColor(Color.Black);
// Create a RelativeLayout for sizing the video
RelativeLayout relativeLayout = new RelativeLayout(_context)
{
LayoutParameters = new CoordinatorLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent)
{
Gravity = (int)GravityFlags.Center
}
};
// Create a VideoView and position it in the RelativeLayout
_videoView = new VideoView(context)
{
LayoutParameters = new RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent)
};
// Add to the layouts
relativeLayout.AddView(_videoView);
AddView(relativeLayout);
// Handle events
_videoView.Prepared += OnVideoViewPrepared;
}
...
}
}
MauiVideoPlayer
' den CoordinatorLayout
türetilir çünkü Android'deki bir .NET MAUI uygulamasındaki kök yerel görünümü şeklindedir CoordinatorLayout
. MauiVideoPlayer
sınıfı diğer yerel Android türlerinden türetilebilir ancak bazı senaryolarda yerel görünüm konumlandırmasını denetlemek zor olabilir.
doğrudan VideoView
öğesine CoordinatorLayout
eklenebilir ve gerektiğinde düzende konumlandırılabilir. Ancak, burada, öğesine CoordinatorLayout
bir Android RelativeLayout
eklenir ve öğesine VideoView
eklenirRelativeLayout
. Düzen parametreleri hem de RelativeLayout
VideoView
üzerinde ayarlanır, böylece VideoView
sayfa ortalanır ve en boy oranını korurken kullanılabilir alanı dolduracak şekilde genişletilir.
Oluşturucu ayrıca olaya abonedir VideoView.Prepared
. Bu olay, video kayıttan yürütme için hazır olduğunda oluşturulur ve geçersiz kılmada Dispose
aboneliği kaldırılır:
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
Video _video;
...
protected override void Dispose(bool disposing)
{
if (disposing)
{
_videoView.Prepared -= OnVideoViewPrepared;
_videoView.Dispose();
_videoView = null;
_video = null;
}
base.Dispose(disposing);
}
...
}
Geçersiz kılma, Dispose
olaydan aboneliği kaldırmaya Prepared
ek olarak yerel görünüm temizleme de gerçekleştirir.
Not
Geçersiz Dispose
kılma, işleyicinin DisconnectHandler geçersiz kılma tarafından çağrılır.
Platform taşıma denetimleri videoyu yürüten, duraklatan ve durduran düğmeler içerir ve Android'in MediaController
türüne göre sağlanır. Video.AreTransportControlsEnabled
özelliği olarak true
ayarlanırsa, a MediaController
öğesinin medya yürütücüsü VideoView
olarak ayarlanır. Bunun nedeniAreTransportControlsEnabled
, özellik ayarlandığında işleyicinin özellik eşleyicisinin yönteminin MapAreTransportControlsEnabled
çağrılmasını sağlaması ve bunun da içinde MauiVideoPlayer
yöntemini çağırmasıdırUpdateTransportControlsEnabled
:
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
MediaController _mediaController;
Video _video;
...
public void UpdateTransportControlsEnabled()
{
if (_video.AreTransportControlsEnabled)
{
_mediaController = new MediaController(_context);
_mediaController.SetMediaPlayer(_videoView);
_videoView.SetMediaController(_mediaController);
}
else
{
_videoView.SetMediaController(null);
if (_mediaController != null)
{
_mediaController.SetMediaPlayer(null);
_mediaController = null;
}
}
}
...
}
Kullanılmayan ancak videoya dokunarak geri yüklenebilen aktarım denetimleri kaybolur.
Video.AreTransportControlsEnabled
özelliği olarak false
ayarlanırsa, MediaController
öğesinin medya yürütücüsü VideoView
olarak kaldırılır. Bu senaryoda video kayıttan yürütmeyi program aracılığıyla denetleyebilir veya kendi aktarım denetimlerinizi sağlayabilirsiniz. Daha fazla bilgi için bkz . Özel aktarım denetimleri oluşturma.
iOS ve Mac Catalyst
Video, ve ile AVPlayer
AVPlayerViewController
iOS ve Mac Catalyst üzerinde oynatılır. Ancak burada, bu türler yerel görünümleri işleyicilerinden ayrı tutmak için bir MauiVideoPlayer
tür içinde kapsüllenir. Aşağıdaki örnek, iOS için kısmi sınıfı ve üç geçersiz kılmasını gösterir VideoHandler
:
using Microsoft.Maui.Handlers;
using VideoDemos.Controls;
using VideoDemos.Platforms.MaciOS;
namespace VideoDemos.Handlers
{
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
protected override MauiVideoPlayer CreatePlatformView() => new MauiVideoPlayer(VirtualView);
protected override void ConnectHandler(MauiVideoPlayer platformView)
{
base.ConnectHandler(platformView);
// Perform any control setup here
}
protected override void DisconnectHandler(MauiVideoPlayer platformView)
{
platformView.Dispose();
base.DisconnectHandler(platformView);
}
...
}
}
VideoHandler
sınıfından ViewHandler<TVirtualView,TPlatformView> türetilir ve Video
genel bağımsız değişken platformlar arası denetim türünü, MauiVideoPlayer
bağımsız değişken ise ve AVPlayerViewController
yerel görünümlerini AVPlayer
kapsülleyen türü belirtir.
Geçersiz CreatePlatformView kılma bir MauiVideoPlayer
nesne oluşturur ve döndürür. Geçersiz ConnectHandler kılma, gerekli yerel görünüm ayarlarını gerçekleştirmek için konumdur. Geçersiz DisconnectHandler kılma, herhangi bir yerel görünüm temizleme işlemini gerçekleştirmek için konumdur ve bu nedenle örnekte yöntemini MauiVideoPlayer
çağırırDispose
.
Platform işleyicisinin ayrıca özellik eşleyici sözlüğünde tanımlanan Eylemleri uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapAreTransportControlsEnabled(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdateTransportControlsEnabled();
}
public static void MapSource(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdateSource();
}
public static void MapIsLooping(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateIsLooping();
}
public static void MapPosition(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdatePosition();
}
...
}
Her Eylem, platformlar arası denetimde değişen bir özelliğe yanıt olarak yürütülür ve bağımsız değişken olarak işleyici ve platformlar arası denetim örnekleri gerektiren bir static
yöntemdir. Her durumda, Eylem türünde tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
Platform işleyicisinin komut eşleyici sözlüğünde tanımlanan Eylemleri de uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapUpdateStatus(VideoHandler handler, Video video, object? args)
{
handler.PlatformView?.UpdateStatus();
}
public static void MapPlayRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PlayRequested(position);
}
public static void MapPauseRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PauseRequested(position);
}
public static void MapStopRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.StopRequested(position);
}
...
}
Her Eylem, platformlar arası denetimden gönderilen bir komuta yanıt olarak yürütülür ve işleyici ve platformlar arası denetim örnekleri ile isteğe bağlı verileri bağımsız değişken olarak gerektiren bir static
yöntemdir. Her durumda, Eylem isteğe bağlı verileri ayıkladıktan sonra sınıfında tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
iOS ve Mac Catalyst'te sınıfı, MauiVideoPlayer
yerel görünümleri işleyicilerinden ayrı tutmak için ve AVPlayerViewController
türlerini kapsüllerAVPlayer
:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerViewController _playerViewController;
Video _video;
...
public MauiVideoPlayer(Video video)
{
_video = video;
_playerViewController = new AVPlayerViewController();
_player = new AVPlayer();
_playerViewController.Player = _player;
_playerViewController.View.Frame = this.Bounds;
#if IOS16_0_OR_GREATER || MACCATALYST16_1_OR_GREATER
// On iOS 16 and Mac Catalyst 16, for Shell-based apps, the AVPlayerViewController has to be added to the parent ViewController, otherwise the transport controls won't be displayed.
var viewController = WindowStateManager.Default.GetCurrentUIViewController();
// If there's no view controller, assume it's not Shell and continue because the transport controls will still be displayed.
if (viewController?.View is not null)
{
// Zero out the safe area insets of the AVPlayerViewController
UIEdgeInsets insets = viewController.View.SafeAreaInsets;
_playerViewController.AdditionalSafeAreaInsets = new UIEdgeInsets(insets.Top * -1, insets.Left, insets.Bottom * -1, insets.Right);
// Add the View from the AVPlayerViewController to the parent ViewController
viewController.View.AddSubview(_playerViewController.View);
}
#endif
// Use the View from the AVPlayerViewController as the native control
AddSubview(_playerViewController.View);
}
...
}
}
MauiVideoPlayer
, içeriği görüntüleyen ve bu içerikle kullanıcı etkileşimini işleyen nesneler için iOS ve Mac Catalyst'te temel sınıf olan öğesinden UIView
türetilir. Oluşturucu, bir AVPlayer
medya dosyasının kayıttan yürütmesini ve zamanlamasını yöneten bir nesnesi oluşturur ve bunu bir AVPlayerViewController
öğesinin Player
özellik değeri olarak ayarlar. öğesinin AVPlayerViewController
AVPlayer
içeriğini görüntüler ve aktarım denetimlerini ve diğer özellikleri sunar. Ardından denetimin boyutu ve konumu ayarlanır ve videonun sayfada ortalanmasını ve en boy oranını korurken kullanılabilir alanı dolduracak şekilde genişletilmesini sağlar. iOS 16 ve Mac Catalyst 16'da, AVPlayerViewController
Kabuk tabanlı uygulamalar için üst ViewController
öğeye eklenmesi gerekir, aksi takdirde aktarım denetimleri görüntülenmez. Yerel görünüm, 'den görünümdür AVPlayerViewController
ve ardından sayfaya eklenir.
Dispose
yöntemi, yerel görünüm temizleme işlemini gerçekleştirmekle sorumludur:
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerViewController _playerViewController;
Video _video;
...
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_player != null)
{
DestroyPlayedToEndObserver();
_player.ReplaceCurrentItemWithPlayerItem(null);
_player.Dispose();
}
if (_playerViewController != null)
_playerViewController.Dispose();
_video = null;
}
base.Dispose(disposing);
}
...
}
Bazı senaryolarda, bir video kayıttan yürütme sayfası kaldırıldıktan sonra videolar oynatılır. Videoyu durdurmak için, ReplaceCurrentItemWithPlayerItem
geçersiz kılmada Dispose
olarak ayarlanır null
ve diğer yerel görünüm temizleme gerçekleştirilir.
Not
Geçersiz Dispose
kılma, işleyicinin DisconnectHandler geçersiz kılma tarafından çağrılır.
Platform taşıma denetimleri, videoyu yürüten, duraklatan ve durduran düğmeler içerir ve tür tarafından AVPlayerViewController
sağlanır. Video.AreTransportControlsEnabled
özelliği olarak true
AVPlayerViewController
ayarlanırsa, kayıttan yürütme denetimlerini görüntüler. Bunun nedeniAreTransportControlsEnabled
, özellik ayarlandığında işleyicinin özellik eşleyicisinin yönteminin MapAreTransportControlsEnabled
çağrılmasını sağlaması ve bunun da içinde MauiVideoPlayer
yöntemini çağırmasıdırUpdateTransportControlsEnabled
:
public class MauiVideoPlayer : UIView
{
AVPlayerViewController _playerViewController;
Video _video;
...
public void UpdateTransportControlsEnabled()
{
_playerViewController.ShowsPlaybackControls = _video.AreTransportControlsEnabled;
}
...
}
Kullanılmayan ancak videoya dokunarak geri yüklenebilen aktarım denetimleri kaybolur.
Video.AreTransportControlsEnabled
özelliği olarak ayarlanırsafalse
AVPlayerViewController
, kayıttan yürütme denetimlerini göstermez. Bu senaryoda video kayıttan yürütmeyi program aracılığıyla denetleyebilir veya kendi aktarım denetimlerinizi sağlayabilirsiniz. Daha fazla bilgi için bkz . Özel aktarım denetimleri oluşturma.
Windows
Ile Windows'ta MediaPlayerElement
video oynatılır. Ancak burada, MediaPlayerElement
yerel görünümü işleyicisinden ayrı tutmak için türü MauiVideoPlayer
kapsüllenmiştir. Aşağıdaki örnekte, windows'un VideoHandler
kısmi sınıfı üç geçersiz kılmayla gösterilmiştir:
#nullable enable
using Microsoft.Maui.Handlers;
using VideoDemos.Controls;
using VideoDemos.Platforms.Windows;
namespace VideoDemos.Handlers
{
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
protected override MauiVideoPlayer CreatePlatformView() => new MauiVideoPlayer(VirtualView);
protected override void ConnectHandler(MauiVideoPlayer platformView)
{
base.ConnectHandler(platformView);
// Perform any control setup here
}
protected override void DisconnectHandler(MauiVideoPlayer platformView)
{
platformView.Dispose();
base.DisconnectHandler(platformView);
}
...
}
}
VideoHandler
sınıfından ViewHandler<TVirtualView,TPlatformView> türetilir ve Video
genel bağımsız değişken platformlar arası denetim türünü belirtir ve MauiVideoPlayer
bağımsız değişken yerel görünümü kapsülleyen MediaPlayerElement
türü belirtir.
Geçersiz CreatePlatformView kılma bir MauiVideoPlayer
nesne oluşturur ve döndürür. Geçersiz ConnectHandler kılma, gerekli yerel görünüm ayarlarını gerçekleştirmek için konumdur. Geçersiz DisconnectHandler kılma, herhangi bir yerel görünüm temizleme işlemini gerçekleştirmek için konumdur ve bu nedenle örnekte yöntemini MauiVideoPlayer
çağırırDispose
.
Platform işleyicisinin ayrıca özellik eşleyici sözlüğünde tanımlanan Eylemleri uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapAreTransportControlsEnabled(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateTransportControlsEnabled();
}
public static void MapSource(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateSource();
}
public static void MapIsLooping(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateIsLooping();
}
public static void MapPosition(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdatePosition();
}
...
}
Her Eylem, platformlar arası denetimde değişen bir özelliğe yanıt olarak yürütülür ve bağımsız değişken olarak işleyici ve platformlar arası denetim örnekleri gerektiren bir static
yöntemdir. Her durumda, Eylem türünde tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
Platform işleyicisinin komut eşleyici sözlüğünde tanımlanan Eylemleri de uygulaması gerekir:
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapUpdateStatus(VideoHandler handler, Video video, object? args)
{
handler.PlatformView?.UpdateStatus();
}
public static void MapPlayRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PlayRequested(position);
}
public static void MapPauseRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.PauseRequested(position);
}
public static void MapStopRequested(VideoHandler handler, Video video, object? args)
{
if (args is not VideoPositionEventArgs)
return;
TimeSpan position = ((VideoPositionEventArgs)args).Position;
handler.PlatformView?.StopRequested(position);
}
...
}
Her Eylem, platformlar arası denetimden gönderilen bir komuta yanıt olarak yürütülür ve işleyici ve platformlar arası denetim örnekleri ile isteğe bağlı verileri bağımsız değişken olarak gerektiren bir static
yöntemdir. Her durumda, Eylem isteğe bağlı verileri ayıkladıktan sonra sınıfında tanımlanan MauiVideoPlayer
bir yöntemi çağırır.
Windows'da sınıfı, MauiVideoPlayer
yerel görünümü işleyicisinden ayrı tutmak için öğesini kapsüller MediaPlayerElement
:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
...
public MauiVideoPlayer(Video video)
{
_video = video;
_mediaPlayerElement = new MediaPlayerElement();
this.Children.Add(_mediaPlayerElement);
}
...
}
}
MauiVideoPlayer
öğesinden Gridtüretilir ve MediaPlayerElement
öğesinin Gridalt öğesi olarak eklenir. Bu, tüm kullanılabilir alanı doldurmak için öğesinin otomatik olarak boyutlandırılabilmesini sağlar MediaPlayerElement
.
Dispose
yöntemi, yerel görünüm temizleme işlemini gerçekleştirmekle sorumludur:
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
public void Dispose()
{
if (_isMediaPlayerAttached)
{
_mediaPlayerElement.MediaPlayer.MediaOpened -= OnMediaPlayerMediaOpened;
_mediaPlayerElement.MediaPlayer.Dispose();
}
_mediaPlayerElement = null;
}
...
}
Geçersiz kılma, Dispose
olaydan aboneliği kaldırmaya MediaOpened
ek olarak yerel görünüm temizleme de gerçekleştirir.
Not
Geçersiz Dispose
kılma, işleyicinin DisconnectHandler geçersiz kılma tarafından çağrılır.
Platform taşıma denetimleri, videoyu yürüten, duraklatan ve durduran düğmeler içerir ve tür tarafından MediaPlayerElement
sağlanır. Video.AreTransportControlsEnabled
özelliği olarak true
MediaPlayerElement
ayarlanırsa, kayıttan yürütme denetimlerini görüntüler. Bunun nedeniAreTransportControlsEnabled
, özellik ayarlandığında işleyicinin özellik eşleyicisinin yönteminin MapAreTransportControlsEnabled
çağrılmasını sağlaması ve bunun da içinde MauiVideoPlayer
yöntemini çağırmasıdırUpdateTransportControlsEnabled
:
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
public void UpdateTransportControlsEnabled()
{
_mediaPlayerElement.AreTransportControlsEnabled = _video.AreTransportControlsEnabled;
}
...
}
Video.AreTransportControlsEnabled
özelliği olarak ayarlanırsafalse
MediaPlayerElement
, kayıttan yürütme denetimlerini göstermez. Bu senaryoda video kayıttan yürütmeyi program aracılığıyla denetleyebilir veya kendi aktarım denetimlerinizi sağlayabilirsiniz. Daha fazla bilgi için bkz . Özel aktarım denetimleri oluşturma.
Platformlar arası denetimi platform denetimine dönüştürme
'den Elementtüretilen herhangi bir .NET MAUI platformlar arası denetimi, uzantı yöntemiyle temel alınan platform denetimine ToPlatform dönüştürülebilir:
- Android'de bir ToPlatform .NET MAUI denetimini Android View nesnesine dönüştürür.
- iOS ve Mac Catalyst'te . ToPlatform NET MAUI denetimini bir UIView nesneye dönüştürür.
- Windows'da bir ToPlatform .NET MAUI denetimini nesneye
FrameworkElement
dönüştürür.
Not
ToPlatform yöntemi ad alanındadırMicrosoft.Maui.Platform
.
Tüm platformlarda ToPlatform yöntemi bir MauiContext bağımsız değişken gerektirir.
ToPlatform yöntemi, platformlar arası denetimi platform kodundan temel alınan platform denetimine dönüştürebilir; örneğin, bir platform için kısmi işleyici sınıfında:
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using VideoDemos.Controls;
using VideoDemos.Platforms.Android;
namespace VideoDemos.Handlers
{
public partial class VideoHandler : ViewHandler<Video, MauiVideoPlayer>
{
...
public static void MapSource(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateSource();
// Convert cross-platform control to its underlying platform control
MauiVideoPlayer mvp = (MauiVideoPlayer)video.ToPlatform(handler.MauiContext);
...
}
...
}
}
Bu örnekte, Android'in VideoHandler
MapSource
kısmi sınıfında yöntemi örneği bir MauiVideoPlayer
nesneye dönüştürürVideo
.
Yöntemi ayrıca ToPlatform platformlar arası bir denetimi, platformlar arası koddan temel alınan platform denetimine dönüştürebilir:
using Microsoft.Maui.Platform;
namespace VideoDemos.Views;
public partial class MyPage : ContentPage
{
...
protected override void OnHandlerChanged()
{
// Convert cross-platform control to its underlying platform control
#if ANDROID
Android.Views.View nativeView = video.ToPlatform(video.Handler.MauiContext);
#elif IOS || MACCATALYST
UIKit.UIView nativeView = video.ToPlatform(video.Handler.MauiContext);
#elif WINDOWS
Microsoft.UI.Xaml.FrameworkElement nativeView = video.ToPlatform(video.Handler.MauiContext);
#endif
...
}
...
}
Bu örnekte, adlı video
bir platformlar Video
arası denetim, geçersiz kılmadaki her platformda temel alınan yerel görünümüne OnHandlerChanged() dönüştürülür. Bu geçersiz kılma, platformlar arası denetimi uygulayan yerel görünüm kullanılabilir ve başlatıldığında çağrılır. yöntemi tarafından ToPlatform döndürülen nesne, burada bir MauiVideoPlayer
olan tam yerel türüne yayınlanabilir.
Video oynatma
Video
sınıfı, video dosyasının kaynağını ve bir özelliği belirtmek için kullanılan bir AutoPlay
özelliği tanımlarSource
. AutoPlay
true
varsayılan olarak ayarlanır. Bu, videonun ayarlandıktan sonra Source
otomatik olarak oynatılması gerektiği anlamına gelir. Bu özelliklerin tanımı için bkz . Platformlar arası denetim oluşturma.
Source
özelliği türündedir VideoSource
ve öğesinden türetilen üç sınıfın örneğini oluşturan üç statik yöntemden VideoSource
oluşan soyut bir sınıftır:
using System.ComponentModel;
namespace VideoDemos.Controls
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
public static VideoSource FromUri(string uri)
{
return new UriVideoSource { Uri = uri };
}
public static VideoSource FromFile(string file)
{
return new FileVideoSource { File = file };
}
public static VideoSource FromResource(string path)
{
return new ResourceVideoSource { Path = path };
}
}
}
sınıfına VideoSource
başvuran VideoSourceConverter
bir TypeConverter
öznitelik içerir:
using System.ComponentModel;
namespace VideoDemos.Controls
{
public class VideoSourceConverter : TypeConverter, IExtendedTypeConverter
{
object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider)
{
if (!string.IsNullOrWhiteSpace(value))
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) && uri.Scheme != "file" ?
VideoSource.FromUri(value) : VideoSource.FromResource(value);
}
throw new InvalidOperationException("Cannot convert null or whitespace to VideoSource.");
}
}
}
Özelliği XAML'de bir dizeye ayarlandığında tür dönüştürücüsü çağrılır Source
. yöntemi, ConvertFromInvariantString
dizeyi bir Uri
nesneye dönüştürmeyi dener. Başarılı olursa ve düzen değilse file
yöntemi bir UriVideoSource
döndürür. Aksi takdirde bir ResourceVideoSource
döndürür.
Web videosu oynatma
UriVideoSource
sınıfı, URI ile uzak bir video belirtmek için kullanılır. türünde string
bir Uri
özellik tanımlar:
namespace VideoDemos.Controls
{
public class UriVideoSource : VideoSource
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(UriVideoSource));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
}
Source
özelliği olarak UriVideoSource
ayarlandığında işleyicinin özellik eşleyicisi yöntemin MapSource
çağrılmasını sağlar:
public static void MapSource(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdateSource();
}
MapSource
içindeki yöntemi, işleyicinin UpdateSource
PlatformView
özelliğinde yöntemini çağırır. PlatformView
türünde MauiVideoPlayer
olan özelliği, her platformda video oynatıcı uygulamasını sağlayan yerel görünümü temsil eder.
Android
Android'de bir VideoView
ile video oynatılır. Aşağıdaki kod örneği, türü UriVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
bool _isPrepared;
Video _video;
...
public void UpdateSource()
{
_isPrepared = false;
bool hasSetSource = false;
if (_video.Source is UriVideoSource)
{
string uri = (_video.Source as UriVideoSource).Uri;
if (!string.IsNullOrWhiteSpace(uri))
{
_videoView.SetVideoURI(Uri.Parse(uri));
hasSetSource = true;
}
}
...
if (hasSetSource && _video.AutoPlay)
{
_videoView.Start();
}
}
...
}
}
türündeki UriVideoSource
SetVideoUri
nesneler işlenirken, yöntemiVideoView
, dize URI'sinden oluşturulan bir Android Uri
nesnesiyle oynatılacak videoyu belirtmek için kullanılır.
özelliğinin AutoPlay
üzerinde VideoView
eşdeğeri yoktur, bu nedenle Start
yeni bir video ayarlandıysa yöntemi çağrılır.
iOS ve Mac Catalyst
iOS ve Mac Catalyst'te bir video oynatmak için, videoyu kapsüllemek için türünde AVAsset
bir nesne oluşturulur ve bu nesne, nesnesine devredilen bir AVPlayerItem
oluşturmak için AVPlayer
kullanılır. Aşağıdaki kod örneği, türü UriVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerItem _playerItem;
Video _video;
...
public void UpdateSource()
{
AVAsset asset = null;
if (_video.Source is UriVideoSource)
{
string uri = (_video.Source as UriVideoSource).Uri;
if (!string.IsNullOrWhiteSpace(uri))
asset = AVAsset.FromUrl(new NSUrl(uri));
}
...
if (asset != null)
_playerItem = new AVPlayerItem(asset);
else
_playerItem = null;
_player.ReplaceCurrentItemWithPlayerItem(_playerItem);
if (_playerItem != null && _video.AutoPlay)
{
_player.Play();
}
}
...
}
}
türündeki UriVideoSource
nesneler işlenirken, statik AVAsset.FromUrl
yöntem, dize URI'sinden oluşturulan bir iOS NSUrl
nesnesiyle oynatılacak videoyu belirtmek için kullanılır.
Özelliğin AutoPlay
iOS video sınıflarında eşdeğeri yoktur, bu nedenle özelliği nesnesinde AVPlayer
yöntemini çağırmak için yöntemin UpdateSource
Play
sonunda inceler.
iOS'ta bazı durumlarda, video kayıttan yürütme sayfası kaldırıldıktan sonra videolar oynatılır. Videoyu durdurmak için geçersiz ReplaceCurrentItemWithPlayerItem
kılmada Dispose
olarak ayarlanırnull
:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_player != null)
{
_player.ReplaceCurrentItemWithPlayerItem(null);
...
}
...
}
base.Dispose(disposing);
}
Windows
Windows'ta bir MediaPlayerElement
ile video oynatılır. Aşağıdaki kod örneği, türü UriVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
public async void UpdateSource()
{
bool hasSetSource = false;
if (_video.Source is UriVideoSource)
{
string uri = (_video.Source as UriVideoSource).Uri;
if (!string.IsNullOrWhiteSpace(uri))
{
_mediaPlayerElement.Source = MediaSource.CreateFromUri(new Uri(uri));
hasSetSource = true;
}
}
...
if (hasSetSource && !_isMediaPlayerAttached)
{
_isMediaPlayerAttached = true;
_mediaPlayerElement.MediaPlayer.MediaOpened += OnMediaPlayerMediaOpened;
}
if (hasSetSource && _video.AutoPlay)
{
_mediaPlayerElement.AutoPlay = true;
}
}
...
}
}
türündeki UriVideoSource
nesneler işlenirken özelliği, MediaPlayerElement.Source
oynatılacak videonun URI'siyle bir Uri
başlatan bir MediaSource
nesneye ayarlanır. MediaPlayerElement.Source
ayarlandığında, OnMediaPlayerMediaOpened
olay işleyicisi yöntemi olaya göre MediaPlayerElement.MediaPlayer.MediaOpened
kaydedilir. Bu olay işleyicisi denetimin Duration
özelliğini Video
ayarlamak için kullanılır.
yönteminin UpdateSource
sonunda özelliği Video.AutoPlay
incelenmiş ve doğruysa MediaPlayerElement.AutoPlay
özellik video kayıttan yürütmeyi başlatacak şekilde true
ayarlanmıştır.
Video kaynağı oynatma
sınıfı ResourceVideoSource
, uygulamaya eklenmiş video dosyalarına erişmek için kullanılır. türünde string
bir Path
özellik tanımlar:
namespace VideoDemos.Controls
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));
public string Path
{
get { return (string)GetValue(PathProperty); }
set { SetValue(PathProperty, value); }
}
}
}
Source
özelliği olarak ResourceVideoSource
ayarlandığında işleyicinin özellik eşleyicisi yöntemin MapSource
çağrılmasını sağlar:
public static void MapSource(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdateSource();
}
MapSource
içindeki yöntemi, işleyicinin UpdateSource
PlatformView
özelliğinde yöntemini çağırır. PlatformView
türünde MauiVideoPlayer
olan özelliği, her platformda video oynatıcı uygulamasını sağlayan yerel görünümü temsil eder.
Android
Aşağıdaki kod örneği, türü ResourceVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
bool _isPrepared;
Context _context;
Video _video;
...
public void UpdateSource()
{
_isPrepared = false;
bool hasSetSource = false;
...
else if (_video.Source is ResourceVideoSource)
{
string package = Context.PackageName;
string path = (_video.Source as ResourceVideoSource).Path;
if (!string.IsNullOrWhiteSpace(path))
{
string assetFilePath = "content://" + package + "/" + path;
_videoView.SetVideoPath(assetFilePath);
hasSetSource = true;
}
}
...
}
...
}
}
türündeki ResourceVideoSource
SetVideoPath
VideoView
nesneler işlenirken yöntemi, uygulamanın paket adını videonun dosya adıyla birleştiren bir dize bağımsız değişkeniyle birlikte oynatılacak videoyu belirtmek için kullanılır.
Kaynak video dosyası paketin varlıklar klasöründe depolanır ve buna erişmek için bir içerik sağlayıcısı gerekir. İçerik sağlayıcısı, video dosyasına erişim sağlayan bir AssetFileDescriptor
nesne oluşturan sınıfı tarafından VideoProvider
sağlanır:
using Android.Content;
using Android.Content.Res;
using Android.Database;
using Debug = System.Diagnostics.Debug;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
[ContentProvider(new string[] { "com.companyname.videodemos" })]
public class VideoProvider : ContentProvider
{
public override AssetFileDescriptor OpenAssetFile(Uri uri, string mode)
{
var assets = Context.Assets;
string fileName = uri.LastPathSegment;
if (fileName == null)
throw new FileNotFoundException();
AssetFileDescriptor afd = null;
try
{
afd = assets.OpenFd(fileName);
}
catch (IOException ex)
{
Debug.WriteLine(ex);
}
return afd;
}
public override bool OnCreate()
{
return false;
}
...
}
}
iOS ve Mac Catalyst
Aşağıdaki kod örneği, türü ResourceVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
Video _video;
...
public void UpdateSource()
{
AVAsset asset = null;
...
else if (_video.Source is ResourceVideoSource)
{
string path = (_video.Source as ResourceVideoSource).Path;
if (!string.IsNullOrWhiteSpace(path))
{
string directory = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path).Substring(1);
NSUrl url = NSBundle.MainBundle.GetUrlForResource(filename, extension, directory);
asset = AVAsset.FromUrl(url);
}
}
...
}
...
}
}
türündeki ResourceVideoSource
GetUrlForResource
nesneler işlenirken yöntemiNSBundle
, dosyayı uygulama paketinden almak için kullanılır. Tam yol bir dosya adı, uzantı ve dizine ayrılmalıdır.
iOS'ta bazı durumlarda, video kayıttan yürütme sayfası kaldırıldıktan sonra videolar oynatılır. Videoyu durdurmak için geçersiz ReplaceCurrentItemWithPlayerItem
kılmada Dispose
olarak ayarlanırnull
:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_player != null)
{
_player.ReplaceCurrentItemWithPlayerItem(null);
...
}
...
}
base.Dispose(disposing);
}
Windows
Aşağıdaki kod örneği, türü ResourceVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
...
public async void UpdateSource()
{
bool hasSetSource = false;
...
else if (_video.Source is ResourceVideoSource)
{
string path = "ms-appx:///" + (_video.Source as ResourceVideoSource).Path;
if (!string.IsNullOrWhiteSpace(path))
{
_mediaPlayerElement.Source = MediaSource.CreateFromUri(new Uri(path));
hasSetSource = true;
}
}
...
}
...
}
}
türündeki ResourceVideoSource
nesneler işlenirken özelliği, ön ekli MediaPlayerElement.Source
video kaynağının yolu ile başlatan ms-appx:///
bir MediaSource
Uri
nesneye ayarlanır.
Cihazın kitaplığından video dosyası yürütme
FileVideoSource
sınıfı, cihazın video kitaplığındaki videolara erişmek için kullanılır. türünde string
bir File
özellik tanımlar:
namespace VideoDemos.Controls
{
public class FileVideoSource : VideoSource
{
public static readonly BindableProperty FileProperty =
BindableProperty.Create(nameof(File), typeof(string), typeof(FileVideoSource));
public string File
{
get { return (string)GetValue(FileProperty); }
set { SetValue(FileProperty, value); }
}
}
}
Source
özelliği olarak FileVideoSource
ayarlandığında işleyicinin özellik eşleyicisi yöntemin MapSource
çağrılmasını sağlar:
public static void MapSource(VideoHandler handler, Video video)
{
handler?.PlatformView.UpdateSource();
}
MapSource
içindeki yöntemi, işleyicinin UpdateSource
PlatformView
özelliğinde yöntemini çağırır. PlatformView
türünde MauiVideoPlayer
olan özelliği, her platformda video oynatıcı uygulamasını sağlayan yerel görünümü temsil eder.
Android
Aşağıdaki kod örneği, türü FileVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
bool _isPrepared;
Video _video;
...
public void UpdateSource()
{
_isPrepared = false;
bool hasSetSource = false;
...
else if (_video.Source is FileVideoSource)
{
string filename = (_video.Source as FileVideoSource).File;
if (!string.IsNullOrWhiteSpace(filename))
{
_videoView.SetVideoPath(filename);
hasSetSource = true;
}
}
...
}
...
}
}
türündeki FileVideoSource
nesneler işlenirken, SetVideoPath
oynatılacak video dosyasını belirtmek için yöntemi VideoView
kullanılır.
iOS ve Mac Catalyst
Aşağıdaki kod örneği, türü FileVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
Video _video;
...
public void UpdateSource()
{
AVAsset asset = null;
...
else if (_video.Source is FileVideoSource)
{
string uri = (_video.Source as FileVideoSource).File;
if (!string.IsNullOrWhiteSpace(uri))
asset = AVAsset.FromUrl(NSUrl.CreateFileUrl(new [] { uri }));
}
...
}
...
}
}
türündeki FileVideoSource
nesneler işlenirken, statik AVAsset.FromUrl
yöntem, dize URI'sinden bir iOS NSUrl
nesnesi oluşturma yöntemiyle NSUrl.CreateFileUrl
birlikte oynatılacak video dosyasını belirtmek için kullanılır.
Windows
Aşağıdaki kod örneği, türü FileVideoSource
olduğunda yönteminin Source
özelliğini nasıl UpdateSource
işlediğini gösterir:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
...
public async void UpdateSource()
{
bool hasSetSource = false;
...
else if (_video.Source is FileVideoSource)
{
string filename = (_video.Source as FileVideoSource).File;
if (!string.IsNullOrWhiteSpace(filename))
{
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
_mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(storageFile);
hasSetSource = true;
}
}
...
}
...
}
}
türünde FileVideoSource
nesneler işlenirken, video dosya adı bir StorageFile
nesneye dönüştürülür. Ardından yöntemi, MediaSource.CreateFromStorageFile
özelliğin değeri MediaPlayerElement.Source
olarak ayarlanmış bir MediaSource
nesne döndürür.
Video döngüleri oluşturma
Video
sınıfı, denetimin sonuna ulaştıktan sonra video konumunu otomatik olarak başlangıç konumuna ayarlamasını sağlayan bir IsLooping
özellik tanımlar. Varsayılan olarak olur ve videoların false
otomatik olarak döngüye alındığını gösterir.
IsLooping
Özellik ayarlandığında, işleyicinin özellik eşleyicisi yöntemin MapIsLooping
çağrılmasını sağlar:
public static void MapIsLooping(VideoHandler handler, Video video)
{
handler.PlatformView?.UpdateIsLooping();
}
yöntemi MapIsLooping
de işleyicinin UpdateIsLooping
PlatformView
özelliğinde yöntemini çağırır. PlatformView
türünde MauiVideoPlayer
olan özelliği, her platformda video oynatıcı uygulamasını sağlayan yerel görünümü temsil eder.
Android
Aşağıdaki kod örneği, Android'de yönteminin UpdateIsLooping
video döngüsüne nasıl olanak sağladığını gösterir:
using Android.Content;
using Android.Media;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout, MediaPlayer.IOnPreparedListener
{
VideoView _videoView;
Video _video;
...
public void UpdateIsLooping()
{
if (_video.IsLooping)
{
_videoView.SetOnPreparedListener(this);
}
else
{
_videoView.SetOnPreparedListener(null);
}
}
public void OnPrepared(MediaPlayer mp)
{
mp.Looping = _video.IsLooping;
}
...
}
}
Video döngüsünü MauiVideoPlayer
etkinleştirmek için sınıfı arabirimini MediaPlayer.IOnPreparedListener
uygular. Bu arabirim, medya kaynağı kayıttan yürütme için hazır olduğunda çağrılan bir OnPrepared
geri çağırma tanımlar. Video.IsLooping
özelliği olduğunda true
UpdateIsLooping
yöntemi, geri çağırmayı sağlayan OnPrepared
nesne olarak ayarlarMauiVideoPlayer
. Geri çağırma özelliği özelliğinin Video.IsLooping
değerine ayarlarMediaPlayer.IsLooping
.
iOS ve Mac Catalyst
Aşağıdaki kod örneği, iOS ve Mac Catalyst'te yönteminin UpdateIsLooping
video döngüye nasıl olanak sağladığını gösterir:
using System.Diagnostics;
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerViewController _playerViewController;
Video _video;
NSObject? _playedToEndObserver;
...
public void UpdateIsLooping()
{
DestroyPlayedToEndObserver();
if (_video.IsLooping)
{
_player.ActionAtItemEnd = AVPlayerActionAtItemEnd.None;
_playedToEndObserver = NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, PlayedToEnd);
}
else
_player.ActionAtItemEnd = AVPlayerActionAtItemEnd.Pause;
}
void PlayedToEnd(NSNotification notification)
{
if (_video == null || notification.Object != _playerViewController.Player?.CurrentItem)
return;
_playerViewController.Player?.Seek(CMTime.Zero);
}
...
}
}
iOS ve Mac Catalyst'te, video sonuna kadar oynatıldığında geri çağırma yürütmek için bir bildirim kullanılır. Video.IsLooping
özelliği olduğunda true
UpdateIsLooping
yöntemi bildirim için AVPlayerItem.DidPlayToEndTimeNotification
bir gözlemci ekler ve bildirim alındığında yöntemini yürütürPlayedToEnd
. Buna karşılık, bu yöntem videonun başından itibaren kayıttan yürütmeyi sürdürür. Video.IsLooping
özelliği isefalse
, video kayıttan yürütmenin sonunda duraklatılır.
Bildirim MauiVideoPlayer
için bir gözlemci eklendiğinden, yerel görünüm temizlemesi gerçekleştirirken gözlemciyi de kaldırması gerekir. Bu, geçersiz kılmada Dispose
gerçekleştirilir:
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerViewController _playerViewController;
Video _video;
NSObject? _playedToEndObserver;
...
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_player != null)
{
DestroyPlayedToEndObserver();
...
}
...
}
base.Dispose(disposing);
}
void DestroyPlayedToEndObserver()
{
if (_playedToEndObserver != null)
{
NSNotificationCenter.DefaultCenter.RemoveObserver(_playedToEndObserver);
DisposeObserver(ref _playedToEndObserver);
}
}
void DisposeObserver(ref NSObject? disposable)
{
disposable?.Dispose();
disposable = null;
}
...
}
Geçersiz Dispose
kılma, bildirim için AVPlayerItem.DidPlayToEndTimeNotification
gözlemciyi kaldıran ve üzerinde yöntemini de çağıran yöntemini NSObject
çağırır DestroyPlayedToEndObserver
Dispose
.
Windows
Aşağıdaki kod örneği, Windows'taki yönteminin UpdateIsLooping
video döngüye nasıl olanak sağladığını gösterir:
public void UpdateIsLooping()
{
if (_isMediaPlayerAttached)
_mediaPlayerElement.MediaPlayer.IsLoopingEnabled = _video.IsLooping;
}
Yöntemi, UpdateIsLooping
video döngüsünü etkinleştirmek için özelliğini özelliğinin Video.IsLooping
değerine ayarlarMediaPlayerElement.MediaPlayer.IsLoopingEnabled
.
Özel aktarım denetimleri oluşturma
Video oynatıcının aktarım denetimleri, videoyu yürüten, duraklatan ve durduran düğmeler içerir. Bu düğmeler genellikle metin yerine tanıdık simgelerle tanımlanır ve yürütme ve duraklat düğmeleri genellikle tek bir düğmede birleştirilir.
Varsayılan olarak, Video
denetim her platform tarafından desteklenen aktarım denetimlerini görüntüler. Ancak özelliğini false
olarak ayarladığınızda AreTransportControlsEnabled
bu denetimler gizleniyor. Daha sonra video kayıttan yürütmeyi program aracılığıyla denetleyebilir veya kendi aktarım denetimlerinizi sağlayabilirsiniz.
Kendi aktarım denetimlerinizi uygulamak için sınıfın videoyu Video
oynatmak, duraklatmak veya durdurmak için yerel görünümlerini bilgilendirebilmesi ve video kayıttan yürütmenin geçerli durumunu bilebilmesi gerekir. Video
sınıfı, Pause
karşılık gelen bir olayı tetikleyen , ve Stop
adlı Play
yöntemleri tanımlar ve öğesine VideoHandler
bir komut gönderir:
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
public event EventHandler<VideoPositionEventArgs> PlayRequested;
public event EventHandler<VideoPositionEventArgs> PauseRequested;
public event EventHandler<VideoPositionEventArgs> StopRequested;
public void Play()
{
VideoPositionEventArgs args = new VideoPositionEventArgs(Position);
PlayRequested?.Invoke(this, args);
Handler?.Invoke(nameof(Video.PlayRequested), args);
}
public void Pause()
{
VideoPositionEventArgs args = new VideoPositionEventArgs(Position);
PauseRequested?.Invoke(this, args);
Handler?.Invoke(nameof(Video.PauseRequested), args);
}
public void Stop()
{
VideoPositionEventArgs args = new VideoPositionEventArgs(Position);
StopRequested?.Invoke(this, args);
Handler?.Invoke(nameof(Video.StopRequested), args);
}
}
}
sınıfı, VideoPositionEventArgs
oluşturucu aracılığıyla ayarlanabilen bir Position
özellik tanımlar. Bu özellik, video kayıttan yürütmenin başlatıldığı, duraklatıldığı veya durdurulduğu konumu temsil eder.
, ve yöntemlerindeki Play
son satır komutu ve ilişkili verileri adresine VideoHandler
gönderir.Stop
Pause
CommandMapper for VideoHandler
komutu, komut adlarını bir komut alındığında yürütülen Eylemlerle eşler. Örneğin, komutunu aldığında VideoHandler
PlayRequested
yöntemini yürütür MapPlayRequested
. Bu yaklaşımın avantajı, yerel görünümlerin platformlar arası denetim olaylarına abone olma ve abonelikten çıkma gereksinimini ortadan kaldırmasıdır. Ayrıca, komut eşleyicisi alt sınıflama olmadan platformlar arası denetim tüketicileri tarafından değiştirilebildiği için kolay özelleştirmeye olanak tanır. hakkında CommandMapperdaha fazla bilgi için bkz . Komut eşleyicisini oluşturma.
MauiVideoPlayer
Android, iOS ve Mac Catalyst'teki uygulama, , PauseRequested
ve StopRequested
komutlarını gönderen PlayRequested
denetime Video
yanıt olarak yürütülen , PauseRequested
ve StopRequested
yöntemlerine sahiptirPlayRequested
. Her yöntem, videoyu oynatmak, duraklatmak veya durdurmak için yerel görünümünde bir yöntem çağırır. Örneğin, aşağıdaki kod iOS ve StopRequested
Mac Catalyst'te , PauseRequested
ve yöntemlerini gösterirPlayRequested
:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
...
public void PlayRequested(TimeSpan position)
{
_player.Play();
Debug.WriteLine($"Video playback from {position.Hours:X2}:{position.Minutes:X2}:{position.Seconds:X2}.");
}
public void PauseRequested(TimeSpan position)
{
_player.Pause();
Debug.WriteLine($"Video paused at {position.Hours:X2}:{position.Minutes:X2}:{position.Seconds:X2}.");
}
public void StopRequested(TimeSpan position)
{
_player.Pause();
_player.Seek(new CMTime(0, 1));
Debug.WriteLine($"Video stopped at {position.Hours:X2}:{position.Minutes:X2}:{position.Seconds:X2}.");
}
}
}
Üç yöntemin her biri, komutuyla gönderilen verileri kullanarak videonun oynatıldığı, duraklatıldığı veya durdurulduğu konumu günlüğe kaydeder.
Bu mekanizma, denetimde Video
, Pause
veya Stop
yöntemi çağrıldığındaPlay
, yerel görünümünün videoyu oynatması, duraklatması veya durdurması ve videonun oynatıldığı, duraklatıldığı veya durdurulduğu konumu günlüğe kaydetmesi talimatını sağlar. Tüm bunlar, yerel görünümlerin platformlar arası olaylara abone olması gerekmeden ayrılmış bir yaklaşım kullanılarak gerçekleşir.
Video durumu
Yürütme, duraklatma ve durdurma işlevlerinin uygulanması, özel aktarım denetimlerini desteklemek için yeterli değildir. Oynatma ve duraklatma işlevi genellikle videonun oynatıldığını veya duraklatıldığını göstermek için görünümünü değiştiren aynı düğmeyle uygulanmalıdır. Ayrıca, video henüz yüklenmemişse düğmenin etkinleştirilmemesi gerekir.
Bu gereksinimler, video oynatıcının oynatıldığını veya duraklatıldığını ya da henüz video oynatmaya hazır olmadığını belirten geçerli bir durumu kullanıma sunması gerektiği anlamına geliyor. Bu durum bir sabit listesiyle gösterilebilir:
public enum VideoStatus
{
NotReady,
Playing,
Paused
}
Video
sınıfı, türünde VideoStatus
adlı Status
salt okunur bağlanabilir bir özellik tanımlar. Yalnızca denetimin işleyicisinden ayarlanması gerektiğinden bu özellik salt okunur olarak tanımlanır:
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
private static readonly BindablePropertyKey StatusPropertyKey =
BindableProperty.CreateReadOnly(nameof(Status), typeof(VideoStatus), typeof(Video), VideoStatus.NotReady);
public static readonly BindableProperty StatusProperty = StatusPropertyKey.BindableProperty;
public VideoStatus Status
{
get { return (VideoStatus)GetValue(StatusProperty); }
}
VideoStatus IVideoController.Status
{
get { return Status; }
set { SetValue(StatusPropertyKey, value); }
}
...
}
}
Genellikle, salt okunur bir bağlanabilir özelliğin sınıfı içinden ayarlanmasına izin vermek için özelliğinde Status
özel set
bir erişimci olur. Ancak, işleyiciler tarafından desteklenen bir View türev için özelliği sınıfın dışından ayarlanmalıdır, ancak yalnızca denetimin işleyicisi tarafından ayarlanmalıdır.
Bu nedenle, adıyla IVideoController.Status
başka bir özellik tanımlanır. Bu açık bir arabirim uygulamasıdır ve sınıfın IVideoController
uyguladığı arabirim Video
tarafından mümkün hale getirilir:
public interface IVideoController
{
VideoStatus Status { get; set; }
TimeSpan Duration { get; set; }
}
Bu arabirim, bir sınıfın arabirimine Video
başvurarak özelliğini ayarlamasını Status
IVideoController
mümkün kılar. özelliği diğer sınıflardan ve işleyiciden ayarlanabilir, ancak yanlışlıkla ayarlanması pek olası değildir. En önemlisi, Status
özelliği bir veri bağlama aracılığıyla ayarlanamaz.
İşleyici uygulamalarının özelliği güncel Video
tutmasına Status
yardımcı olmak için sınıfı bir UpdateStatus
olay ve komut tanımlar:
using System.ComponentModel;
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
public event EventHandler UpdateStatus;
IDispatcherTimer _timer;
public Video()
{
_timer = Dispatcher.CreateTimer();
_timer.Interval = TimeSpan.FromMilliseconds(100);
_timer.Tick += OnTimerTick;
_timer.Start();
}
~Video() => _timer.Tick -= OnTimerTick;
void OnTimerTick(object sender, EventArgs e)
{
UpdateStatus?.Invoke(this, EventArgs.Empty);
Handler?.Invoke(nameof(Video.UpdateStatus));
}
...
}
}
Olay OnTimerTick
işleyicisi saniyenin onda birinde yürütülür ve bu da olayı tetikler UpdateStatus
ve komutunu çağırır UpdateStatus
.
UpdateStatus
Komut denetimden Video
işleyicisine gönderildiğinde, işleyicinin komut eşleyicisi yöntemin MapUpdateStatus
çağrılmasını sağlar:
public static void MapUpdateStatus(VideoHandler handler, Video video, object? args)
{
handler.PlatformView?.UpdateStatus();
}
MapUpdateStatus
içindeki yöntemi, işleyicinin UpdateStatus
PlatformView
özelliğinde yöntemini çağırır. PlatformView
türünde MauiVideoPlayer
olan özelliği, her platformda video oynatıcı uygulamasını sağlayan yerel görünümleri kapsüller.
Android
Aşağıdaki kod örneği, Android'de yönteminin UpdateStatus
özelliğini ayarlamasını Status
gösterir:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
bool _isPrepared;
Video _video;
...
public MauiVideoPlayer(Context context, Video video) : base(context)
{
_video = video;
...
_videoView.Prepared += OnVideoViewPrepared;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_videoView.Prepared -= OnVideoViewPrepared;
...
}
base.Dispose(disposing);
}
void OnVideoViewPrepared(object sender, EventArgs args)
{
_isPrepared = true;
((IVideoController)_video).Duration = TimeSpan.FromMilliseconds(_videoView.Duration);
}
public void UpdateStatus()
{
VideoStatus status = VideoStatus.NotReady;
if (_isPrepared)
status = _videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
((IVideoController)_video).Status = status;
...
}
...
}
}
VideoView.IsPlaying
özelliği, videonun oynatıldığını veya duraklatıldığını gösteren bir Boole değeridir. videonun VideoView
oynatılmadığını veya duraklatılmadığını belirlemek için olayın Prepared
işlenmesi gerekir. Medya kaynağı kayıttan yürütme için hazır olduğunda bu olay tetikleniyor. Olay oluşturucuda MauiVideoPlayer
abone yapılır ve geçersiz kılmada Dispose
aboneliği kaldırılır. UpdateStatus
Yöntemi daha sonra nesnesini değerine dönüştürerek IVideoController
özelliğini ayarlamak Status
için alanını ve VideoView.IsPlaying
özelliğini Video
kullanırisPrepared
.
iOS ve Mac Catalyst
Aşağıdaki kod örneği, iOS ve Mac Catalyst'te özelliğini ayarlarken Status
yöntemini gösterirUpdateStatus
:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
Video _video;
...
public void UpdateStatus()
{
VideoStatus videoStatus = VideoStatus.NotReady;
switch (_player.Status)
{
case AVPlayerStatus.ReadyToPlay:
switch (_player.TimeControlStatus)
{
case AVPlayerTimeControlStatus.Playing:
videoStatus = VideoStatus.Playing;
break;
case AVPlayerTimeControlStatus.Paused:
videoStatus = VideoStatus.Paused;
break;
}
break;
}
((IVideoController)_video).Status = videoStatus;
...
}
...
}
}
özelliğini ayarlamak Status
için iki özelliğine AVPlayer
erişilmelidir: Status
türün AVPlayerStatus
özelliği ve TimeControlStatus
türünün AVPlayerTimeControlStatus
özelliği. Daha Status
sonra özelliği nesnesine Video
yayınlanarak IVideoController
nesne üzerinde ayarlanabilir.
Windows
Aşağıdaki kod örneği, Windows'da özelliğini ayarlarken Status
yöntemini gösterirUpdateStatus
:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
public void UpdateStatus()
{
if (_isMediaPlayerAttached)
{
VideoStatus status = VideoStatus.NotReady;
switch (_mediaPlayerElement.MediaPlayer.CurrentState)
{
case MediaPlayerState.Playing:
status = VideoStatus.Playing;
break;
case MediaPlayerState.Paused:
case MediaPlayerState.Stopped:
status = VideoStatus.Paused;
break;
}
((IVideoController)_video).Status = status;
_video.Position = _mediaPlayerElement.MediaPlayer.Position;
}
}
...
}
}
yöntemi, UpdateStatus
özelliğin MediaPlayerElement.MediaPlayer.CurrentState
değerini belirlemek için özelliğinin Status
değerini kullanır. Daha Status
sonra özelliği nesnesine Video
yayınlanarak IVideoController
nesne üzerinde ayarlanabilir.
Konumlandırma çubuğu
Her platform tarafından uygulanan taşıma denetimleri bir konumlandırma çubuğu içerir. Bu çubuk kaydırıcı veya kaydırma çubuğuna benzer ve videonun toplam süresi içindeki geçerli konumunu gösterir. Kullanıcılar, videoda yeni bir konuma ileri veya geri gitmek için konumlandırma çubuğunu değiştirebilir.
Kendi konumlandırma çubuğunuzu uygulamak için sınıfın Video
videonun süresini ve bu süre içindeki geçerli konumunu bilmesi gerekir.
Süre
Denetimin özel bir konumlandırma çubuğunu desteklemesi Video
için gereken bilgilerden biri videonun süresidir. Video
sınıfı, türünde TimeSpan
adlı Duration
salt okunur bir bağlanabilir özellik tanımlar. Yalnızca denetimin işleyicisinden ayarlanması gerektiğinden bu özellik salt okunur olarak tanımlanır:
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
private static readonly BindablePropertyKey DurationPropertyKey =
BindableProperty.CreateReadOnly(nameof(Duration), typeof(TimeSpan), typeof(Video), new TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((Video)bindable).SetTimeToEnd());
public static readonly BindableProperty DurationProperty = DurationPropertyKey.BindableProperty;
public TimeSpan Duration
{
get { return (TimeSpan)GetValue(DurationProperty); }
}
TimeSpan IVideoController.Duration
{
get { return Duration; }
set { SetValue(DurationPropertyKey, value); }
}
...
}
}
Genellikle, salt okunur bir bağlanabilir özelliğin sınıfı içinden ayarlanmasına izin vermek için özelliğinde Duration
özel set
bir erişimci olur. Ancak, işleyiciler tarafından desteklenen bir View türev için özelliği sınıfın dışından ayarlanmalıdır, ancak yalnızca denetimin işleyicisi tarafından ayarlanmalıdır.
Not
Bağlanabilir özelliğin Duration
özellik tarafından değiştirilen olay işleyicisi, Bitiş saatini hesaplama bölümünde açıklanan adlı SetTimeToEnd
bir yöntemi çağırır.
Bu nedenle, adıyla IVideoController.Duration
başka bir özellik tanımlanır. Bu açık bir arabirim uygulamasıdır ve sınıfın IVideoController
uyguladığı arabirim Video
tarafından mümkün hale getirilir:
public interface IVideoController
{
VideoStatus Status { get; set; }
TimeSpan Duration { get; set; }
}
Bu arabirim, bir sınıfın arabirimine Video
başvurarak özelliğini ayarlamasını Duration
IVideoController
mümkün kılar. özelliği diğer sınıflardan ve işleyiciden ayarlanabilir, ancak yanlışlıkla ayarlanması pek olası değildir. En önemlisi, Duration
özelliği bir veri bağlama aracılığıyla ayarlanamaz.
Denetimin özelliği ayarlandıktan hemen sonra Source
videonun Video
süresi kullanılamaz. Yerel görünümün süresini belirleyebilmesi için önce videonun kısmen indirilmesi gerekir.
Android
Android'de VideoView.Duration
özellik, etkinlik oluşturulduktan sonra VideoView.Prepared
milisaniye cinsinden geçerli bir süre bildirir. sınıfı, MauiVideoPlayer
özellik değerini almak için olay işleyicisini Duration
kullanırPrepared
:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
Video _video;
...
void OnVideoViewPrepared(object sender, EventArgs args)
{
...
((IVideoController)_video).Duration = TimeSpan.FromMilliseconds(_videoView.Duration);
}
...
}
}
iOS ve Mac Catalyst
iOS ve Mac Catalyst'te, videonun süresi özelliğinden AVPlayerItem.Duration
alınır, ancak oluşturulduktan hemen sonra AVPlayerItem
alınmaz. Özelliği için bir iOS gözlemcisi Duration
ayarlamak mümkündür, ancak MauiVideoPlayer
sınıfı saniyede 10 kez çağrılan yöntemde UpdateStatus
süreyi alır:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayerItem _playerItem;
...
TimeSpan ConvertTime(CMTime cmTime)
{
return TimeSpan.FromSeconds(Double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);
}
public void UpdateStatus()
{
...
if (_playerItem != null)
{
((IVideoController)_video).Duration = ConvertTime(_playerItem.Duration);
...
}
}
...
}
}
yöntemi bir ConvertTime
CMTime
nesneyi bir TimeSpan
değere dönüştürür.
Windows
Windows'da özelliği, MediaPlayerElement.MediaPlayer.NaturalDuration
olay tetiklendiğinde MediaPlayerElement.MediaPlayer.MediaOpened
geçerli hale gelen bir TimeSpan
değerdir. sınıfı, MauiVideoPlayer
özellik değerini almak için olay işleyicisini NaturalDuration
kullanırMediaOpened
:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
void OnMediaPlayerMediaOpened(MediaPlayer sender, object args)
{
MainThread.BeginInvokeOnMainThread(() =>
{
((IVideoController)_video).Duration = _mediaPlayerElement.MediaPlayer.NaturalDuration;
});
}
...
}
}
Daha OnMediaPlayer
sonra olay işleyicisi, ana iş parçacığında Video
öğesine dönüştürerek nesnesinin özelliğini ayarlamak Duration
için IVideoController
yöntemini çağırırMainThread.BeginInvokeOnMainThread
. Olay bir arka plan iş parçacığında işlendiğinden MediaPlayerElement.MediaPlayer.MediaOpened
bu gereklidir. Kodu ana iş parçacığında çalıştırma hakkında daha fazla bilgi için bkz . .NET MAUI kullanıcı arabirimi iş parçacığında iş parçacığı oluşturma.
Position
Denetim ayrıca Video
video oynattıkça sıfırdan bir Duration
özelliğe de ihtiyaç duyarPosition
. sınıfı bu Video
özelliği public get
ve set
accessors ile bağlanabilir bir özellik olarak uygular:
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(Video), new TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((Video)bindable).SetTimeToEnd());
public TimeSpan Position
{
get { return (TimeSpan)GetValue(PositionProperty); }
set { SetValue(PositionProperty, value); }
}
...
}
}
Erişimci get
videonun geçerli konumunu oynatırken döndürür. Erişimci, set
video konumunu ileri veya geri hareket ettirerek konumlandırma çubuğunun kullanıcı düzenlemesine yanıt verir.
Not
Bağlanabilir özelliğin Position
özellik tarafından değiştirilen olay işleyicisi, Bitiş saatini hesaplama bölümünde açıklanan adlı SetTimeToEnd
bir yöntemi çağırır.
Android, iOS ve Mac Catalyst'te, geçerli konumu alan özelliğin yalnızca bir get
aksesuarı vardır. Bunun yerine, konumu ayarlamak için bir Seek
yöntem kullanılabilir. Bu, doğal bir sorunu olan tek Position
bir özelliği kullanmaktan daha mantıklı bir yaklaşım gibi görünüyor. Video oynattıkça özelliğin Position
yeni konumu yansıtacak şekilde sürekli güncelleştirilmiş olması gerekir. Ancak özellikteki çoğu değişikliğin video oynatıcının Position
videoda yeni bir konuma geçmesine neden olmasını istemezsiniz. Böyle bir durumda video oynatıcı özelliğin son değerini Position
arayarak yanıt verir ve video ilerlemez.
ve set
erişimcileriyle get
özellik Position
uygulama güçlüklerine rağmen, veri bağlamayı kullanabildiği için bu yaklaşım kullanılır. Denetimin Position
Video
özelliği, hem konumu görüntülemek hem de yeni bir Slider konum aramak için kullanılan bir öğesine bağlanabilir. Ancak, geri bildirim döngülerini önlemek için özelliği uygularken Position
çeşitli önlemler gereklidir.
Android
Android'de VideoView.CurrentPosition
özelliği videonun geçerli konumunu gösterir. MauiVideoPlayer
sınıfı, yönteminin Position
özelliğini UpdateStatus
ayarlarken özelliğini ayarlarDuration
:
using Android.Content;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
using VideoDemos.Controls;
using Color = Android.Graphics.Color;
using Uri = Android.Net.Uri;
namespace VideoDemos.Platforms.Android
{
public class MauiVideoPlayer : CoordinatorLayout
{
VideoView _videoView;
Video _video;
...
public void UpdateStatus()
{
...
TimeSpan timeSpan = TimeSpan.FromMilliseconds(_videoView.CurrentPosition);
_video.Position = timeSpan;
}
public void UpdatePosition()
{
if (Math.Abs(_videoView.CurrentPosition - _video.Position.TotalMilliseconds) > 1000)
{
_videoView.SeekTo((int)_video.Position.TotalMilliseconds);
}
}
...
}
}
Position
özelliği yöntemi tarafından UpdateStatus
her ayarlandığında, Position
özelliği bir PropertyChanged
olay tetikler ve bu da işleyici için özellik eşleyicisinin yöntemini çağırmasına UpdatePosition
neden olur. yöntemi, UpdatePosition
özellik değişikliklerinin çoğu için hiçbir şey yapmamalıdır. Aksi takdirde, videonun konumundaki her değişiklikle aynı konuma taşınırdı. Bu geri bildirim döngüsünü önlemek için, UpdatePosition
özelliği ile geçerli konumu VideoView
arasındaki Position
fark bir saniyeden büyük olduğunda yalnızca nesnede yöntemini VideoView
çağırırSeek
.
iOS ve Mac Catalyst
iOS ve Mac Catalyst'te özelliği videonun AVPlayerItem.CurrentTime
geçerli konumunu gösterir. MauiVideoPlayer
sınıfı, yönteminin Position
özelliğini UpdateStatus
ayarlarken özelliğini ayarlarDuration
:
using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using System.Diagnostics;
using UIKit;
using VideoDemos.Controls;
namespace VideoDemos.Platforms.MaciOS
{
public class MauiVideoPlayer : UIView
{
AVPlayer _player;
AVPlayerItem _playerItem;
Video _video;
...
TimeSpan ConvertTime(CMTime cmTime)
{
return TimeSpan.FromSeconds(Double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);
}
public void UpdateStatus()
{
...
if (_playerItem != null)
{
...
_video.Position = ConvertTime(_playerItem.CurrentTime);
}
}
public void UpdatePosition()
{
TimeSpan controlPosition = ConvertTime(_player.CurrentTime);
if (Math.Abs((controlPosition - _video.Position).TotalSeconds) > 1)
{
_player.Seek(CMTime.FromSeconds(_video.Position.TotalSeconds, 1));
}
}
...
}
}
Position
özelliği yöntemi tarafından UpdateStatus
her ayarlandığında, Position
özelliği bir PropertyChanged
olay tetikler ve bu da işleyici için özellik eşleyicisinin yöntemini çağırmasına UpdatePosition
neden olur. yöntemi, UpdatePosition
özellik değişikliklerinin çoğu için hiçbir şey yapmamalıdır. Aksi takdirde, videonun konumundaki her değişiklikle aynı konuma taşınırdı. Bu geri bildirim döngüsünü önlemek için, UpdatePosition
özelliği ile geçerli konumu AVPlayer
arasındaki Position
fark bir saniyeden büyük olduğunda yalnızca nesnede yöntemini AVPlayer
çağırırSeek
.
Windows
Windows'da özelliği videonun MediaPlayerElement.MedaPlayer.Position
geçerli konumunu gösterir. MauiVideoPlayer
sınıfı, yönteminin Position
özelliğini UpdateStatus
ayarlarken özelliğini ayarlarDuration
:
using Microsoft.UI.Xaml.Controls;
using VideoDemos.Controls;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Grid = Microsoft.UI.Xaml.Controls.Grid;
namespace VideoDemos.Platforms.Windows
{
public class MauiVideoPlayer : Grid, IDisposable
{
MediaPlayerElement _mediaPlayerElement;
Video _video;
bool _isMediaPlayerAttached;
...
public void UpdateStatus()
{
if (_isMediaPlayerAttached)
{
...
_video.Position = _mediaPlayerElement.MediaPlayer.Position;
}
}
public void UpdatePosition()
{
if (_isMediaPlayerAttached)
{
if (Math.Abs((_mediaPlayerElement.MediaPlayer.Position - _video.Position).TotalSeconds) > 1)
{
_mediaPlayerElement.MediaPlayer.Position = _video.Position;
}
}
}
...
}
}
Position
özelliği yöntemi tarafından UpdateStatus
her ayarlandığında, Position
özelliği bir PropertyChanged
olay tetikler ve bu da işleyici için özellik eşleyicisinin yöntemini çağırmasına UpdatePosition
neden olur. yöntemi, UpdatePosition
özellik değişikliklerinin çoğu için hiçbir şey yapmamalıdır. Aksi takdirde, videonun konumundaki her değişiklikle aynı konuma taşınırdı. Bu geri bildirim döngüsünü önlemek için özelliği UpdatePosition
ile geçerli konumu arasındaki fark bir saniyeden Position
MediaPlayerElement
büyük olduğunda yalnızca özelliği ayarlarMediaPlayerElement.MediaPlayer.Position
.
Bitiş süresini hesaplama
Bazen video oynatıcılar videoda kalan süreyi gösterir. Bu değer, video başladığında videonun süresiyle başlar ve video sona erdiğinde sıfıra düşer.
sınıfı, Video
ve Position
özelliklerindeki değişikliklere Duration
göre hesaplanan salt okunur TimeToEnd
bir özellik içerir:
namespace VideoDemos.Controls
{
public class Video : View, IVideoController
{
...
private static readonly BindablePropertyKey TimeToEndPropertyKey =
BindableProperty.CreateReadOnly(nameof(TimeToEnd), typeof(TimeSpan), typeof(Video), new TimeSpan());
public static readonly BindableProperty TimeToEndProperty = TimeToEndPropertyKey.BindableProperty;
public TimeSpan TimeToEnd
{
get { return (TimeSpan)GetValue(TimeToEndProperty); }
private set { SetValue(TimeToEndPropertyKey, value); }
}
void SetTimeToEnd()
{
TimeToEnd = Duration - Position;
}
...
}
}
SetTimeToEnd
yöntemi ve Position
özelliklerinin özellik tarafından değiştirilen olay işleyicilerinden çağrılırDuration
.
Özel konumlandırma çubuğu
özel konumlandırma çubuğu, türünde TimeSpan
ve Position
özelliklerini içeren Duration
öğesinden Slidertüretilen bir sınıf oluşturularak uygulanabilir:
namespace VideoDemos.Controls
{
public class PositionSlider : Slider
{
public static readonly BindableProperty DurationProperty =
BindableProperty.Create(nameof(Duration), typeof(TimeSpan), typeof(PositionSlider), new TimeSpan(1),
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((Slider)bindable).Maximum = seconds <= 0 ? 1 : seconds;
});
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(PositionSlider), new TimeSpan(0),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((Slider)bindable).Value = seconds;
});
public TimeSpan Duration
{
get { return (TimeSpan)GetValue(DurationProperty); }
set { SetValue(DurationProperty, value); }
}
public TimeSpan Position
{
get { return (TimeSpan)GetValue(PositionProperty); }
set { SetValue (PositionProperty, value); }
}
public PositionSlider()
{
PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Value")
{
TimeSpan newPosition = TimeSpan.FromSeconds(Value);
if (Math.Abs(newPosition.TotalSeconds - Position.TotalSeconds) / Duration.TotalSeconds > 0.01)
Position = newPosition;
}
};
}
}
}
özelliği için Duration
özellik tarafından değiştirilen olay işleyicisi Slider özelliğini değerinin TotalSeconds
özelliğine TimeSpan
ayarlarMaximum
. Benzer şekilde, özelliği için Position
özellik tarafından değiştirilen olay işleyicisi Sliderözelliğini ayarlarValue
. Bu, konumunun izlendiği Slider mekanizmadır PositionSlider
.
PositionSlider
, yalnızca bir senaryoda temel alınandan Slider güncelleştirilir. Bu, kullanıcının videonun gelişmiş veya yeni bir konuma ters çevrilmesi gerektiğini belirtmek için öğesini işlemesidirSlider. Bu, oluşturucudaki PropertyChanged
işleyicide PositionSlider
algılanır. Bu olay işleyici özelliğinde Value
bir değişiklik olup olmadığını denetler ve özelliğinden Position
farklıysa özelliği Position
özelliğinden Value
ayarlanır.
İşleyiciyi kaydetme
Bir özel denetimin ve işleyicinin, bir uygulamanın tüketilmesi için önce bir uygulamaya kaydedilmesi gerekir. Bu, uygulamanın platformlar arası giriş noktası olan uygulama projenizdeki sınıfındaki yönteminde MauiProgram
gerçekleşmelidirCreateMauiApp
:
using VideoDemos.Controls;
using VideoDemos.Handlers;
namespace VideoDemos;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Video), typeof(VideoHandler));
});
return builder.Build();
}
}
İşleyici ve AddHandler yöntemiyle ConfigureMauiHandlers kaydedilir. Yöntemin AddHandler ilk bağımsız değişkeni platformlar arası denetim türüdür ve ikinci bağımsız değişken de işleyici türüdür.
Platformlar arası denetimi kullanma
İşleyiciyi uygulamanıza kaydettikten sonra platformlar arası denetim kullanılabilir.
Web videosu oynatma
Denetim Video
, aşağıdaki örnekte gösterildiği gibi BIR URL'den video oynatabilir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:VideoDemos.Controls"
x:Class="VideoDemos.Views.PlayWebVideoPage"
Unloaded="OnContentPageUnloaded"
Title="Play web video">
<controls:Video x:Name="video"
Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />
</ContentPage>
Bu örnekte sınıfı, VideoSourceConverter
URI'yi temsil eden dizeyi öğesine UriVideoSource
dönüştürür. Daha sonra video yüklenmeye başlar ve yeterli miktarda veri indirildikten ve arabelleğe alındıktan sonra oynatılmaya başlar. Her platformda, kullanılmayan ancak videoya dokunarak geri yüklenebilen aktarım denetimleri kaybolur.
Video kaynağı oynatma
MauiAsset derleme eylemiyle uygulamanın Resources\Raw klasörüne eklenmiş video dosyaları denetim tarafından Video
oynatılabilir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:VideoDemos.Controls"
x:Class="VideoDemos.Views.PlayVideoResourcePage"
Unloaded="OnContentPageUnloaded"
Title="Play video resource">
<controls:Video x:Name="video"
Source="video.mp4" />
</ContentPage>
Bu örnekte sınıfı, VideoSourceConverter
videonun dosya adını temsil eden dizeyi öğesine ResourceVideoSource
dönüştürür. Her platform için, dosya uygulama paketinde olduğundan ve indirilmesi gerekmeyen video kaynağı ayarlandıktan hemen sonra video oynatılmaya başlar. Her platformda, kullanılmayan ancak videoya dokunarak geri yüklenebilen aktarım denetimleri kaybolur.
Cihazın kitaplığından video dosyası yürütme
Cihazda depolanan video dosyaları alınabilir ve ardından denetim tarafından Video
oynatılabilir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:VideoDemos.Controls"
x:Class="VideoDemos.Views.PlayLibraryVideoPage"
Unloaded="OnContentPageUnloaded"
Title="Play library video">
<Grid RowDefinitions="*,Auto">
<controls:Video x:Name="video" />
<Button Grid.Row="1"
Text="Show Video Library"
Margin="10"
HorizontalOptions="Center"
Clicked="OnShowVideoLibraryClicked" />
</Grid>
</ContentPage>
öğesine dokunulduğunda Button Clicked
, aşağıdaki kod örneğinde gösterilen olay işleyicisi yürütülür:
async void OnShowVideoLibraryClicked(object sender, EventArgs e)
{
Button button = sender as Button;
button.IsEnabled = false;
var pickedVideo = await MediaPicker.PickVideoAsync();
if (!string.IsNullOrWhiteSpace(pickedVideo?.FileName))
{
video.Source = new FileVideoSource
{
File = pickedVideo.FullPath
};
}
button.IsEnabled = true;
}
Olay işleyicisi Clicked
, kullanıcının cihazdan bir video dosyası seçmesine izin vermek için .NET MAUI'nin MediaPicker
sınıfını kullanır. Seçilen video dosyası daha sonra bir FileVideoSource
nesne olarak kapsüllenip denetimin Source
Video
özelliği olarak ayarlanır. Sınıf hakkında MediaPicker
daha fazla bilgi için bkz . Medya seçici. Her platform için, dosya cihazda olduğundan ve indirilmesi gerekmeyen video kaynağı ayarlandıktan hemen sonra video oynatılmaya başlar. Her platformda, kullanılmayan ancak videoya dokunarak geri yüklenebilen aktarım denetimleri kaybolur.
Video denetimini yapılandırma
özelliğini false
olarak ayarlayarak videonun otomatik olarak başlatılmasını AutoPlay
engelleyebilirsiniz:
<controls:Video x:Name="video"
Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AutoPlay="False" />
özelliğini false
olarak ayarlayarak AreTransportControlsEnabled
aktarım denetimlerini gizleyebilirsiniz:
<controls:Video x:Name="video"
Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AreTransportControlsEnabled="False" />
ve AreTransportControlsEnabled
false
olarak ayarlarsanızAutoPlay
, video oynatılmaya başlamaz ve oynatılmaya başlamanın hiçbir yolu yoktur. Bu senaryoda arka planda kod dosyasından Play
yöntemini çağırmanız veya kendi aktarım denetimlerinizi oluşturmanız gerekir.
Ayrıca, özelliğini olarak ayarlayarak bir videoyu döngüye IsLooping
ayarlayabilirsiniz true:
<controls:Video x:Name="video"
Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
IsLooping="true" />
özelliğini bu şekilde true
ayarlarsanızIsLooping
, denetimin Video
sonuna ulaştıktan sonra video konumunu otomatik olarak başlangıç konumuna ayarlamasını sağlar.
Özel aktarım denetimlerini kullanma
Aşağıdaki XAML örneği videoyu yürüten, duraklatan ve durduran özel aktarım denetimlerini gösterir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:VideoDemos.Controls"
x:Class="VideoDemos.Views.CustomTransportPage"
Unloaded="OnContentPageUnloaded"
Title="Custom transport controls">
<Grid RowDefinitions="*,Auto">
<controls:Video x:Name="video"
AutoPlay="False"
AreTransportControlsEnabled="False"
Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />
<ActivityIndicator Color="Gray"
IsVisible="False">
<ActivityIndicator.Triggers>
<DataTrigger TargetType="ActivityIndicator"
Binding="{Binding Source={x:Reference video},
Path=Status}"
Value="{x:Static controls:VideoStatus.NotReady}">
<Setter Property="IsVisible"
Value="True" />
<Setter Property="IsRunning"
Value="True" />
</DataTrigger>
</ActivityIndicator.Triggers>
</ActivityIndicator>
<Grid Grid.Row="1"
Margin="0,10"
ColumnDefinitions="0.5*,0.5*"
BindingContext="{x:Reference video}">
<Button Text="▶️ Play"
HorizontalOptions="Center"
Clicked="OnPlayPauseButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static controls:VideoStatus.Playing}">
<Setter Property="Text"
Value="⏸ Pause" />
</DataTrigger>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static controls:VideoStatus.NotReady}">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
<Button Grid.Column="1"
Text="⏹ Stop"
HorizontalOptions="Center"
Clicked="OnStopButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static controls:VideoStatus.NotReady}">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
</Grid>
</Grid>
</ContentPage>
Bu örnekte, Video
denetim özelliğini false
olarak ayarlar ve videoyu AreTransportControlsEnabled
yürüten ve duraklatan ve video kayıttan yürütmeyi durduran bir Button öğesini tanımlarButton. Düğme görünümü, simge ve metinden oluşan düğmeler oluşturmak için unicode karakterler ve bunların metin eşdeğerleri kullanılarak tanımlanır:
Video oynatılırken oynat düğmesi duraklat düğmesine güncelleştirilir:
Kullanıcı arabirimi, video yüklenirken görüntülenen bir ActivityIndicator de içerir. Veri tetikleyicileri, ve düğmelerini etkinleştirmek ve devre dışı bırakmak ActivityIndicator ve ilk düğmeyi oynatma ve duraklatma arasında değiştirmek için kullanılır. Veri tetikleyicileri hakkında daha fazla bilgi için bkz . Veri tetikleyicileri.
Arka planda kod dosyası, düğme Clicked
olayları için olay işleyicilerini tanımlar:
public partial class CustomTransportPage : ContentPage
{
...
void OnPlayPauseButtonClicked(object sender, EventArgs args)
{
if (video.Status == VideoStatus.Playing)
{
video.Pause();
}
else if (video.Status == VideoStatus.Paused)
{
video.Play();
}
}
void OnStopButtonClicked(object sender, EventArgs args)
{
video.Stop();
}
...
}
Özel konumlandırma çubuğu
Aşağıdaki örnekte, PositionSlider
XAML'de kullanılan özel bir konumlandırma çubuğu gösterilmektedir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:VideoDemos.Controls"
x:Class="VideoDemos.Views.CustomPositionBarPage"
Unloaded="OnContentPageUnloaded"
Title="Custom position bar">
<Grid RowDefinitions="*,Auto,Auto">
<controls:Video x:Name="video"
AreTransportControlsEnabled="False"
Source="{StaticResource ElephantsDream}" />
...
<Grid Grid.Row="1"
Margin="10,0"
ColumnDefinitions="0.25*,0.25*,0.25*,0.25*"
BindingContext="{x:Reference video}">
<Label Text="{Binding Path=Position,
StringFormat='{0:hh\\:mm\\:ss}'}"
HorizontalOptions="Center"
VerticalOptions="Center" />
...
<Label Grid.Column="3"
Text="{Binding Path=TimeToEnd,
StringFormat='{0:hh\\:mm\\:ss}'}"
HorizontalOptions="Center"
VerticalOptions="Center" />
</Grid>
<controls:PositionSlider Grid.Row="2"
Margin="10,0,10,10"
BindingContext="{x:Reference video}"
Duration="{Binding Duration}"
Position="{Binding Position}">
<controls:PositionSlider.Triggers>
<DataTrigger TargetType="controls:PositionSlider"
Binding="{Binding Status}"
Value="{x:Static controls:VideoStatus.NotReady}">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</controls:PositionSlider.Triggers>
</controls:PositionSlider>
</Grid>
</ContentPage>
Position
ÖzelliğiVideo
, her platformda yöntemi tarafından MauiVideoPlayer.UpdateStatus
değiştirildiğinden, nesnenin PositionSlider
özelliği performans sorunları Video.Position
olmadan öğesinin özelliğine bağlıdır Position
ve bu da saniyede yalnızca 10 kez çağrılır. Buna ek olarak, iki Label nesne nesneden Position
Video
ve TimeToEnd
özellikleri değerlerini görüntüler.
Yerel görünüm temizleme
Her platformun işleyici uygulaması, olaylardan abonelikten çıkarma ve nesneleri yok etme gibi yerel görünüm temizleme gerçekleştirmek için kullanılan uygulamayı geçersiz kılar DisconnectHandler . Ancak, bu geçersiz kılma kasıtlı olarak .NET MAUI tarafından çağrılmıyor. Bunun yerine, uygulamanızın yaşam döngüsünde uygun bir konumdan kendiniz çağırmanız gerekir. Bu durum genellikle denetimi içeren sayfanın bulunduğu sayfadan Video
uzaklaştığında olur ve bu da sayfanın Unloaded
olayının tetiklenmesine neden olur.
Sayfanın Unloaded
olayı için bir olay işleyicisi XAML'ye kaydedilebilir:
<ContentPage ...
xmlns:controls="clr-namespace:VideoDemos.Controls"
Unloaded="OnContentPageUnloaded">
<controls:Video x:Name="video"
... />
</ContentPage>
Daha sonra olayın olay işleyicisi Unloaded
, örneğinde DisconnectHandler Handler
yöntemini çağırabilir:
void OnContentPageUnloaded(object sender, EventArgs e)
{
video.Handler?.DisconnectHandler();
}
Yerel görünüm kaynaklarını temizlemeye ek olarak, işleyicinin DisconnectHandler yöntemini çağırmak, iOS'ta videoların geriye dönük gezintide oynatılmasını da durdurur.
Denetim işleyicisi bağlantısının kesilmesi
Her platformun işleyici uygulaması, olaylardan abonelikten çıkarma ve nesneleri yok etme gibi yerel görünüm temizleme gerçekleştirmek için kullanılan uygulamayı geçersiz kılar DisconnectHandler . Varsayılan olarak, işleyiciler bir uygulamada geriye doğru gezinirken olduğu gibi mümkün olduğunda denetimlerinin bağlantısını otomatik olarak keser.
Bazı senaryolarda, ekli özellik ile HandlerProperties.DisconnectPolicy
elde edilebilen bir işleyicinin denetimiyle bağlantısının ne zaman kesilebileceğini denetlemek isteyebilirsiniz. Bu özellik, sabit listesi aşağıdaki değerleri tanımlayan bir HandlerDisconnectPolicy bağımsız değişken gerektirir:
Automatic
, işleyicinin bağlantısının otomatik olarak kesileceğini gösterir. Bu, eklenen özelliğinHandlerProperties.DisconnectPolicy
varsayılan değeridir.Manual
, işleyicinin uygulamayı çağırarak el ile bağlantısının DisconnectHandler() kesilmesi gerektiğini gösterir.
Aşağıdaki örnekte, ekli özelliğin HandlerProperties.DisconnectPolicy
ayarlanması gösterilmektedir:
<controls:Video x:Name="video"
HandlerProperties.DisconnectPolicy="Manual"
Source="video.mp4"
AutoPlay="False" />
Eşdeğer C# kodu:
Video video = new Video
{
Source = "video.mp4",
AutoPlay = false
};
HandlerProperties.SetDisconnectPolicy(video, HandlerDisconnectPolicy.Manual);
Ekli özelliği Manual
size ayarlarkenHandlerProperties.DisconnectPolicy
, işleyicinin DisconnectHandler uygulamasını uygulamanızın yaşam döngüsünde uygun bir konumdan kendiniz çağırmanız gerekir. Bu, çağrılarak video.Handler?.DisconnectHandler();
elde edilebilir.
Ayrıca, işleyicilerin belirli IViewbir ile bağlantısını kesen bir DisconnectHandlers uzantı yöntemi vardır:
video.DisconnectHandlers();
Bağlantı kesilirken, DisconnectHandlers yöntem el ile ilke ayarlayan bir denetimi tamamlayana veya ulaşana kadar denetim ağacını aşağı doğru yayacaktır.