0

Colleagues,

I develop a custom keyboard. There was a problem with the speed of switching between types of keyboards (letters, numbers, special characters). This is due to the fact that each time the button is re-drawn. NSLayoutConstraint I set up as follows:

  1. There is a class KeyboardViewController. He adds to his KeyboardView

        let left = NSLayoutConstraint(item: self.keyboardView, attribute: .Left, relatedBy: .Equal,
                toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
            let top = NSLayoutConstraint(item: self.keyboardView, attribute: .Top, relatedBy: .Equal,
                toItem: placeForSuggestion!, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
            let right = NSLayoutConstraint(item: self.keyboardView, attribute: .Right, relatedBy: .Equal,
                toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0.0)
            let bottom = NSLayoutConstraint(item: self.keyboardView, attribute: .Bottom, relatedBy: .Equal,
                toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
            let height = NSLayoutConstraint(item: self.keyboardView, attribute: .Height, relatedBy: .Equal,
                toItem: self.view, attribute: .Height, multiplier: 1.0, constant: 216)
            left.priority = 999
            right.priority = 999
            bottom.priority = 999
            top.priority = 999
            height.priority = 999
            self.view.addConstraints([left, right, top, bottom, height])
    
  2. In the class KeyboardView, buttons are added as follows:

    super.updateConstraints()
    
    if !layoutConstrained {
    
        var lastRowView: UIView? = nil
        for (rowIndex, keyRow) in keyRows.enumerate() {
            var lastKeyView: UIView? = nil
            for (keyIndex, key) in keyRow.enumerate() {
    
                var relativeWidth: CGFloat = 0.0;
                switch key.type! {
                case .ModeChange:
                    relativeWidth = 0.92/8
                case .KeyboardChange:
                    relativeWidth = 0.92/8
                case .Space:
                    relativeWidth = 3.92/8
                case .Return:
                    relativeWidth = 1.84/8
                default:
                    relativeWidth = 0.0
                }
    
                key.translatesAutoresizingMaskIntoConstraints = false
    
                if let lastView = lastKeyView {
                    let left: NSLayoutConstraint!
                    if (key.keyCap == "Z" || (key.keyCap == "backspace" && keyRow[keyIndex - 1].keyCap == "M")) {
                        left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
                            toItem: lastView, attribute: .Right, multiplier: 1.0, constant: englishMZSpace)
                    } else {
                        left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
                            toItem: lastView, attribute: .Right, multiplier: 1.0, constant: distanceBetweenKeys)
                    }
                    let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy: .Equal,
                        toItem: lastView, attribute: .Top, multiplier: 1.0, constant: 0.0)
                    let bottom = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
                        toItem: lastView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
                    var width: NSLayoutConstraint?
                    if relativeWidth == 0.0 {
                        width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
                            toItem: lastView, attribute: .Width, multiplier: 1.0, constant: 0.0)
                    } else {
                        width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
                            toItem: self, attribute: .Width, multiplier: relativeWidth, constant: 0.0)
                    }
                    self.addConstraints([left, top, bottom, width!])
                } else {
                    let leftEdge: NSLayoutConstraint
                    if key.keyCap == "A" {
                        leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
                            toItem: self, attribute: .Left, multiplier: 1.0, constant: englishALSpace)
                    } else {
                        leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
                            toItem: self, attribute: .Left, multiplier: 1.0, constant: leftRightSpace)
                    }
    
                    self.addConstraint(leftEdge)
    
                    if let lastRow = lastRowView {
                        let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
                            toItem: lastRow, attribute: .Bottom, multiplier: 1.0, constant: rowTopInset)
                        let height = NSLayoutConstraint(item: key, attribute: .Height, relatedBy: .Equal,
                            toItem: lastRow, attribute: .Height, multiplier: 1.0, constant: 0.0)
    
                        self.addConstraints([top, height])
                    } else {
                        let topEdge =  NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
                            toItem: self, attribute: .Top, multiplier: 1.0, constant: rowTopInset)
    
                        self.addConstraint(topEdge)
                    }
    
                    if rowIndex == keyRows.count - 1 {
                        let bottomEdge = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
                            toItem: self, attribute: .Bottom, multiplier: 1.0, constant: -rowBottomInset)
                        self.addConstraint(bottomEdge)
                    }
    
                    lastRowView = key
                }
    
                if keyIndex == keyRow.count - 1 {
                    let rightEdge: NSLayoutConstraint
                    if key.keyCap == "L" {
                        rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
                            toItem: self, attribute: .Right, multiplier: 1.0, constant: -englishALSpace)
                    } else {
                        rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
                            toItem: self, attribute: .Right, multiplier: 1.0, constant: -leftRightSpace)
                    }
                    self.addConstraint(rightEdge)
                }
    
                lastKeyView = key
            }
        }
        layoutConstrained = true
    }
    

I see 2 variants of optimization:

  1. After the first run to cache all NSLayoutConstraint
  2. Use CGRectMake instead NSLayoutConstraint

You may be able to offer more relevant options?

In this video I try to switch keyboard and print quickly https://yadi.sk/i/36YxEwgtmHJVd

Ga77ett
  • 11
  • 4

1 Answers1

0

It seems pretty fast to me in the video.

However, instead of re-creating the layout constraints every time I would recommend to create each keyboard type once, and then just switch between the existing keyboards. Regarding the small views that shouldn't be a memory issue, and it's a lot better than recreating and deleting constraints all the time.

Alternatively, if the key amount stays (almost) the same, you could just change the constraint's values and even animate the change of key positions for a maybe nice effect.

TheEye
  • 9,280
  • 2
  • 42
  • 58