实施文本转语音

当你想要实现文本到语音转换(tts)时,请求特定于平台的代码的功能的一个很好的示例。此示例假定你正在使用 PCL 库中的共享代码。

我们的解决方案的示意图将看起来像下面的图像。

StackOverflow 文档

在我们的共享代码中,我们定义了一个在 DependencyService 中注册的接口。这是我们调用的地方。定义类似于下面的界面。

public interface ITextToSpeech
{
    void Speak (string text);
}

现在,在每个特定平台中,我们需要创建此接口的实现。让我们从 iOS 实现开始。

iOS 实施

using AVFoundation;

public class TextToSpeechImplementation : ITextToSpeech
{
    public TextToSpeechImplementation () {}

    public void Speak (string text)
    {
        var speechSynthesizer = new AVSpeechSynthesizer ();

        var speechUtterance = new AVSpeechUtterance (text) {
            Rate = AVSpeechUtterance.MaximumSpeechRate/4,
            Voice = AVSpeechSynthesisVoice.FromLanguage ("en-US"),
            Volume = 0.5f,
            PitchMultiplier = 1.0f
        };

        speechSynthesizer.SpeakUtterance (speechUtterance);
    }
}

在上面的代码示例中,你注意到 iOS 有特定的代码。像 AVSpeechSynthesizer 这样的类型。这些在共享代码中不起作用。

要使用 Xamarin DependencyService 注册此实现,请在命名空间声明上方添加此属性。

using AVFoundation;
using DependencyServiceSample.iOS;//enables registration outside of namespace

[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.iOS {
    public class TextToSpeechImplementation : ITextToSpeech
//... Rest of code

现在,当你在共享代码中执行此类调用时,将注入正在运行应用程序的平台的正确实现。

DependencyService.Get<ITextToSpeech>()。稍后会详细介绍。

Android 实施

这段代码的 Android 实现看起来就像在下面。

using Android.Speech.Tts;
using Xamarin.Forms;
using System.Collections.Generic;
using DependencyServiceSample.Droid;

public class TextToSpeechImplementation : Java.Lang.Object, ITextToSpeech, TextToSpeech.IOnInitListener
{
    TextToSpeech speaker;
    string toSpeak;

    public TextToSpeechImplementation () {}

    public void Speak (string text)
    {
        var ctx = Forms.Context; // useful for many Android SDK features
        toSpeak = text;
        if (speaker == null) {
            speaker = new TextToSpeech (ctx, this);
        } else {
            var p = new Dictionary<string,string> ();
            speaker.Speak (toSpeak, QueueMode.Flush, p);
        }
    }

    #region IOnInitListener implementation
    public void OnInit (OperationResult status)
    {
        if (status.Equals (OperationResult.Success)) {
            var p = new Dictionary<string,string> ();
            speaker.Speak (toSpeak, QueueMode.Flush, p);
        }
    }
    #endregion
}

再次不要忘记将其注册到 DependencyService

using Android.Speech.Tts;
using Xamarin.Forms;
using System.Collections.Generic;
using DependencyServiceSample.Droid;

[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.Droid{
    //... Rest of code

Windows Phone 实现

最后,对于 Windows Phone,可以使用此代码。

public class TextToSpeechImplementation : ITextToSpeech
{
    public TextToSpeechImplementation() {}

    public async void Speak(string text)
    {
        MediaElement mediaElement = new MediaElement();

        var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();

        SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Hello World");

        mediaElement.SetSource(stream, stream.ContentType);
        mediaElement.Play();
        await synth.SynthesizeTextToStreamAsync(text);
    }
}

再一次不要忘记注册它。

using Windows.Media.SpeechSynthesis;
using Windows.UI.Xaml.Controls;
using DependencyServiceSample.WinPhone;//enables registration outside of namespace

[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.WinPhone{
    //... Rest of code

在共享代码中实现

现在一切都准备好了! 最后,在共享代码中,你现在可以使用该界面调用此函数。在运行时,将注入与其运行的当前平台相对应的实现。

在此代码中,你将看到可能位于 Xamarin Forms 项目中的页面。它创建了一个按钮,通过使用 DependencyService 调用 Speak() 方法。

public MainPage ()
{
    var speak = new Button {
        Text = "Hello, Forms !",
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.CenterAndExpand,
    };
    speak.Clicked += (sender, e) => {
        DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");
    };
    Content = speak;
}

结果是当应用程序运行并单击按钮时,将说出提供的文本。

所有这一切都无需像编译器提示等那样做。你现在可以通过独立于平台的代码来统一访问平台特定功能。