xamarin 是否可以在应用程序级别挂钩到硬件键盘事件?

3npbholx  于 2022-12-07  发布在  其他
关注(0)|答案(4)|浏览(142)

我正在为iOSAndroidUWP开发Xamarin.Forms应用程序。
我希望在应用程序级别(而不是单个页面级别(因为它是Xamarin.Forms应用程序))挂钩硬件键盘事件,以便当用户按下键盘上的键时,我可以调用应用程序中的操作。
在Android上,我使用MainActivity上的以下事件来完成此操作:。

public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
    //process key press
    return base.OnKeyUp(keyCode, e);
}

Xamarin iOS有等价物吗?

odopli94

odopli941#

您可以使用KeyCommands跟踪硬件键盘上的按键。

按键命令

支持硬件键盘命令的响应器对象可以重新定义此属性,并使用它返回它所支持的UIKeyCommand对象的数组。每个键盘命令对象表示要识别的键盘序列和响应器在响应时要调用的操作方法。
从这个方法传回的按钮命令会套用到整个回应器链接。当按下符合按钮命令对象的按钮组合时,UIKit会浏览回应器链接,寻找实作Map动作方法的对象。它会在找到的第一个对象上呼叫该方法,然后停止行程事件。
在Xamarin.forms中,你必须在iOS平台上为ContentPage创建自定义的渲染器。然后可以在该页面渲染器中添加键命令。
如果您希望ViewController(Page)可以处理按键操作,而不仅仅是输入控件(如Entry),请使用canBecomeFirstResponder使ViewController成为第一响应者。

例如,iOS平台中ContentPage的自定义渲染器可能如下:

using System;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using KeyCommandsInXamarinForms.iOS;

[assembly: ExportRenderer(typeof(ContentPage), typeof(MyCustomPageRenderer))]
namespace KeyCommandsInXamarinForms.iOS
{
    public class MyCustomPageRenderer : PageRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            //Create your keycommand as you need.
            UIKeyCommand keyCommand1 = UIKeyCommand.Create(new NSString("1"), UIKeyModifierFlags.Command, new ObjCRuntime.Selector("Action:"));
            UIKeyCommand keyCommand2 = UIKeyCommand.Create(new NSString("\t"), 0, new ObjCRuntime.Selector("Action:"));
            //Add your keycommands
            this.AddKeyCommand(keyCommand1);
            this.AddKeyCommand(keyCommand2);
        }

        [Export("Action:")]
        private void Excute(UIKeyCommand keyCommand)
        {
            Console.WriteLine(String.Format("key pressed - {0}", keyCommand.Value);
        }

        //Enable viewcontroller to become the first responder, so it is able to respond to the key commands.
        public override bool CanBecomeFirstResponder
        {
            get
            {
                return true;
            }
        }
    }
}

请注意这一行,使用typeof(ContentPage)作为处理程序参数,则无需更改PCL中的任何内容:

[assembly: ExportRenderer(typeof(ContentPage), typeof(MyCustomPageRenderer))]

ckx4rj1h

ckx4rj1h2#

我需要在我的XamForms应用程序中允许数字输入+在末尾输入。下面是我在Xamarin Forms 3.0.0.482510 / Xamarin.iOS 11.10中解决这个问题的方法(这和Kevin的答案有点不同,因为我想在XamForms共享xaml项目中处理这个问题,而不是在iOS项目中):
在您的iOS项目中(例如,解决方案中名为'MobileProject'的Xamarin Forms共享项目),创建一个新类:

using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(MobileProject.MainPage), typeof (com.YourCompany.iOS.KeyboardHookRenderer))]
namespace com.YourCompany.iOS
{
public class KeyboardHookRenderer : PageRenderer
{
    private string _RecvValue = string.Empty;

    public override bool CanBecomeFirstResponder
    {
        get { return true; }
    }

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        string key = string.Empty;
        var selector = new ObjCRuntime.Selector("KeyRecv:");
        UIKeyCommand accelerator1 = UIKeyCommand.Create((NSString)"1", 0, selector);
        AddKeyCommand(accelerator1);
        UIKeyCommand accelerator2 = UIKeyCommand.Create((NSString)"2", 0, selector);
        AddKeyCommand(accelerator2);
        UIKeyCommand accelerator3 = UIKeyCommand.Create((NSString)"3", 0, selector);
        AddKeyCommand(accelerator3);

        ... etc as many as you need or use a loop based on key id...
    }

    [Export("KeyRecv:")]
    public void KeyRecv(UIKeyCommand cmd)
    {
        if (cmd == null)
            return;
        var inputValue = cmd.Input;
        if (inputValue == "\n" || inputValue == "\r")
        {
            ((MobileProject.MainPage) Element)?.HandleHardwareKeyboard(_RecvValue);
            _RecvValue = string.Empty;
        }
        else
        {
            _RecvValue += inputValue;
        }
    }
}
}

然后,在MainPage.xaml.cs中的共享应用程序中,您只需要:

/// <summary>
/// Handle hardware keys (from KeyboardHookRender.cs in iOS project)
/// </summary>
/// <param name="keys">Keys sent, including trailing Cr or Lf</param>
public void HandleHardwareKeyboard(string keys)
{
    SomeTextbox.Text = keys;
    // Whatever else you need to do to handle it
}
6fe3ivhb

6fe3ivhb3#

iOS的事情就在于它没有这样的方法,首先你需要了解你想要捕捉什么按钮,如果你想要捕捉音量按钮,那么你可以在这里找到答案:https://forums.xamarin.com/discussion/29648/detect-volume-change-from-hardware-buttons

public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        //KVO for outputVolume
        var session = AVAudioSession.SharedInstance();
        var errorOrNull = session.SetActive (true);
        if (errorOrNull != null) {
            //TODO: ...handle it
        }
        session.AddObserver (this, "outputVolume", NSKeyValueObservingOptions.New, IntPtr.Zero);

    }

    public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
    {
                   //TODO: Filter as appropriate, error-handling, etc.
        var volume = (float) (change ["new"] as NSNumber);

        volumeLabel.Text = volume.ToString();
    }

如果要捕获键盘事件,则必须订阅负责输入过程的视图。
您可以使用NotificationCenter来订阅可以在一个位置处理输入和接收通知的所有视图。

NSNotificationCenter.DefaultCenter.AddObserver (UITextField.TextFieldTextDidChangeNotification, (notification) =>
{
    Console.WriteLine ("Character received! {0}", notification.Object == TextField);
});
bcs8qyzn

bcs8qyzn4#

我这样做了:在主活动.cs中:

public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e)
    {
        if (keyCode == Keycode.VolumeDown)
        {
            var vm = MainViewModel.GetInstance().YourPageName;
            if (vm != null && App.Navigator.CurrentPage.GetType().Name == "YourPagePage")
            {
                vm.GuardarRecorrido();
                return true;
            }
        }

        return base.OnKeyUp(keyCode, e);
    }

我要求的名称,所以卷键只在该页运行。

相关问题