Xamarin Community Toolkit MediaElement
MediaElement
是播放視訊和音訊的檢視。 基礎平臺支援的媒體可從下列來源播放:
- Web,使用 URI (HTTP 或 HTTPS) 。
- 使用
ms-appx:///
URI 配置內嵌在平臺應用程式中的資源。 - 使用 URI 配置,來自應用程式的本機和暫存資料檔案夾的
ms-appdata:///
檔案。 - 裝置的程式庫。
MediaElement
可以使用平臺播放控制項,這稱為傳輸控制項。 不過,預設會停用它們,並可取代為您自己的傳輸控制項。 下列螢幕擷取畫面顯示 MediaElement
使用平臺傳輸控制項播放影片:
注意
MediaElement
適用于 iOS、Android、通用 Windows 平臺 (UWP) 、macOS、Windows Presentation Foundation和 Tizen。
MediaElement
會定義下列屬性:
Aspect
類型Aspect
為 的 ,決定媒體如何調整以符合顯示區域。 此屬性的預設值為AspectFit
。AutoPlay
類型bool
為 的 ,指出設定 屬性時Source
,媒體播放是否會自動開始。 此屬性的預設值為true
。BufferingProgress
類型double
為 的 ,表示目前的緩衝進度。 此屬性的預設值為 0.0。CanSeek
類型bool
為 的 ,指出媒體是否可以藉由設定 屬性的值Position
來重新置放。 這是一個唯讀屬性。CurrentState
類型MediaElementState
為 的 ,表示控制項的目前狀態。 這是唯讀屬性,其預設值為MediaElementState.Closed
。Duration
類型TimeSpan?
為 的 ,表示目前開啟媒體的持續時間。 這是唯讀屬性,其預設值為null
。IsLooping
類型bool
為 的 ,描述目前載入的媒體來源是否應該在到達其結束之後從開始繼續播放。 此屬性的預設值為false
。KeepScreenOn
類型bool
為 的 ,可判斷裝置畫面是否應該在媒體播放期間保持開啟。 此屬性的預設值為false
。Position
類型TimeSpan
為 的 ,描述媒體播放時間的目前進度。 此屬性使用系TwoWay
結,其預設值為TimeSpan.Zero
。ShowsPlaybackControls
類型bool
為 的 ,決定是否顯示平臺播放控制項。 此屬性的預設值為false
。 請注意,在 iOS 上,控制項只會在與畫面互動之後顯示一段短暫的時間。 無法隨時讓控制項保持可見。 在 WPF 上,不支援系統控制項,因此此屬性沒有任何作用。Speed
類型double
為 的 ,決定媒體的播放速度。 這個屬性的預設值為 1。Source
類型MediaSource
為 的 ,表示載入控制項的媒體來源。VideoHeight
類型int
為 的 ,表示控制項的高度。 這是一個唯讀屬性。VideoWidth
類型int
為 的 ,表示控制項的寬度。 這是一個唯讀屬性。Volume
類型double
為 的 ,會決定媒體的磁片區,以介於 0 到 1 之間的線性刻度表示。 此屬性使用系TwoWay
結,其預設值為 1。
除了 屬性之外 CanSeek
,這些屬性是由 物件所支援 BindableProperty
,這表示這些屬性可以是資料系結的目標,並設定樣式。
類別 MediaElement
也會定義四個事件:
MediaOpened
在媒體資料流程經過驗證並開啟時引發。MediaEnded
會在 完成播放其媒體時MediaElement
引發。MediaFailed
當媒體來源發生相關錯誤時,就會引發 。SeekCompleted
當所要求搜尋作業的搜尋點準備好播放時,就會引發 。
此外, MediaElement
還包含 Play
、 Pause
和 Stop
方法。
如需 Android 上支援媒體格式的資訊,請參閱支援 developer.android.com 的 媒體格式 。 如需通用 Windows 平臺 (UWP) 上支援媒體格式的資訊,請參閱支援的編解碼器。
播放遠端媒體
MediaElement
可以使用 HTTP 和 HTTPS URI 配置播放遠端媒體檔案。 這可藉由將 Source
屬性設定為媒體檔案的 URI 來完成:
<MediaElement Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"
ShowsPlaybackControls="True" />
根據預設,屬性所 Source
定義的媒體會在媒體開啟之後立即播放。 若要隱藏自動媒體播放,請將 AutoPlay
屬性設定為 false
。
預設會停用媒體播放控制項,並將 屬性設定 ShowsPlaybackControls
為 true
來啟用。 MediaElement
接著會使用可用的平臺播放控制項。
播放本機媒體
您可以從下列來源播放本機媒體:
- 使用
ms-appx:///
URI 配置內嵌在平臺應用程式中的資源。 - 使用 URI 配置,來自應用程式的本機和暫存資料檔案夾的
ms-appdata:///
檔案。 - 裝置的程式庫。
如需這些 URI 配置的詳細資訊,請參閱 URI 配置。
播放內嵌在應用程式套件中的媒體
MediaElement
可以使用 URI 配置播放內嵌在應用程式套件 ms-appx:///
中的媒體檔案。 媒體檔案會內嵌在應用程式套件中,方法是將它們放在平臺專案中。
在每個平臺專案中儲存媒體檔案會有所不同:
- 在 iOS 上,媒體檔案必須儲存在 Resources 資料夾或 Resources 資料夾的子資料夾中。 媒體檔案必須具有
Build Action
的BundleResource
。 - 在 Android 上,媒體檔案必須儲存 在名為raw的資源子資料夾中。 raw 資料夾不能包含子資料夾。 媒體檔案必須具有
Build Action
的AndroidResource
。 - 在 UWP 上,媒體檔案可以儲存在專案中的任何資料夾中。 媒體檔案必須具有
BuildAction
的Content
。
然後,您可以使用 URI 配置來播放符合這些準則的 ms-appx:///
媒體檔案:
<MediaElement Source="ms-appx:///XamarinForms101UsingEmbeddedImages.mp4"
ShowsPlaybackControls="True" />
使用資料系結時,可以使用值轉換器來套用此 URI 配置:
public class VideoSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return null;
if (string.IsNullOrWhiteSpace(value.ToString()))
return null;
if (Device.RuntimePlatform == Device.UWP)
return new Uri($"ms-appx:///Assets/{value}");
else
return new Uri($"ms-appx:///{value}");
}
// ...
}
接著,可以使用 的 VideoSourceConverter
實例,將 URI 配置套 ms-appx:///
用至內嵌媒體檔案:
<MediaElement Source="{Binding MediaSource, Converter={StaticResource VideoSourceConverter}}"
ShowsPlaybackControls="True" />
如需 ms-appx URI 配置的詳細資訊,請參閱 ms-appx 和 ms-appx-web。
從應用程式的本機和暫存資料夾播放媒體
MediaElement
可以使用 URI 配置,播放複製到應用程式本機或暫存資料檔案夾 ms-appdata:///
的媒體檔案。
下列範例顯示 Source
屬性設定為儲存在應用程式本機資料檔案夾中的媒體檔案:
<MediaElement Source="ms-appdata:///local/XamarinVideo.mp4"
ShowsPlaybackControls="True" />
下列範例顯示儲存 Source
在應用程式暫存資料檔案夾中之媒體檔案的屬性:
<MediaElement Source="ms-appdata:///temp/XamarinVideo.mp4"
ShowsPlaybackControls="True" />
重要
除了播放儲存在應用程式本機或暫存資料檔案夾中的媒體檔案之外,UWP 也可以播放位於應用程式漫遊資料夾中的媒體檔案。 藉由將媒體檔案 ms-appdata:///roaming/
前置詞加上 ,即可達成此目的。
使用資料系結時,可以使用值轉換器來套用此 URI 配置:
public class VideoSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return null;
if (string.IsNullOrWhiteSpace(value.ToString()))
return null;
return new Uri($"ms-appdata:///{value}");
}
// ...
}
接著,可以使用 的 VideoSourceConverter
實例,將 URI 配置套 ms-appdata:///
用至應用程式本機或暫存資料檔案夾中的媒體檔案:
<MediaElement Source="{Binding MediaSource, Converter={StaticResource VideoSourceConverter}}"
ShowsPlaybackControls="True" />
如需 ms-appdata URI 配置的詳細資訊,請參閱 ms-appdata。
將媒體檔案複製到應用程式的本機或暫存資料檔案夾
播放儲存在應用程式本機或暫存資料檔案夾中的媒體檔案,需要應用程式將媒體檔案複製到該處。 例如,藉由從應用程式套件複製媒體檔案,即可完成此作業:
// This method copies the video from the app package to the app data
// directory for your app. To copy the video to the temp directory
// for your app, comment out the first line of code, and uncomment
// the second line of code.
public static async Task CopyVideoIfNotExists(string filename)
{
string folder = FileSystem.AppDataDirectory;
//string folder = Path.GetTempPath();
string videoFile = Path.Combine(folder, "XamarinVideo.mp4");
if (!File.Exists(videoFile))
{
using (Stream inputStream = await FileSystem.OpenAppPackageFileAsync(filename))
{
using (FileStream outputStream = File.Create(videoFile))
{
await inputStream.CopyToAsync(outputStream);
}
}
}
}
注意
上述程式碼範例會 FileSystem
使用 Xamarin.Essentials 中包含的 類別。 如需詳細資訊,請參閱 Xamarin.Essentials:檔案系統協助程式。
從裝置媒體櫃播放媒體
大部分的新式行動裝置和桌上型電腦都能夠使用裝置的相機和麥克風來錄製視訊和音訊。 接著,建立的媒體會儲存為裝置上的檔案。 您可以從程式庫擷取這些檔案,並由 播放 MediaElement
。
每個平臺都包含一個功能,可讓使用者從裝置的程式庫選取媒體。 在 Xamarin.Forms 中,平臺專案可以叫用這項功能,而且可由 類別呼叫 DependencyService
。
範例應用程式中所使用的影片挑選相依性服務與 從圖片庫挑選相片中所定義的相依性服務非常類似,不同之處在于選擇器會傳回檔案名,而不是 Stream
物件。 共用程式碼專案會定義名為 的 IVideoPicker
介面,該介面會定義名為 GetVideoFileAsync
的單一方法。 然後,每個平臺都會在 類別中實作 VideoPicker
這個介面。
下列程式碼範例示範如何從裝置程式庫擷取媒體檔案:
string filename = await DependencyService.Get<IVideoPicker>().GetVideoFileAsync();
if (!string.IsNullOrWhiteSpace(filename))
{
mediaElement.Source = new FileMediaSource
{
File = filename
};
}
呼叫 方法來取得平臺專案中介面的實作 IVideoPicker
,以叫 DependencyService.Get
用影片挑選相依性服務。 GetVideoFileAsync
然後,在該實例上呼叫 方法,並使用傳回的檔案名來建立 FileMediaSource
物件,並將它設定為 Source
的 MediaElement
屬性。
變更視訊外觀比例
屬性 Aspect
會決定視訊媒體的縮放方式,以符合顯示區域。 根據預設,此屬性會設定為 AspectFit
列舉成員,但可以設定為任何 Aspect
列舉成員:
AspectFit
表示視訊會視需要收件匣,以符合顯示區域,同時保留外觀比例。AspectFill
表示會裁剪視訊,使其填滿顯示區域,同時保留外觀比例。Fill
表示視訊會延展以填滿顯示區域。
系結至 Position 屬性
播放時,可系結屬性的屬性變更通知 Position
會以 200 毫秒間隔引發。 因此,屬性可以系結至 Slider
控制項 (或類似) ,以透過媒體顯示進度。 CommunityToolkit 也提供 , TimeSpanToDoubleConverter
其會將 TimeSpan
轉換成浮點值,代表經過的總秒數。 如此一來,您可以將 Slider Maximum
設定為 Duration
媒體的 , Value
並將 設定為 , Position
以提供精確的進度:
<?xml version="1.0" encoding="UTF-8"?>
<pages:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:pages="clr-namespace:Xamarin.CommunityToolkit.Sample.Pages"
x:Class="Xamarin.CommunityToolkit.Sample.Pages.Views.MediaElementPage">
<pages:BasePage.Resources>
<xct:TimeSpanToDoubleConverter x:Key="TimeSpanConverter"/>
</pages:BasePage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<xct:MediaElement
x:Name="mediaElement"
Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"
ShowsPlaybackControls="True"
HorizontalOptions="Fill"
SeekCompleted="OnSeekCompleted" />
<Slider Grid.Row="1" BindingContext="{x:Reference mediaElement}" Value="{Binding Position, Converter={StaticResource TimeSpanConverter}}" Maximum="{Binding Duration, Converter={StaticResource TimeSpanConverter}}">
<Slider.Triggers>
<DataTrigger TargetType="Slider"
Binding="{Binding CurrentState}"
Value="{x:Static MediaElementState.Buffering}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Slider.Triggers>
</Slider>
<Button Grid.Row="2" Text="Reset Source (Set Null)" Clicked="OnResetClicked" />
</Grid>
</pages:BasePage>
在此範例中 Maximum
,的 Slider
屬性會系結至 Duration
的 MediaElement
屬性,而 Value
的 Slider
屬性則系結至 Position
的 屬性 MediaElement
。 因此,拖 Slider
曳媒體播放位置的結果會變更:
此外,當媒體進行緩衝處理時, DataTrigger
會使用 物件來停用 Slider
。 如需資料觸發程式的詳細資訊,請參閱 Xamarin.Forms 觸發程式。
注意
在 Android 上, Slider
不論 和 Maximum
設定為何, Minimum
只有 1000 個離散步驟。 如果媒體長度大於 1000 秒,則兩個不同的 Position
值會對應至 相同的 Value
Slider
。 這就是為什麼上述程式碼會檢查新位置和現有位置是否大於整體持續時間的一百分之一。
瞭解 MediaSource 類型
MediaElement
可以播放媒體,方法是將其 Source
屬性設定為遠端或本機媒體檔案。 屬性 Source
的類型為 MediaSource
,而這個類別會定義兩個靜態方法:
FromFile
會從string
引數傳回MediaSource
實例。FromUri
會從Uri
引數傳回MediaSource
實例。
此外,類別 MediaSource
也有從 和 Uri
引數傳回 MediaSource
實例 string
的隱含運算子。
注意
Source
在 XAML 中設定 屬性時,會叫用型別轉換器,以從 string
或 傳 Uri
回 MediaSource
實例。
類別 MediaSource
也有兩個衍生類別:
UriMediaSource
,用來從 URI 指定遠端媒體檔案。 這個類別具有Uri
可設定為Uri
的屬性。FileMediaSource
,用來指定 的string
本機媒體檔案。 這個類別具有File
可設定為string
的屬性。 此外,這個類別具有隱含運算子,可將 轉換成 物件,並將FileMediaSource
物件轉換成string
string
。FileMediaSource
注意
FileMediaSource
在 XAML 中建立 物件時,會叫用型別轉換器,以從 string
傳回 FileMediaSource
實例。
判斷 MediaElement 狀態
類別 MediaElement
會定義名為 的唯讀可系結屬性,其 CurrentState
類型為 MediaElementState
。 這個屬性工作表示控制項的目前狀態,例如媒體現正播放或暫停,或者它尚未準備好播放媒體。
MediaElementState
列舉會定義下列成員:
Closed
表示MediaElement
不包含媒體。Opening
表示 正在MediaElement
驗證並嘗試載入指定的來源。Buffering
表示MediaElement
正在載入媒體以供播放。 其Position
屬性不會在此狀態期間前進。MediaElement
如果 現正播放視訊,它會繼續顯示最後一個顯示的框架。Playing
表示MediaElement
現正播放媒體來源。Paused
表示MediaElement
不會前進其Position
屬性。MediaElement
如果 現正播放視訊,它會繼續顯示目前的畫面。Stopped
表示MediaElement
包含媒體,但未播放或暫停。 其Position
屬性為 0,且不會前進。 如果載入的媒體是視訊,則會MediaElement
顯示第一個畫面。
使用 MediaElement
傳輸控制項時,通常不需要檢查 CurrentState
屬性。 不過,實作您自己的傳輸控制項時,這個屬性會變得很重要。
實作自訂傳輸控制項
媒體播放程式的傳輸控制項包含執行 播放、 暫停和 停止函式的按鈕。 這些按鈕通常會以熟悉的圖示而非文字呈現,且 [播放] 及 [暫停] 功能常會合併為一個按鈕。
根據預設, MediaElement
會停用播放控制項。 這可讓您 MediaElement
以程式設計方式或提供自己的傳輸控制項來控制 。 支援此功能時, MediaElement
包括 Play
、 Pause
和 Stop
方法。
下列 XAML 範例顯示包含 MediaElement
和 自訂傳輸控制項的頁面:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MediaElementDemos.CustomTransportPage"
Title="Custom transport">
<Grid>
...
<MediaElement x:Name="mediaElement"
AutoPlay="False"
... />
<StackLayout BindingContext="{x:Reference mediaElement}"
...>
<Button Text="▶️ Play"
HorizontalOptions="CenterAndExpand"
Clicked="OnPlayPauseButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding CurrentState}"
Value="{x:Static MediaElementState.Playing}">
<Setter Property="Text"
Value="⏸ Pause" />
</DataTrigger>
<DataTrigger TargetType="Button"
Binding="{Binding CurrentState}"
Value="{x:Static MediaElementState.Buffering}">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
<Button Text="⏹ Stop"
HorizontalOptions="CenterAndExpand"
Clicked="OnStopButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding CurrentState}"
Value="{x:Static MediaElementState.Stopped}">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
</StackLayout>
</Grid>
</ContentPage>
在此範例中,自訂傳輸控制項會定義為 Button
物件。 不過,只有兩 Button
個物件,第一個 Button
代表 Play 和 Pause,第二個 Button
代表 Stop。 DataTrigger
物件可用來啟用和停用按鈕,以及切換 播放 和 暫停之間的第一個按鈕。 如需資料觸發程式的詳細資訊,請參閱 Xamarin.Forms 觸發程式。
程式碼後置檔案具有事件的處理常式 Clicked
:
void OnPlayPauseButtonClicked(object sender, EventArgs args)
{
if (mediaElement.CurrentState == MediaElementState.Stopped ||
mediaElement.CurrentState == MediaElementState.Paused)
{
mediaElement.Play();
}
else if (mediaElement.CurrentState == MediaElementState.Playing)
{
mediaElement.Pause();
}
}
void OnStopButtonClicked(object sender, EventArgs args)
{
mediaElement.Stop();
}
一旦啟用 [播放] 按鈕,就可以按下 [ 播放 ] 按鈕,開始播放:
按下 [暫停] 按鈕會導致播放暫停:
按下 [停止] 按鈕會停止播放,並將媒體檔案的位置傳回至開頭。
實作自訂磁片區控制項
每個平臺所實作的媒體播放控制項都包含音量列。 此列類似于滑杆,並顯示媒體的音量。 此外,您可以操作磁片區列來增加或減少磁片區。
您可以使用 來實 Slider
作自訂磁片區列,如下列範例所示:
<StackLayout>
<MediaElement AutoPlay="False"
Source="{StaticResource AdvancedAsync}" />
<Slider Maximum="1.0"
Minimum="0.0"
Value="{Binding Volume}"
Rotation="270"
WidthRequest="100" />
</StackLayout>
在此範例中 Slider
,資料會將其 Value
屬性系結至 Volume
的 MediaElement
屬性。 這是可行的, Volume
因為 屬性使用系 TwoWay
結。 因此,變更 Value
屬性會導致 Volume
屬性變更。
注意
Volume
屬性具有驗證回呼,可確保其值大於或等於 0.0,且小於或等於 1.0。
如需使用 Slider
的詳細資訊,請參閱 Xamarin.Forms 滑杆