Использование собственного шрифта в UITextField приводит к его небольшому смещению при доступе - есть ли исправление? - PullRequest
23 голосов
/ 15 июня 2011

У меня есть собственный шрифт в UITextField, и я заметил, что когда к нему обращаются (когда появляется клавиатура), текст смещается вниз на очень небольшое количество - возможно, на пиксель или два или три. (Конечно, я не могу измерить его, но мне достаточно заметить.) А потом, когда клавиатура закрыта, она снова поднимается.

Я попытался очистить поле при редактировании (которое скрывает проблему начального сдвига вниз), но это не решило проблему. Я также просмотрел различные атрибуты в IB и попытался изменить несколько, но проблема все еще сохраняется. Я получаю одинаковые результаты в симуляторе и на моем iPad2.

(Поле хорошо видно на клавиатуре, так что не весь вид движется в сторону - это просто содержимое этого конкретного текстового поля.)

Я уверен, что причиной этого является нестандартный шрифт - без него не обойтись.

Есть идеи, как решить эту проблему? Я подумал, что мне может понадобиться создать текстовое поле программно, а не в IB - и я знаю, что, вероятно, мне следует попробовать это, прежде чем задавать вопрос здесь, но я не хочу идти на все эти неприятности, если это не произойдет решить проблему.

Любой совет приветствуется!

Ответы [ 10 ]

16 голосов
/ 10 апреля 2012

У меня также была эта проблема.

Чтобы исправить, создайте подкласс UITextField и примените следующие методы для настройки расположения текста, когда редактирование и редактирование не выполняются.

- (CGRect)textRectForBounds:(CGRect)bounds {

    return CGRectInset( bounds , 8 , 8 );
}

- (CGRect)editingRectForBounds:(CGRect)bounds {

    return CGRectInset( bounds , 8 , 5 );
}
3 голосов
/ 10 сентября 2012

Мое решение в том же духе, что и в McDJ, но с несколько иным поворотом. Подкласс UITextField и переопределить только эти:

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
  return CGRectOffset( [self editingRectForBounds:bounds], 0, 2 );
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
  return CGRectOffset( [super editingRectForBounds:bounds], 0, -2 );
}

При использовании собственного шрифта, который я использую, 2 точки - это правильная вертикальная регулировка, помогая заполнителю, «статическому» и «редактированию» текста оставаться на одной вертикальной линии.

2 голосов
/ 13 апреля 2017

К сожалению, ни один из ответов не сработал для меня.

@ ответ blackjacx работал, но только иногда: (

Я начал отладку, и вот что я обнаружил:

1 - Реальная проблема, похоже, связана с частным подпредставлением UITextField типа UIFieldEditorContentView

UITextField view hieararchy

Ниже вы можете видеть, что y его подпредставления не совпадает с UITextField самого:

Y is not set to 0

Осознав это, я нашел следующий обходной путь:

override func layoutSubviews() {
    super.layoutSubviews()
    fixMisplacedEditorContentView()
}

func fixMisplacedEditorContentView() {
    if #available(iOS 10, *) {
        for view in subviews {
            if view.bounds.origin.y < 0 {
                view.bounds.origin = CGPoint(x: view.bounds.origin.x, y: 0)
            }
        }
    }
}

Вам потребуется создать подкласс UITextField и переопределить layoutSubviews, чтобы добавить возможность вручную установить 0 y любого подпредставления, для которого установлено отрицательное значение. Поскольку эта проблема не возникает в iOS 9, описанной ниже, я добавил проверку, чтобы обойти ее, только когда она установлена ​​в iOS 10.

Результат вы можете увидеть ниже:

Working properly

2 - Этот обходной путь не работает, если пользователь выбирает поддиапазон текста (selectAll работает отлично)

Поскольку выбор текста не является обязательным требованием для моего приложения, я скорее отключаю его. Для этого вы можете использовать следующий код (Swift 3):

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if #available(iOS 10, *) {
        if action == #selector(UIResponderStandardEditActions.select(_:)) {
            return false
        }
    }

    return super.canPerformAction(action, withSender: sender)
}
1 голос
/ 24 февраля 2016

