我需要通过在 .NET MAUI 中向上或向下滚动来查看列表中的项目。我的列表中有一些使用 YoutubeApi 和 MediaElement 展示的视频。 (Tiktok、Instagram Reels 等)我想在这里做什么;
无论哪个项目当前可见,MediaElement.Play()
该项目的 都应该起作用。无论如何我找不到合适的滚动事件。有人对此有什么想法吗?
我已经尝试了所有附加的方法来做到这一点,但没有成功。
4
1 个回答
1
布局
和CollectionView可以轻松实现这种布局和滚动行为:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="FullPageSnapCollection.MainPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:fullPageSnapCollection="clr-namespace:FullPageSnapCollection"
x:DataType="fullPageSnapCollection:MainViewModel">
<Grid>
<CollectionView
HeightRequest="500"
HorizontalOptions="Fill"
VerticalOptions="Center"
ItemsSource="{Binding Items}">
<CollectionView.ItemsLayout>
<LinearItemsLayout
Orientation="Vertical"
SnapPointsType="MandatorySingle"
SnapPointsAlignment="Start" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="fullPageSnapCollection:MyModel">
<Grid
HeightRequest="500"
BackgroundColor="{Binding BackgroundColor}"
HorizontalOptions="Fill">
<Label
Text="{Binding Name}"
VerticalOptions="Center"
HorizontalOptions="Center"
FontSize="Title" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage>
您需要HeightRequest
为CollectionView以及DataTemplate中的布局提供,以便项目与CollectionView具有相同的高度。与捕捉点一起,这应该会产生您正在寻找的内容。我还为此创建了一个小型
如果您需要检测当前在(视图)中心可见的项目,您可以订阅该事件并从事件参数中Scrolled
获取,如此所述。CenterItemIndex
自动播放/停止
为了播放MediaElement中托管的视频,我们需要使用一些小技巧。由于MediaElement不公开任何可绑定和可设置的属性,因此我们需要通过使用IsPlaying
扩展该类来自行添加:
public class ExtendedMediaElement : MediaElement
{
public bool IsPlaying
{
get => (bool)GetValue(IsPlayingProperty);
set => SetValue(IsPlayingProperty, value);
}
public static readonly BindableProperty IsPlayingProperty = BindableProperty.Create(nameof(IsPlaying), typeof(bool), typeof(ExtendedMediaElement), false, propertyChanged: OnIsPlayingPropertyChanged);
private static void OnIsPlayingPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var mediaElement = (ExtendedMediaElement)bindable;
if (newValue is true)
{
mediaElement.Play();
}
else
{
mediaElement.Stop();
}
}
}
现在,我们可以绑定到模型类的任何属性,通过更新属性来控制播放/停止功能。
接下来,我们需要向模型添加一个可观察属性,用于更新可绑定属性,例如:
public partial class MyModel(string videoUri) : ObservableObject
{
public string VideoUri { get; } = videoUri;
[ObservableProperty]
private bool _isPlaying;
}
我们将不使用MediaElement ,而是使用ExtendedMediaElement并在添加到我们添加的可绑定属性的DataTemplate
绑定中:IsPlaying
<DataTemplate x:DataType="fullPageSnapCollection:MyModel">
<Grid
HeightRequest="500"
BackgroundColor="{Binding BackgroundColor}"
HorizontalOptions="Fill">
<fullPageSnapCollection:ExtendedMediaElement
Aspect="Fill"
Source="{Binding VideoUri}"
ShouldAutoPlay="False"
ShouldLoopPlayback="True"
ShouldShowPlaybackControls="False"
IsPlaying="{Binding IsPlaying}" />
</Grid>
</DataTemplate>
最后但并非最不重要的一点是,我们现在可以使用CollectionViewScrolled
事件的事件处理程序来更新页面代码隐藏中每个模型实例的属性,这将随后触发播放/停止功能:IsPlaying
public partial class MainPage : ContentPage
{
private readonly MainViewModel _vm;
public MainPage()
{
InitializeComponent();
BindingContext = _vm = new MainViewModel();
}
private void ItemsView_OnScrolled(object? sender, ItemsViewScrolledEventArgs e)
{
var itemIndex = e.CenterItemIndex;
_vm.Items[itemIndex].IsPlaying = true;
foreach (var myModel in _vm.Items)
{
if (myModel != _vm.Items[itemIndex])
{
myModel.IsPlaying = false;
}
}
}
}
3
-
感谢您的回答。你太棒了。
– -
我需要通过滚动事件到达相当于 CenterItemIndex 的 MediaElement 并触发 MediaElement.Play()。您对此有什么想法吗?谢谢先生。 🙂
–
-
@Bestekarx 我已经更新了答案。
–
|
–
–
–
–
|