Как потерять маржу / отступ в UITextView?
у меня есть UITextView в моем приложении iOS, которое отображает большое количество текста. Затем я просматриваю этот текст, используя параметр поля смещения UITextView. Моя проблема заключается в том, что обивка UITextView сбивает с толку мои расчеты, поскольку он, кажется, отличается в зависимости от размера шрифта и шрифта, который я использую.
поэтому я задаю вопрос: Можно ли удалить обивку, окружающую содержимое UITextView?
смотрим вперед к слышать ваши ответы!
19 ответов:
2018 год
это одна из самых глупых ошибок в iOS.
класс
UITextViewFixed- это, как правило, разумное решение.вот класс:
@IBDesignable class UITextViewFixed: UITextView { override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 } }не забудьте отключить scrollEnabled в Инспекторе!
решение работает правильно в раскадровке
решение работает правильно во время выполнения
вот и все, ты сделанный.
в общем, это должно быть все, что вам нужно в большинстве случаев.
даже если вы меняете высоту текстового представления на лету, это обычно делает все, что вам нужно.
(распространенный пример изменения высоты на лету, изменяет его по мере ввода пользователем.)
вот сломанный UITextView от Apple...
здесь
UITextViewFixed:
обратите внимание, что, конечно, вы должны
отключить scrollEnabled в Инспекторе!
не забудьте выключить scrollEnabled! :)
некоторые дополнительные вопросы
(1) в некоторых необычных случаях - например, в некоторых случаях гибких представлений таблицы высоты ячейки с динамически изменяющейся высотой - Apple делает самую возмутительную вещь в мире: они добавляют дополнительное пространство на дно. Нет, правда! Это должно было бы быть одной из самых возмутительных вещей в iOS.
вот "быстрое решение", чтобы добавить, что часто помогает с этим безумием.
... textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 // this is not ideal, but you can sometimes use this // to fix the "space at bottom" insanity var b = bounds let h = sizeThatFits(CGSize( width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude) ).height b.size.height = h bounds = b ...(2) Иногда, чтобы исправить еще один тонкий яблочный беспорядок, вы должны добавить это:
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) { super.setContentOffset(contentOffset, animated: false) }(3) Возможно, мы должны добавляем :
contentInset = UIEdgeInsets.zeroсразу после
.lineFragmentPadding = 0наUITextViewFixed. Однако... это просто не работа в текущей iOS! Возможно, потребуется добавить это в будущем.дело в том, что
UITextViewполностью разбиты в iOS-это одна из самых странных вещей во всех мобильных компьютеров.наконец, вот несколько похожий совет для текстаполе: https://stackoverflow.com/a/43099816/294884
для iOS 7.0 я обнаружил, что трюк contentInset больше не работает. Это код, который я использовал, чтобы избавиться от поля/заполнения в iOS 7.
это приводит левый край текста к левому краю контейнера:
textView.textContainer.lineFragmentPadding = 0это приводит к выравниванию верхней части текста с верхней частью контейнера
textView.textContainerInset = .zeroобе строки необходимы для полного удаления поля / отступа.
этот обходной путь был написан в 2009 году, когда была выпущена IOS 3.0. Он больше не применяется.
я столкнулся с точно такой же проблемой, в конце концов мне пришлось использовать
nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);где nameField-это
UITextView. Шрифт, который я использовал, был Helvetica 16 point. Его единственное пользовательское решение для конкретного размера поля, которое я рисовал. Это делает левое смещение заподлицо с левой стороной, а верхнее смещение, где я хочу его для коробки, его втягивает.кроме того, это относится только к
UITextViewsгде вы используете алигмент по умолчанию, т. е.nameField.textAlignment = NSTextAlignmentLeft;выровнять вправо, например, и
UIEdgeInsetsMakeкажется, не имеет никакого влияния на правый край вообще.по крайней мере, с помощью .свойство contentInset позволяет размещать поля с" правильными " позициями и учитывать отклонения без компенсации вашего
UITextViews.
отталкиваясь от некоторых хороших ответов, которые уже даны, вот чисто интерфейсное решение на основе конструктора, которое использует пользовательские атрибуты времени выполнения и работает в iOS 7.0+:
Я бы определенно избегал любых ответов, связанных с жестко закодированными значениями, поскольку фактические поля могут меняться с настройками размера шрифта пользователя и т. д.
вот ответ @user1687195, написанный без изменения
textContainer.lineFragmentPadding(поскольку docs государство-это не целевое использование).Это отлично подходит для iOS 7 и более поздних версий.
self.textView.textContainerInset = UIEdgeInsetsMake( 0, -self.textView.textContainer.lineFragmentPadding, 0, -self.textView.textContainer.lineFragmentPadding);это фактически тот же результат, только немного чище в том, что это не так неправильное использование свойства lineFragmentPadding.
раскадровку или интерфейс построителя решений, используя определенные пользователем атрибуты во время выполнения. обновление. добавлены скриншоты iOS7.1 и iOS6. 1 с contentInset = {{-10, -5}, {0, 0}}
все эти ответы касаются вопроса заголовка, но я хотел бы предложить некоторые решения для проблем, представленных в теле вопроса ОП.
размер текстового содержимого
быстрый способ рассчитать размер текста внутри
UITextViewиспользоватьNSLayoutManager:UITextView *textView; CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size;это дает общее прокручиваемое содержимое, которое может быть больше, чем
UITextView's кадр. Я обнаружил, что это гораздо точнее, чемtextView.contentSizeтак как это на самом деле вычисляет, сколько места занимает текст. Например, дано пустоеUITextView:textView.frame.size = (width=246, height=50) textSize = (width=10, height=16.701999999999998) textView.contentSize = (width=246, height=33) textView.textContainerInset = (top=8, left=0, bottom=8, right=0)Высота Строки
UIFontимеет свойство, которое быстро позволяет получить высоту строки для данного шрифта. Так что вы можете быстро найти высоту строки текста вUITextViewС:UITextView *textView; CGFloat lineHeight = textView.font.lineHeight;Вычисление Видимого Размера Текста
определение объема текста, который фактически виден, важно для обработки эффекта "подкачки".
UITextViewимеет свойство под названиемtextContainerInsetкоторый на самом деле является границей между фактическимUITextView.frameи сам текст. Для расчета реальной высоты видимого кадра можно выполнить следующие расчеты:UITextView *textView; CGFloat textViewHeight = textView.frame.size.height; UIEdgeInsets textInsets = textView.textContainerInset; CGFloat textHeight = textViewHeight - textInsets.top - textInsets.bottom;Определение Размера Подкачки
наконец, теперь, когда у вас есть видимый размер текста и содержание, вы можете быстро определить, что ваши смещения должны быть путем вычитания
textHeightСtextSize:// where n is the page number you want CGFloat pageOffsetY = textSize - textHeight * (n - 1); textView.contentOffset = CGPointMake(textView.contentOffset.x, pageOffsetY); // examples CGFloat page1Offset = 0; CGFloat page2Offset = textSize - textHeight CGFloat page3Offset = textSize - textHeight * 2используя все это методы, я не трогал свои вставки, и я смог перейти к каретке или где угодно в тексте, который я хочу.
можно использовать
textContainerInsetсобственностьUITextView:textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
(сверху, слева, снизу, справа)
для iOS 10 следующая строка работает для удаления верхнего и нижнего отступов.
captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
вот обновленная версия очень полезного ответа Fattie. Он добавляет 2 очень важные строки, которые помогли мне получить идеальный макет, работающий на iOS 10 и 11 (и, вероятно, на более низких).
d@IBDesignable class UITextViewFixed: UITextView { override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { translatesAutoresizingMaskIntoConstraints = true textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 translatesAutoresizingMaskIntoConstraints = false } }важные линии-это два
translatesAutoresizingMaskIntoConstraints = <true/false>заявления!это удивительно удаляет все поля при всех моих обстоятельствах!
в то время как
textViewэто не первый ответчик может случиться, что там это какой-то странный нижний край, который не может быть решен с помощьюsizeThatFitsметод, который упоминается в принятой ответ.
При нажатии на textView внезапно странное нижнее поле исчезло, и все выглядело так, как должно, но только как только textView получилfirstResponder.так я читал так что включение и отключение
translatesAutoresizingMaskIntoConstraintsпомогает при установке кадра / границ вручную между вызовами.к счастью это работает не только с настройкой кадра, но и с 2 строками
setup()зажатый между двумяtranslatesAutoresizingMaskIntoConstraintsзвонки!вот например очень полезным при расчете кадра вида используя
systemLayoutSizeFittingнаUIView. Возвращает правильный размер (который ранее этого не делал)!как в оригинальном ответе упоминается:
не забудьте отключить scrollEnabled в Инспекторе!
Это решение действительно работает правильно в раскадровке, а также во время выполнения.вот и все, теперь ты действительно готово!
для swift 4, Xcode 9
С помощью следующей функции можно изменить поля / отступы текста в UITextView
общественные Функ UIEdgeInsetsMake(_ топ: CGFloat, _ осталось: CGFloat, _ основание: CGFloat, _ право: CGFloat) -> UIEdgeInsets
Так что в данном случае составляет
self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
делая решение вставки, у меня все еще была прокладка с правой стороны и снизу. Также выравнивание текста вызывало проблемы. Единственный верный способ огня, который я нашел, состоял в том, чтобы поместить текстовое представление в другое представление, которое обрезано до границ.
вот простое небольшое расширение, которое удалит поле Apple по умолчанию из каждого текстового представления в вашем приложении.
Примечание: Interface Builder по-прежнему будет показывать старое поле, но ваше приложение будет работать так, как ожидалось.
extension UITextView { open override func awakeFromNib() { super.awakeFromNib(); removeMargins(); } /** Removes the Apple textview margins. */ public func removeMargins() { self.contentInset = UIEdgeInsetsMake( 0, -textContainer.lineFragmentPadding, 0, -textContainer.lineFragmentPadding); } }
Последний Swift
self.поле TextView.textContainerInset = .init (сверху: -2, слева: 0, снизу: 0, справа: 0) личность.поле TextView.textContainer.lineFragmentPadding = 0
для меня (iOS 11 & Xcode 9.4.1) то, что сработало волшебным образом, было настройкой textView.свойство шрифта для
UIFont.preferred(forTextStyle:UIFontTextStyle)стиль, а также первый ответ, Как упоминалось @Fattie. Но ответ @Fattie не работал, пока я не установил textView.свойство шрифта else UITextView продолжает вести себя хаотично.
Я нашел еще один подход, получая представление с текстом из подвидов UITextView и устанавливая его в метод layoutSubview подкласса:
- (void)layoutSubviews { [super layoutSubviews]; const int textViewIndex = 1; UIView *textView = [self.subviews objectAtIndex:textViewIndex]; textView.frame = CGRectMake( kStatusViewContentOffset, 0.0f, self.bounds.size.width - (2.0f * kStatusViewContentOffset), self.bounds.size.height - kStatusViewContentOffset); }
прокрутка textView также влияет на положение текста и делает его похожим на не вертикально центрированный. Мне удалось центрировать текст в представлении, отключив прокрутку и установив верхнюю вставку в 0:
textView.scrollEnabled = NO; textView.textContainerInset = UIEdgeInsetsMake(0, textView.textContainerInset.left, textView.textContainerInset.bottom, textView.textContainerInset.right);по какой-то причине я еще не понял, курсор все еще не центрирован до начала ввода, но текст центрируется сразу же, как я начинаю печатать.





Comments