По непонятной причине я не совсем понял, что решил эту проблему, установив автоматически AdjustsScrollViewInsets в NO (или эквивалент в Interface Builder).Это с iOS 8.1.

1 голос
/ 13 ноября 2012

Работает для всех размеров шрифта и не вызывает несовпадения с clearButton.

Подкласс UITextField и переопределите их следующим образом:

- (CGRect)placeholderRectForBounds:(CGRect)bounds
{
    return CGRectOffset( bounds, 0, 4 );
}

- (CGRect)editingRectForBounds:(CGRect)bounds
{
    return CGRectOffset( bounds, 0, 2);
}

- (CGRect)textRectForBounds:(CGRect)bounds
{
    return CGRectOffset( bounds , 0 , 4 );
}
0 голосов
/ 06 апреля 2017

Swift 3

Не забудьте accessory views UITextField. Вам нужно будет учитывать super функций * rect (forBounds: ...), если вы хотите работающую реализацию. И также обязательно смещайте ректы только для багги iOS 10, а не для 9 или 8! Следующий код должен сделать трюк:

public class CustomTextField: UITextField {
    public override func textRect(forBounds bounds: CGRect) -> CGRect {
        let superValue = super.textRect(forBounds: bounds)

        if #available(iOS 10, *) {
            return superValue.insetBy(dx: 0, dy: 0)
        }
        return superValue
    }

    public override func editingRect(forBounds bounds: CGRect) -> CGRect {
        let superValue = super.editingRect(forBounds: bounds)

        if #available(iOS 10, *) {
            return superValue.insetBy(dx: 0, dy: -0.5)
        }
        return superValue
    }

    public override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        let superValue = super.placeholderRect(forBounds: bounds)

        if #available(iOS 10, *) {
            if isEditing {
                return superValue.insetBy(dx: 0, dy: 0.5)
            }
            return superValue.insetBy(dx: 0, dy: 0.0)
        }
        return superValue
    }
}

EDIT

Я немного отредактировал свой код сверху до следующего, и он работает лучше для меня. Я тестирую его на iPhone 6, 6, 7, 7, а также на устройствах «плюс» с iOS 9.3 и 10.3.

public class CustomTextField: UITextField {

    public override func textRect(forBounds bounds: CGRect) -> CGRect {
        let superValue = super.textRect(forBounds: bounds)

        if #available(iOS 10, *) {
            return superValue.insetBy(dx: 0, dy: -0.3)
        }
        return superValue.insetBy(dx: 0, dy: -0.2)
    }

    public override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return self.textRect(forBounds: bounds)
    }
}

Я думаю, это также зависит от используемого вами шрифта. Я использую UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightLight)

0 голосов
/ 03 февраля 2017

Установите для вашего текстового поля Border Style любое значение, кроме «none» в IB, затем в наборе viewDidLoad вашего ViewController:

yourTextField.borderStyle = .none

(на основе этого ответа от Box Jeon)

0 голосов
/ 27 октября 2016

Это ожидаемое поведение в стандартном UITextField.Однако вы можете решить эту проблему, создав подкласс UITextField и скорректировав границы для самого текста.

Swift 3

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return(bounds.insetBy(dx: 0, dy: 0))
}

override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return(bounds.insetBy(dx: 0, dy: -0.5))
}

override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return(bounds.insetBy(dx: 0, dy: 0))
}

Это должно помочь!

0 голосов
/ 30 апреля 2014

Вы должны установить свойство Font раньше, чем свойство Text.

0 голосов
/ 03 февраля 2012

У меня была эта проблема с пользовательским шрифтом, и я решил ее, сместив метку в другом направлении, когда сработают события клавиатуры.Я переместил центр метки в кнопке, переопределив метод drawRect:

- (void)drawRect:(CGRect)rect
{
    self.titleLabel.center = CGPointMake(self.titleLabel.center.x, self.titleLabel.center.y+3);
}
...