如何使用 Rx 遍历一系列带有停顿和淡入淡出的字符串?
How do I use Rx to iterate through a series of strings with pauses and fade ins and outs?
我的要求是从数组中取出一系列字符串,从第一个开始,5 秒后移动到下一个字符串,同时在 Xamarin 中使用带有 XAML 的 Rx 淡出并淡出下一个字符串。您可以假设这是在具有 'Message' 属性 和 'MessageOpacity' 属性 的视图模型上发生的,它们适用于文本和介于 0 和 1 之间的小数。您还可以假设我有后台调度程序和 UiScheduler 设置。
我对 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];
});
上面的方法不起作用,因为 Buffer 没有按照我的预期工作。相反,它每 5 秒快速连续地发射 4 根弦,而不是逐步穿过每根弦。
我不明白的是如何以正确的 'Rx' 方式按每个 'x seconds' 的顺序遍历每个字符串,以及(作为对我的奖励!)如何随后触发另一个可观察到的每条新消息都会在每次更改时将不透明度从 0 提高和降低到 1。
目的是实现 'windows 10' 风格的屏幕,以便在发生重大更新或用户等待长时间操作完成时使用。
您可以使用 Zip 运算符结合 Observable.Interval 来提供您想要的迭代字符串输出:
[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());
}
请注意,第一个元素的不透明度将为零,因此您看不到它。您可能希望稍微更改数学(提供偏移量)以将不透明度从非零值缩放为一。
希望对您有所帮助: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];
});
我的要求是从数组中取出一系列字符串,从第一个开始,5 秒后移动到下一个字符串,同时在 Xamarin 中使用带有 XAML 的 Rx 淡出并淡出下一个字符串。您可以假设这是在具有 'Message' 属性 和 'MessageOpacity' 属性 的视图模型上发生的,它们适用于文本和介于 0 和 1 之间的小数。您还可以假设我有后台调度程序和 UiScheduler 设置。
我对 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];
});
上面的方法不起作用,因为 Buffer 没有按照我的预期工作。相反,它每 5 秒快速连续地发射 4 根弦,而不是逐步穿过每根弦。
我不明白的是如何以正确的 'Rx' 方式按每个 'x seconds' 的顺序遍历每个字符串,以及(作为对我的奖励!)如何随后触发另一个可观察到的每条新消息都会在每次更改时将不透明度从 0 提高和降低到 1。
目的是实现 'windows 10' 风格的屏幕,以便在发生重大更新或用户等待长时间操作完成时使用。
您可以使用 Zip 运算符结合 Observable.Interval 来提供您想要的迭代字符串输出:
[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());
}
请注意,第一个元素的不透明度将为零,因此您看不到它。您可能希望稍微更改数学(提供偏移量)以将不透明度从非零值缩放为一。
希望对您有所帮助: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];
});