Подтвердить что ты не робот

UITextField, текст немного сбивается, когда начинается редактирование

У меня здесь странная проблема. У меня есть UITextFields в ячейках таблицы. Когда я выбираю поле, текст перескакивает очень слабо:

введите описание изображения здесь

Шрифт является системным по умолчанию 17. У меня adjust to fit включен в размере 17. Я попытался отключить adjust to fit, и есть еще прыжок. Я пробовал использовать разные стили границ, и это тоже не имеет значения. Я попытался отключить клип до предела, он все еще прыгает. Я также попытался сделать раму выше (намного выше), и она все еще прыгает. Единственное, что работает, - это сделать размер шрифта намного меньше, например 13. Что я здесь делаю неправильно? Если я могу сделать шрифт более мелким, чтобы исправить прыжок, то почему бы не сделать кадр более крупным? Любые указатели на это были бы действительно оценены. Спасибо!

4b9b3361

Ответ 1

Я должен признать, что я всегда видел это маленькое подпрыгивание во время моих событий, но я никогда не расследую его. Некоторые моменты, которые я использовал для репликации вашей проблемы:

  • два текстовых поля с настройками и настройками по умолчанию
  • с использованием стандартного шрифта по умолчанию и изменить его размер от 13 до 25 только для проверить поведение

Я предполагаю, что есть другие способы решения вашей проблемы, но я не нахожу быстрого свойства, чтобы остановить этот небольшой "прыжок" текста. Я решил проанализировать текущий UITextField ($ xcrun swift -version = Swift 3.1), чтобы увидеть его состав:

import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var myTextField: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        myTextField.delegate = self
    }
    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("\ntextFieldDidBeginEditing")
        showLayersDescription()
    }
    func textFieldDidEndEditing(_ textField: UITextField) {
        print("\ntextFieldDidEndEditing")
        showLayersDescription()
    }
    func showLayersDescription() {
        myTextField.layer.sublayers?.forEach{ print($0.debugDescription)}
    }
}

где myTextField по существу является одним из двух текстовых полей

Вывод с использованием размера шрифта 17:

введите описание изображения здесь

По существу, есть 3 CALayer:

  • слой с фреймом = CGRect (0 0; 252 30), который имеет _UITextFieldRoundedRectBackgroundViewNeue в качестве делегата, который имеет одинаковое измерение нашего текстового поля
  • слой с рамкой = CGRect (7 2; 238 26), который показан только в нашем textFieldDidBeginEditing и имеет UIFieldEditor в качестве делегата что, по-видимому, отвечает за часть редактирования.
  • слой, который отображается только в textFieldDidEndEditing с frame = CGRect.zero и с делегатом UITextFieldLabel

Если я пишу что-то в первый текстовый фильтр, то я перехожу к следующему текстовому полю, ничего не произошло, но если я вернусь к первому текстовому полю, а затем ко второму , слой с фреймом, равным CGRect.zero, измените на frame = CGRect(7 0.5; 238 27.5)

Это маленькая высота (0.5), которую мы можем видеть в начале и в конце нашего редактирования.

Мы можем попытаться уточнить отладку и перехватить эти слои с помощью расширения:

extension UITextField
{
    func debugLayers() {
        print("We have the follow layers:")
        let FieldEditor: AnyObject.Type = NSClassFromString("UIFieldEditor")!
        let LabelLayer: AnyObject.Type = NSClassFromString("_UILabelLayer")!
        let TextFieldRoundRect: AnyObject.Type = NSClassFromString("_UITextFieldRoundedRectBackgroundViewNeue")!
        self.layer.sublayers?.forEach{
            if ($0.delegate?.self.isKind(of: TextFieldRoundRect))! { print("- layer with _UITextFieldRoundedRectBackgroundViewNeue as delegate have frame:\($0.frame)") }
            if ($0.delegate?.self.isKind(of: FieldEditor))! { print("- layer with UIFieldEditor as delegate have frame:\($0.frame)") }
            if $0.self.isKind(of: LabelLayer) { print("- layer is kind of _UILabelLayer have frame:\($0.frame)") }
        }
    }
}

Итак, мы имеем, например:

import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var myTextField: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        myTextField.delegate = self
    }
    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("\ntextFieldDidBeginEditing")
        myTextField.debugLayers()
    }
    func textFieldDidEndEditing(_ textField: UITextField) {
        print("\ntextFieldDidEndEditing")
        myTextField.debugLayers()
    }
}

Вывод всегда с размером шрифта 17:

введите описание изображения здесь

Как мы видим, мы всегда имеем эту 0,5 разницу в высоте в этом слое.

Выполняя другие попытки, я видел, что это поведение произошло только в том случае, если размер по умолчанию составляет от 13 до 17, менее 13 и от 18 до 25 это не произошло, если вы сообщаете на свой вопрос.

Решение:

Я думаю, что лучший способ перехватить и попытаться исправить это, чтобы создать новое расширение:

