【问题标题】:How do I implement iOS "shake to undo" in Xamarin Forms, only on apple devices?如何在 Xamarin Forms 中仅在苹果设备上实现 iOS“摇晃撤消”?
【发布时间】:2018-01-17 22:41:46
【问题描述】:

这篇博客描述了如何执行shake to undo,但是我想创建某种可以重用此代码的基类(以 Xamarin 形式):

#region respond to shaking (OS3+)
public override bool CanBecomeFirstResponder {
   get {
      return true;
   }
}
public override void ViewDidAppear (bool animated)
{
   base.ViewDidAppear (animated);
   this.BecomeFirstResponder();
}
public override void ViewWillDisappear (bool animated)
{
   this.ResignFirstResponder();
   base.ViewWillDisappear (animated);
}
public override void MotionEnded (UIEventSubtype motion, UIEvent evt)
{
   Console.WriteLine("Motion detected");
   if (motion ==  UIEventSubtype.MotionShake)
   {
      Console.WriteLine("and was a shake");
      // Do your application-specific shake response here...
      Update();   
   }
}
#endregion

我不确定从哪里开始...创建一个仅适用于 iOS 的基类。

对于所有视图的基类的此运行时实现,是否有任何类型的依赖注入可以与 XamarinForms 一起使用?

【问题讨论】:

  • 您可以创建一个通用的 BasePage 类,所有页面都从该类继承,并且它们使用自定义渲染器仅在 iOS 上添加抖动行为
  • 您在哪里实施 Shake To Undo?它默认为 iOS 的Xamarin.Forms.Entry 控件实现。
  • @BrandonMinnick 想要的效果是让这个弹出窗口适用于所有其他情况:"Would you like to submit a bug report?"
  • 知道了!因此,您正在寻找 Xamarin.Forms 以在用户摇动设备时显示弹出警报。对吗?
  • LamonteCristo - 如果您想要实现以下示例代码,请告诉我!我总是可以调整答案来帮助你!

标签: xamarin.ios xamarin.forms prism


【解决方案1】:

说明

好消息是我们可以利用Device Motion NuGet Package 代替自定义渲染器!

我们可以在NavgiationPage 基类中实现摇动功能,并将其用作我们的MainPage

我还在 App 构造函数中包含了逻辑,它只为 iOS 实现了 ShakeListenerNavigationPage

代码

using System;
using System.Diagnostics;

using Xamarin.Forms;

using DeviceMotion.Plugin;
using DeviceMotion.Plugin.Abstractions;

namespace YourNamespace
{

    public class App : Application
    {
        public App()
        {
            NavigationPage navigationPage;
            switch(Device.RuntimePlatform)
            {
                case Device.iOS:
                    navigationPage = new ShakeListenerNavigationPage(new MyPage());
                    break;
                default:
                    navigationPage = new NavigationPage(new MyPage());
                    break;
            }

            MainPage = navigationPage;
        }
    }

    public class ShakeListenerNavigationPage : NavigationPage
    {
        #region Constant Fields
        const int _shakeDetectionTimeLapse = 250;
        readonly double _shakeThreshold;
        #endregion

        #region Fields
        bool _hasUpdated;
        DateTime _lastUpdate;
        double _lastX, _lastY, _lastZ;
        #endregion

        #region Constructors
        public ShakeListenerNavigationPage(Page root) : base(root)
        {
            switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    _shakeThreshold = 20;
                    break;
                default:
                    _shakeThreshold = 800;
                    break;
            }


            CrossDeviceMotion.Current.Start(MotionSensorType.Accelerometer, MotionSensorDelay.Default);
            CrossDeviceMotion.Current.SensorValueChanged += HandleSensorValueChanged;
        }
        #endregion

        #region Methods
        void HandleSensorValueChanged(object sender, SensorValueChangedEventArgs e)
        {
            if (e.SensorType == MotionSensorType.Accelerometer)
            {
                double x = ((MotionVector)e.Value).X;
                double y = ((MotionVector)e.Value).Y;
                double z = ((MotionVector)e.Value).Z;

                var currentTime = DateTime.Now;

                if (_hasUpdated == false)
                {
                    _hasUpdated = true;
                    _lastUpdate = currentTime;
                }
                else
                {
                    var hasMinimumTimeElapsed = (currentTime - _lastUpdate).TotalMilliseconds > _shakeDetectionTimeLapse;

                    if (!hasMinimumTimeElapsed)
                        return;

                    _lastUpdate = currentTime;

                    var timeSinceLastShakeInMilliseconds = (currentTime - _lastUpdate).TotalMilliseconds;
                    var totalMovementDistance = x + y + z - _lastX - _lastY - _lastZ;
                    var shakeSpeed = Math.Abs(totalMovementDistance) / timeSinceLastShakeInMilliseconds * 10000;

                    Debug.WriteLine($"Shake Speed: {shakeSpeed}");

                    if (shakeSpeed > _shakeThreshold)
                        HandleShake();
                }

                _lastX = x;
                _lastY = y;
                _lastZ = z;
            }
        }

        void HandleShake()
        {
            Device.BeginInvokeOnMainThread(async () => await DisplayAlert("Shake Detected", "You shook your device!", "Ok"));
        }
        #endregion
    }
}

示例应用

这是一个示例 Xamarin.Forms 应用程序,我在其中实现了此功能! https://github.com/brminnick/InvestmentDataSampleApp

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 2019-08-26
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多