Ответ 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
}
}
}
}
Я тестировал это новое расширение, и он ведет себя правильно, как старый.