You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在.NET MAUI中基于MediaElement实现音频播放进度滑块?

.NET MAUI 音频进度滑块实现方案(基于MediaElement)

一、布局实现

根据需求,可选择两种布局方式实现进度滑块:

方式1:自定义视觉进度(灵活可控)

通过BoxView实现进度填充效果,叠加透明Slider支持交互,同时显示当前/总时长:

<HorizontalStackLayout HeightRequest="40" Margin="16,0">
    <!-- 进度背景条 -->
    <BoxView x:Name="ProgressBg" Color="#E0E0E0" CornerRadius="20" HeightRequest="8" VerticalOptions="Center" />
    <!-- 动态填充的进度条 -->
    <BoxView x:Name="ProgressFill" Color="#2196F3" CornerRadius="20" HeightRequest="8" VerticalOptions="Center" WidthRequest="0" />
    <!-- 透明可交互滑块 -->
    <Slider x:Name="AudioSlider" 
            Minimum="0" 
            Maximum="100" 
            Value="0" 
            Opacity="0" 
            HeightRequest="40" 
            VerticalOptions="Center"
            DragCompleted="AudioSlider_DragCompleted" />
    <!-- 时间标签 -->
    <Label x:Name="CurrentTime" Text="00:00" Margin="8,0" VerticalOptions="Center" />
    <Label x:Name="TotalTime" Text="00:00" Margin="0,0,8,0" VerticalOptions="Center" />
</HorizontalStackLayout>

<!-- 音频播放组件 -->
<toolkit:MediaElement x:Name="AudioPlayer" 
                      AutoPlay="False"
                      MediaOpened="AudioPlayer_MediaOpened"
                      PositionChanged="AudioPlayer_PositionChanged"
                      MediaEnded="AudioPlayer_MediaEnded" />

方式2:自定义Slider样式(简洁高效)

直接修改Slider的默认样式,通过绑定实现进度同步:

<ContentPage.Resources>
    <!-- 时间转秒转换器 -->
    <local:TimeSpanToSecondsConverter x:Key="TimeSpanToSeconds" />
    <!-- Slider自定义样式 -->
    <Style TargetType="Slider">
        <Setter Property="MinimumTrackColor" Value="#2196F3" />
        <Setter Property="MaximumTrackColor" Value="#E0E0E0" />
        <Setter Property="ThumbColor" Value="#2196F3" />
        <Setter Property="HeightRequest" Value="8" />
        <Setter Property="ThumbSize" Value="16" />
    </Style>
</ContentPage.Resources>

<Slider x:Name="AudioSlider"
        Minimum="0"
        Maximum="{Binding Source={x:Reference AudioPlayer}, Path=Duration.TotalSeconds, FallbackValue=0}"
        Value="{Binding Source={x:Reference AudioPlayer}, Path=Position, Converter={StaticResource TimeSpanToSeconds}, Mode=TwoWay}" />

<toolkit:MediaElement x:Name="AudioPlayer" AutoPlay="False" />

二、后台逻辑实现

1. 基础事件处理(对应方式1)

// 音频加载完成:初始化滑块最大值与总时长标签
private void AudioPlayer_MediaOpened(object sender, EventArgs e)
{
    if (AudioPlayer.Duration.TotalSeconds <= 0) return;
    AudioSlider.Maximum = AudioPlayer.Duration.TotalSeconds;
    TotalTime.Text = TimeSpan.FromSeconds(AudioPlayer.Duration.TotalSeconds).ToString(@"mm\:ss");
}

// 播放位置变化:实时更新进度填充与当前时间
private void AudioPlayer_PositionChanged(object sender, CommunityToolkit.Maui.Core.Primitives.PositionChangedEventArgs e)
{
    if (AudioPlayer.Duration.TotalSeconds <= 0) return;
    
    AudioSlider.Value = e.Position.TotalSeconds;
    var progressRatio = e.Position.TotalSeconds / AudioPlayer.Duration.TotalSeconds;
    ProgressFill.WidthRequest = ProgressBg.Width * progressRatio;
    CurrentTime.Text = e.Position.ToString(@"mm\:ss");
}

// 滑块拖动完成:同步播放位置
private void AudioSlider_DragCompleted(object sender, EventArgs e)
{
    if (AudioPlayer.Duration.TotalSeconds > 0)
    {
        AudioPlayer.Position = TimeSpan.FromSeconds(AudioSlider.Value);
    }
}

// 播放/暂停控制
private void PlayPauseBtn_Clicked(object sender, EventArgs e)
{
    if (AudioPlayer.CurrentState == CommunityToolkit.Maui.Core.Primitives.MediaElementState.Playing)
    {
        AudioPlayer.Pause();
        // 更新按钮图标为播放状态
    }
    else
    {
        AudioPlayer.Play();
        // 更新按钮图标为暂停状态
    }
}

2. 值转换器实现(对应方式2)

public class TimeSpanToSecondsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value is TimeSpan span ? span.TotalSeconds : 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value is double seconds ? TimeSpan.FromSeconds(seconds) : TimeSpan.Zero;
    }
}

三、关键注意事项

  • 进度自动暂停PositionChanged事件仅在音频播放时触发,暂停时会自动停止进度更新,无需额外处理。
  • 平台兼容性:Android与iOS上MediaElement的事件表现一致,无需针对平台单独适配。
  • 异常处理:需监听MediaFailed事件,在音频加载失败时重置进度状态。
  • 性能优化:若需处理高频率进度更新,可通过MainThread.BeginInvokeOnMainThread确保UI操作在主线程执行。

内容的提问来源于stack exchange,提问作者Matthew Pans

火山引擎 最新活动