2017-11-06 1 views
0

入力アクセサリビューの高さをアニメーション化するときに、私が異常な動作をしています。私は間違って何をしていますか?入力アクセサリビューの高さをアニメーション化するにはどうすればよいですか?

私はUIInputViewサブクラス(InputView)を1つのサブビューで作成します。 InputViewとそのintrinsicContentSizeの高さは、サブビューによって制御されます。 isVisibleがの場合はInputViewは50ピクセル、高さが0の場合はisVisibleがfalseです。

import UIKit 

class InputView: UIInputView { 
    private let someHeight: CGFloat = 50.0, zeroHeight: CGFloat = 0.0 
    private let subView = UIView() 
    private var hide: NSLayoutConstraint?, show: NSLayoutConstraint? 

    var isVisible: Bool { 
     get { 
      return show!.isActive 
     } 
     set { 
      // Always deactivate constraints before activating conflicting ones 
      if newValue == true { 
       hide?.isActive = false 
       show?.isActive = true 
      } else { 
       show?.isActive = false 
       hide?.isActive = true 
      } 
     } 
    } 

    // MARK: Sizing 

    override func sizeThatFits(_ size: CGSize) -> CGSize { 
     return CGSize(width: size.width, height: someHeight) 
    } 

    override var intrinsicContentSize: CGSize { 
     return CGSize.init(width: bounds.size.width, height: subView.bounds.size.height) 
    } 

    // MARK: Initializers 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

    override init(frame: CGRect, inputViewStyle: UIInputViewStyle) { 
     super.init(frame: frame, inputViewStyle: inputViewStyle) 

     addSubview(subView) 
     subView.backgroundColor = UIColor.purple 

     translatesAutoresizingMaskIntoConstraints = false 
     subView.translatesAutoresizingMaskIntoConstraints = false 

     subView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true 
     subView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true 
     subView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true 
     subView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true 

     show = subView.heightAnchor.constraint(equalToConstant: someHeight) 
     hide = subView.heightAnchor.constraint(equalToConstant: zeroHeight) 
     hide?.isActive = true 
    } 
} 

ボタンが押されたときにホスト・ビュー・コントローラは、1秒のアニメーションブロック内isVisibleをトグルします。

import UIKit 

class MainViewController: UIViewController { 
    let testInputView = InputView.init(frame: .zero, inputViewStyle: .default) 

    @IBAction func button(_ sender: AnyObject) { 
     UIView.animate(withDuration: 1.0) { 
      let isVisible = self.testInputView.isVisible 
      self.testInputView.isVisible = !isVisible 
      self.testInputView.layoutIfNeeded() 
     } 
    } 

    override var canBecomeFirstResponder: Bool { 
     return true 
    } 

    override var inputAccessoryView: UIView? { 
     return testInputView 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
    } 
} 

Iが円滑isVisibletrueに設定し、かつ円滑isVisiblefalseに設定されているときに、画面のボタンに縮小された画面のボタンから成長する入力アクセサリビューを期待。代わりにキーボードの背景オーバーレイは、isVisibletrueで、入力アクセサリビューがそのフレームのセンターから成長するとすぐに、完全な50ピクセルの高さで表示されます。

The purple box is not growing from the bottom of the screen and is surrounded by the keyboard overlay background

縮小し、入力アクセサリビューは瞬時にスムーズにアニメーションを続行する前に、その高さの一部を失います。

この予期しない動作を表示するinput accessory view demonstration projectを作成しました。しかし、それはAppleがデザインを変更した場合、スーパーを呼び出すことをお勧めことはない

UIView.animate(withDuration: 1.0) { 
     let isVisible = self.testInputView.isVisible 
     self.testInputView.isVisible = !isVisible 
     self.testInputView.superview?.superview?.layoutIfNeeded() 
    } 

答えて

1

これはあなたの正しいアニメーションを提供します。だからもっと良い答えがあるかもしれません。

print(testInputView.superview) // UIInputSetHostView 

print(testInputView.superview?.superview) // UIInputSetContainerView 

EDIT::追加A SAFER SOLUTION

を私はUIInputViewとあまり慣れていないんだ

これはsuperviewsが表すものです。

ステップ1:アニメーションブロック外
移動のisVisibleのみサブビューの高さ変化をアニメーション化するのではなく、スーパービューを呼び出すことなく、それを解決する一つの方法は次のようになります。

@IBAction func button(_ sender: AnyObject) { 
    let isVisible = self.testInputView.isVisible 
    self.testInputView.isVisible = !isVisible 
    UIView.animate(withDuration: 1.0) { 
     self.testInputView.layoutIfNeeded() 
    } 
} 

ステップ2: InputView代わりのintrinsicContentSizeの高さ制約を変更し、あなたのInputViewで新しいメソッドを作成します。

private func updateHeightConstraint(height: CGFloat) { 
    for constraint in constraints { 
     if constraint.firstAttribute == .height { 
      constraint.constant = height 
     } 
    } 
    self.layoutIfNeeded() 
} 

ステップ3: とセッターの内側にそのメソッドを呼び出します。

if newValue == true { 
    updateHeightConstraint(height: someHeight) 
    hide?.isActive = false 
    show?.isActive = true 
} else { 
    updateHeightConstraint(height: zeroHeight) 
    show?.isActive = false 
    hide?.isActive = true 
} 

ステップ4:initの中 最後にいくつかの変更。

override init(frame: CGRect, inputViewStyle: UIInputViewStyle) { 
    super.init(frame: frame, inputViewStyle: inputViewStyle) 

    addSubview(subView) 

    backgroundColor = .clear 
    subView.backgroundColor = UIColor.purple 

    subView.translatesAutoresizingMaskIntoConstraints = false 

    subView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true 
    subView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true 
    subView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true 

    show = subView.heightAnchor.constraint(equalToConstant: someHeight) 
    hide = subView.heightAnchor.constraint(equalToConstant: zeroHeight) 
    hide?.isActive = true 
} 

結論: InputViewのこの結果は、それが紫色のサブビューの高さをアニメーション化する前に高さを変更します。唯一の欠点は、UIInputViewです.UIInputViewは、デフォルトで灰色の背景があり、クリアに変更することはできません。ただし、VCと同じbackgroundColorを使用できます。

しかし、InputAccessoryViewとして通常のUIViewを使用する必要がある場合は、デフォルトでUIColor.clearになります。最初の "ジャンプ"より気付かれません。

+0

私はこれを最善の答え*として受け入れていませんが、誰かがより安全な修正を明らかにすることを期待していますが、これは美しく機能します。スーパービューを見つける方法のヒントも非常に便利です。 –

関連する問題