extension UITextField
{
    override open func layoutSubviews() {
        super.layoutSubviews()
        let FieldEditor: AnyObject.Type = NSClassFromString("UIFieldEditor")!
        let LabelLayer: AnyObject.Type = NSClassFromString("_UILabelLayer")!
        self.layer.sublayers?.forEach{
            if ($0.delegate?.self.isKind(of: FieldEditor))! {
                var f = $0.frame
                f.origin.y = 0.0
                $0.frame = f
            }
            if $0.self.isKind(of: LabelLayer) {
                var layerFrame = CGRect.zero
                layerFrame.origin = self.editingRect(forBounds: self.bounds).origin
                layerFrame.size = self.editingRect(forBounds: self.bounds).size
                if let size = self.font?.pointSize, 14 ... 17 ~= size {
                    layerFrame.origin.y = -0.5
                } else {
                    layerFrame.origin.y = 0.0
                }
                $0.frame = layerFrame
            }
        }
    }
} 

Окончательные соображения:

Это расширение подавляет небольшое "перескакивание" текста во время изменения на другой текстовый экран. Это, вероятно, для баланса:

contentsCenter = CGRect (0.485 0.485; 0.000588235 0.000588235)

что и второй, и третий уровень имеют эту группу размеров шрифтов. Как вы видите в расширении, я установил ноль и начало высоты слоя с делегатом UIFieldEditor (до версии 2.0 как высота), потому что это связано с этим изменением, я сделал это, чтобы сбалансировать различия ограничений.

Обновление для действующего и утвержденного расширения:

Я прочитал ваш комментарий, поэтому я проанализировал в глубине ситуации о слоях: я нашел, что слой, у которого есть пробел -0,5 height НИКОГДА, не подпадает под подушки, когда другие ВСЕГДА представляют один подуровень (имеют UIFieldEditor в качестве делегата), поэтому мы можем легко исправить расширение следующим образом:

extension UITextField
{
    override open func layoutSubviews() {
        super.layoutSubviews()
        self.layer.sublayers?.forEach{
            if let subs = $0.sublayers, subs.count>0 {
                var f = $0.frame
                f.origin.y = 0.0
                $0.frame = f
            } else {
                var layerFrame = CGRect.zero
                layerFrame.origin = self.editingRect(forBounds: self.bounds).origin
                layerFrame.size = self.editingRect(forBounds: self.bounds).size
                if let size = self.font?.pointSize, 14 ... 17 ~= size {
                    layerFrame.origin.y = -0.5
                } else {
                    layerFrame.origin.y = 0.0
                }
                $0.frame = layerFrame
            }
        }
    }
}

Я тестировал это новое расширение, и он ведет себя правильно, как старый.

Ответ 2

Изменение свойства contentVerticalAlignment UITextField может привести к этому поведению.

Вы можете добавить символическую точку останова

[UITextField setContentVerticalAlignment:]

если вы измените свойство contentVerticalAlignment UITextField случайно.

Ответ 3

Итак, вы, возможно, наткнулись на что-то очень странное. Если вы подклассифицируете свой UITextField на что-то вроде этого.

class NonJumpyTextField: UITextField {

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        var previousRect = super.textRect(forBounds: bounds)

        print("Bounds: \(bounds)")
        print("TextRect: \(previousRect)")
        print("TextFieldRect \(frame)")

        //not reccomended but does seem to help
        previousRect.origin.y = 2.25

        return previousRect
    }
}

и прочитайте журналы, в которых вы получаете некоторое нечетное поведение при его редактировании.

Bounds: (0.0, 0.0, 100.0, 100.0)
TextRect: (7.0, 2.0, 86.0, 96.0)
TextFieldRect (64.0, 66.0, 97.0, 30.0)
Bounds: (0.0, 0.0, 97.0, 30.0)
TextRect: (7.0, 2.0, 83.0, 26.0)
TextFieldRect (64.0, 66.0, 97.0, 30.0)
Bounds: (0.0, 0.0, 100.0, 100.0)
TextRect: (7.0, 2.0, 86.0, 96.0)
TextFieldRect (64.0, 66.0, 97.0, 30.0)

после редактирования

Bounds: (0.0, 0.0, 97.0, 30.0)
TextRect: (7.0, 2.0, 83.0, 26.0)
TextFieldRect (64.0, 66.0, 97.0, 30.0)
Bounds: (0.0, 0.0, 100.0, 100.0)
TextRect: (7.0, 2.0, 86.0, 96.0)
TextFieldRect (64.0, 66.0, 97.0, 30.0)

В образце я работал с грубым принуждением, положение y действительно помогло, но не рекомендовалось. Я подозреваю, что проблема связана с тем, что границы кажутся случайными 100 х 100. Надеюсь, что-то здесь поможет вам найти решение, которое будет работать для вас.

Ответ 4

Вы можете попытаться увеличить высоту inputView в UITextField.

UITextField имеет inputView, который будет отображаться, когда объект становится первым ответчиком.