Swift iOS键盘扩展中屏幕左侧的动画延迟

Swift iOS键盘扩展中屏幕左侧的动画延迟,swift,core-animation,ios-app-extension,Swift,Core Animation,Ios App Extension,我正在为iOS开发键盘扩展。然而,我有一些奇怪的问题,动画/层没有立即出现在屏幕最左边。我使用层/动画在用户按键时显示“工具提示”。对于除A和Q之外的所有关键点,工具提示都会立即显示,但对于这两个关键点,在层和动画出现之前似乎有一点延迟。这只发生在触地时,如果我滑入Q或命中区域,工具提示会立即渲染。我的调试表明,代码对所有键的执行完全相同,但对这两个键没有立即的效果 有没有关于屏幕左边缘是否有什么特别的东西可能导致这种行为的想法?还是我做了一些愚蠢的事情可能是导致这一切的原因 这是触发工具提示渲

我正在为iOS开发键盘扩展。然而,我有一些奇怪的问题,动画/层没有立即出现在屏幕最左边。我使用层/动画在用户按键时显示“工具提示”。对于除A和Q之外的所有关键点,工具提示都会立即显示,但对于这两个关键点,在层和动画出现之前似乎有一点延迟。这只发生在触地时,如果我滑入Q或命中区域,工具提示会立即渲染。我的调试表明,代码对所有键的执行完全相同,但对这两个键没有立即的效果

有没有关于屏幕左边缘是否有什么特别的东西可能导致这种行为的想法?还是我做了一些愚蠢的事情可能是导致这一切的原因

这是触发工具提示渲染的触摸处理代码的一部分:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if(!shouldIgnoreTouches()) {
        for touch in touches {
            let location = (touch ).locationInView(self.inputView)

            // pass coordinates to offset service to find candidate keys
            let keyArray = keyOffsetService.getKeys(_keyboardLayout!, location: location)
            let primaryKey = keyArray[0]

            if primaryKey.alphaNumericKey != nil {
                let layers = findLayers(touch )

                if layers.keyLayer != nil {
                    graphicsService.animateKeyDown(layers.keyLayer as! CATextLayer, shieldLayer: layers.shieldLayer)
                    _shieldsUp.append((textLayer:layers.keyLayer, shieldLayer:layers.shieldLayer))
                }
            }
         }
    }
}
取消隐藏工具提示层:

private func keyDownShields(layer:CATextLayer, shieldLayer:CALayer) {
    shieldLayer.hidden = false
    shieldLayer.setValue(true, forKey: "isUp")
    shieldLayer.zPosition = 1
    shieldLayer.removeAllAnimations()
    layer.setValue(true, forKey: "isUp")
}

这是由iOS 9中的一项功能造成的,该功能允许用户在向右滑动的同时强制按下屏幕的左边缘来切换应用程序

您可以通过禁用3D touch来关闭此功能,但这并不是一个解决方案


我不知道有任何API允许您重写此行为。

官方解决方案正在重写您的
UIInputViewController的
首选屏幕边缘延迟系统手势

然而,它至少在iOS 13上似乎不起作用。据我所知,发生这种情况的原因是,至少在iOS 13上,当在
UIInputViewController
内部重写时,
preferredScreenedges延迟系统手势
无法正常工作

在常规视图控制器中重写此属性时,它将按预期工作:

override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
    return [.left, .bottom, .right]
}
不过,对于
UIInputViewController
,情况并非如此

UPD:看起来,手势识别器仍将获得
。已开始
状态更新,无延迟。因此,您可以添加一个自定义手势识别器来处理触摸事件,而不是遵循下面相当混乱的解决方案

通过向控件视图添加
uilongpressurerecognizer
minimumPressDuration=0
,可以快速测试此功能

另一种解决方案:

我最初的解决方法是调用
touch-down
effects-inside
hitTest(upoint:CGPoint,with-event:UIEvent?)->UIView?
,即使视图的触摸延迟,也会调用该方法

当“真实”触地事件在大约0.4秒后触发或与
触地事件同时触发时,您必须忽略“真实”触地事件。此外,只有在测试点位于~20pt横向边缘内的情况下,才应用此方法可能更好

因此,例如,对于屏幕宽度相等的视图,实现可能如下所示:

let edgeProtectedZoneWidth: CGFloat = 20

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let result = super.hitTest(point, with: event)

    guard result == self else {
        return result
    }

    if point.x < edgeProtectedZoneWidth || point.x > bounds.width-edgeProtectedZoneWidth
    {
        if !alreadyTriggeredFocus {
            isHighlighted = true
        }
        triggerFocus()
    }

    return result
}

private var alreadyTriggeredFocus: Bool = false

@objc override func triggerFocus() {
    guard !alreadyTriggeredFocus else { return }
    super.triggerFocus()
    alreadyTriggeredFocus = true
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesCancelled(touches, with: event)

    alreadyTriggeredFocus = false
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)

    alreadyTriggeredFocus = false
}
让边缘保护分区宽度:CGFloat=20
覆盖func hitTest(uPoint:CGPoint,带有事件:UIEvent?->UIView?{
让结果=super.hitTest(点,带:事件)
保护结果==自身或其他{
返回结果
}
如果点.xbounds.width-edgeProtectedZoneWidth
{
如果!已准备好触发焦点{
isHighlighted=true
}
triggerFocus()
}
返回结果
}
私有变量alreadyTriggeredFocus:Bool=false
@objc override func triggerFocus(){
守卫!alreadyTriggeredFocus else{return}
super.triggerFocus()
alreadyTriggeredFocus=true
}
覆盖功能触摸已取消(touchs:Set,带有事件:UIEvent?){
super.touchscancelled(触摸,带有:事件)
alreadyTriggeredFocus=false
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
super.touchesend(触摸,带有:事件)
alreadyTriggeredFocus=false
}

…其中,
triggerFocus()
是您在
触地事件上调用的方法。或者,您可以覆盖
touchesbeated(:with:)

谢谢,这很有道理。我想iOS10的行为已经改变了,因为问题已经解决了。我的iPhone 6s iOS 11版本仍然存在这个问题。据我所知,你知道如何在我的应用程序中禁用3D触摸吗???@Netero?你不能。“至少我们从来没能对此做点什么。”马拉金谢谢你!令人失望的是:/我已经在提交了一份雷达文件,表明苹果提供了一个类似于能够设置的API:self.navigationController?.interactiveEPGEsturerecognizer.enabled=false
let edgeProtectedZoneWidth: CGFloat = 20

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let result = super.hitTest(point, with: event)

    guard result == self else {
        return result
    }

    if point.x < edgeProtectedZoneWidth || point.x > bounds.width-edgeProtectedZoneWidth
    {
        if !alreadyTriggeredFocus {
            isHighlighted = true
        }
        triggerFocus()
    }

    return result
}

private var alreadyTriggeredFocus: Bool = false

@objc override func triggerFocus() {
    guard !alreadyTriggeredFocus else { return }
    super.triggerFocus()
    alreadyTriggeredFocus = true
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesCancelled(touches, with: event)

    alreadyTriggeredFocus = false
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)

    alreadyTriggeredFocus = false
}