我如何使用Rx迭代一系列字符串与暂停和淡出
本文关键字:暂停 淡出 字符串 一系列 何使用 Rx 迭代 | 更新日期: 2023-09-27 18:15:05
我的要求是从数组中取出一系列字符串,从第一个开始,5秒后移动到下一个,同时在Xamarin中使用Rx和XAML淡出下一个字符串。你可以假设这发生在一个视图模型上,它有一个'Message'属性和一个'MessageOpacity'属性,它接受文本和一个0到1之间的小数。你也可以假设我有一个后台调度程序和uisscheduler设置。
我对Rx相当陌生,这将变得明显,到目前为止,我已经做到了:
var messages = new[] {
"Welcome",
"We are settings things up for you",
"This may take a little while first time" };
Observable.Interval(TimeSpan.FromSeconds(5), Scheduler.BackgroundScheduler)
.SelectMany((long arg) => messages)
.Buffer(1, 1)
.SubscribeOn(Scheduler.UiScheduler)
.Subscribe((obj) =>
{
Message = obj[0];
});
以上不起作用,因为缓冲区没有按我预期的方式工作。相反,它每5秒快速连续发射4个字符串,而不是逐个串。
我不明白的是如何以正确的"Rx"方式按顺序每"x秒"遍历每个字符串,以及(作为对我的奖励!)如何随后触发另一个可观察到的每个新消息在每次更改时从0到1的不透明度上升和下降。
目的是实现"windows 10"风格的屏幕,当一个大的更新发生或当用户正在等待一个长时间的操作完成
你可以将Zip操作符与Observable结合使用。给出所需迭代字符串输出的间隔:
[Fact]
public void ShouldIterateThroughStringsEveryFiveSeconds()
{
TestScheduler scheduler = new TestScheduler();
string[] messages = new[]
{
"Welcome",
"We are settings things up for you",
"This may take a little while first time"
};
var expected = new[]
{
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(0).Ticks, "Welcome"),
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(5).Ticks, "We are settings things up for you"),
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(10).Ticks, "This may take a little while first time"),
ReactiveTest.OnCompleted<string>(ReactiveTest.Subscribed + TimeSpan.FromSeconds(15).Ticks)
};
var actual = scheduler.Start(
// Solution
() => Observable.Zip(
messages.ToObservable(),
Observable.Interval(TimeSpan.FromSeconds(5), scheduler).StartWith(0),
(text, time) => text),
TimeSpan.FromSeconds(20).Ticks
);
Assert.Equal(expected, actual.Messages.ToArray());
}
编辑:与其为不透明度添加第二个可观察对象,不如这样组合它们:
[Fact]
public void ShouldIterateThroughStringsEveryFiveSecondsProvidingStringAndOpacity()
{
TestScheduler scheduler = new TestScheduler();
string[] messages = new[]
{
"Welcome",
"We are settings things up for you",
"This may take a little while first time"
};
var expected = new[]
{
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(0).Ticks, Tuple.Create("Welcome", 0.0)),
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(5).Ticks, Tuple.Create("We are settings things up for you", 0.5)),
ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(10).Ticks, Tuple.Create("This may take a little while first time", 1.0)),
ReactiveTest.OnCompleted<Tuple<string, double>>(ReactiveTest.Subscribed + TimeSpan.FromSeconds(15).Ticks)
};
var actual = scheduler.Start(
// Solution
() => Observable
.Zip(
messages.ToObservable(),
Observable.Interval(TimeSpan.FromSeconds(5), scheduler).StartWith(0),
(text, time) => text)
.Select((text, index) => Tuple.Create(text, Convert.ToDouble(index) / Convert.ToDouble(messages.Length - 1))),
TimeSpan.FromSeconds(20).Ticks
);
Assert.Equal(expected, actual.Messages.ToArray());
}
请注意,第一个元素的不透明度将为零,因此您将看不到它。你可能想稍微改变数学(提供一个偏移量),将不透明度从非零值缩放到1。
希望有帮助:0)
我将使用Observable.Generate
:
Observable
.Generate(
1,
x => x < messages.Length,
x => x + 1,
x => x,
x => TimeSpan.FromSeconds(5.0))
.StartWith(0)
.Select(x => messages[x])
.Subscribe((obj) =>
{
Message = obj[0];
});
你可以尝试这个版本,它确保在处理开始之前对源数组进行复制-这避免了可能的副作用。
Observable
.Create<string>(o =>
{
var ms = messages.ToArray();
return Observable
.Generate(
1,
x => x < ms.Length,
x => x + 1,
x => x,
x => TimeSpan.FromSeconds(5.0))
.StartWith(0)
.Select(x => ms[x])
.Subscribe(o);
})
.Subscribe((obj) =>
{
Message = obj[0];
});