Как потерять поля / отступы в UITextView?

У меня есть UITextView в моем приложении iOS, которое отображает большое количество текста. Затем я разбиваю на страницы этот текст с помощью параметра отступа поля UITextView. Моя проблема в том, что отступы UITextView сбивают с толку мои расчеты, так как они кажутся различными в зависимости от размера шрифта и используемого шрифта.

Поэтому я задаю вопрос: возможно ли удалить отступы, окружающие содержимое UITextView?

С нетерпением ждем ваших ответов!

вопрос задан 14.04.2009
sniurkst
2862 репутация

19 ответов


  • 733 рейтинг

    Для iOS 7. 0, я обнаружил, что трюк contentInset больше не работает. Это код, который я использовал, чтобы избавиться от полей / отступов в iOS 7.

    Это приводит левый край текста к левому краю контейнера:

    textView.textContainer.lineFragmentPadding = 0
    

    Это приводит к тому, что верх текста выравнивается по верху контейнера.

    textView.textContainerInset = .zero
    

    Обе строки необходимы для полного удаления полей / отступов.

    ответ дан user1687195, с репутацией 7746, 24.09.2013
  • 250 рейтинг

    Этот обходной путь был написан в 2009 году, когда IOS 3. 0 был выпущен. Это больше не применяется.

    Я столкнулся с точно такой же проблемой, в конце концов мне пришлось завершить с использованием

    nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);
    

    , где nameField - UITextView. Я использовал шрифт Helvetica 16 пунктов. Это единственное нестандартное решение для конкретного размера поля, которое я рисовал. Это делает левое смещение заподлицо с левой стороной, а верхнее смещение там, где я хочу, для поля, в котором оно нарисовано.

    Кроме того, кажется, что это применимо только к UITextViews, где вы используете aligment по умолчанию, т.е.

    nameField.textAlignment = NSTextAlignmentLeft;
    

    Например, выровняйтесь по правому краю, и UIEdgeInsetsMake, кажется, вообще не влияет на правый край.

    По крайней мере, используя. Свойство contentInset позволяет размещать поля с «правильными» позициями и учитывать отклонения, не смещая UITextViews.

    ответ дан Michael, с репутацией 2901, 26.07.2009
  • 193 рейтинг

    на 2018 год

    Это одна из самых глупых ошибок в iOS.

    UITextViewFixed обычно является разумным решением:

    @IBDesignable class UITextViewFixed: UITextView {
        override func layoutSubviews() {
            super.layoutSubviews()
            setup()
        }
        func setup() {
            textContainerInset = UIEdgeInsets.zero
            textContainer.lineFragmentPadding = 0
        }
    }
    

    Не забудьте отключить scrollEnabled в Инспекторе!

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

    Вот и все, все готово.

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

    (Даже если вы изменяете высоту текстового представления на лету - например, когда пользователь вводит текст - обычно это делает все, что вам нужно. )

    Вот сломанный UITextView от Apple. , ,

    screenshot of IB with UITextView

    Почти во всех случаях UITextViewFixed является приемлемым исправлением:

    screenshot of IB with 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) Иногда, чтобы исправить еще одну тонкую ошибку Apple, вы должны добавить это:

    override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
        super.setContentOffset(contentOffset, animated: false)
    }
    

    (3) Возможно, мы должны добавить:

    contentInset = UIEdgeInsets.zero
    

    сразу после .lineFragmentPadding = 0. Тем не мение . , , это не работает в текущей iOS! Возможно, потребуется добавить это в будущих версиях ОС.

    Тот факт, что UITextView из всех вещей полностью сломан в iOS, является лишь одной из самых странных вещей во всех мобильных вычислениях.

    Наконец, вот несколько похожий совет для Text Поле : https: // stackoverflow. com / a / 43099816/294884

    ответ дан Fattie, с репутацией 20066, 19.02.2017
  • 62 рейтинг

    Опираясь на некоторые из хороших ответов, которые уже даны, вот чисто решение на основе Interface Builder, которое использует пользовательские атрибуты времени выполнения и работает в iOS 7. 0+:

    enter image description here

    ответ дан azdev, с репутацией 10892, 4.02.2015
  • 44 рейтинг

    На iOS 5 UIEdgeInsetsMake(-8,-8,-8,-8);, кажется, прекрасно работает.

    ответ дан Engin Kurutepe, с репутацией 5145, 8.05.2012
  • 38 рейтинг

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

    Вот ответ @ user1687195, написанный без изменения textContainer.lineFragmentPadding (потому что docs заявляют, что это не предназначенное использование).

    Это прекрасно работает для iOS 7 и более поздних версий.

    self.textView.textContainerInset = UIEdgeInsetsMake(
                                          0, 
                                          -self.textView.textContainer.lineFragmentPadding, 
                                          0, 
                                          -self.textView.textContainer.lineFragmentPadding);
    

    Это фактически тот же результат, только немного чище, поскольку он не использует свойство lineFragmentPadding.

    ответ дан ldoogy, с репутацией 1583, 24.04.2016
  • 18 рейтинг

    Решение Storyboard или Interface Builder с использованием пользовательских атрибутов времени выполнения. Обновление. Добавлена ​​iOS7. 1 & амп; iOS6. 1 скриншотов с contentInset = {{-10, -5}, {0, 0}} enter image description here enter image description here

    ответ дан Uladzimir, с репутацией 1322, 5.09.2013
  • 15 рейтинг

    Все эти ответы касаются заглавного вопроса, но я хотел предложить некоторые решения проблем, представленных в основной части вопроса ОП.

    Размер текстового содержимого

    Быстрый способ рассчитать размер текста внутри UITextView заключается в использовании NSLayoutManager:

    UITextView *textView;
    CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size;
    

    Это дает общий прокручиваемый контент, который может быть больше, чем фрейм UITextView. Я обнаружил, что это намного точнее, чем 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
    

    Используя все эти методы, я не трогал свои вкладыши и мог перейти к каретке или куда угодно в тексте, который я хочу.

    ответ дан mikeho, с репутацией 4695, 26.06.2015
  • 11 рейтинг

    вы можете использовать textContainerInset свойство UITextView:

    textView. textContainerInset = UIEdgeInsetsMake (10, 10, 10, 10);

    (сверху, слева, снизу, справа)

    ответ дан Himanshu padia, с репутацией 4055, 5.05.2015
  • 6 рейтинг

    Для iOS 10 следующая строка работает для удаления верхнего и нижнего отступов.

    captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
    
    ответ дан Anson Yao, с репутацией 807, 12.10.2016
  • 3 рейтинг

    Вот обновленная версия очень полезного ответа Фэтти. Он добавляет 2 очень важные строки, которые помогли мне получить идеальный макет, работающий на iOS 10 и 11 (и, вероятно, также на более низких).
    д

    @IBDesignable class UITextViewFixed: UITextView {
        override func layoutSubviews() {
            super.layoutSubviews()
            setup()
        }
        func setup() {
            translatesAutoresizingMaskIntoConstraints = true
            textContainerInset = UIEdgeInsets.zero
            textContainer.lineFragmentPadding = 0
            translatesAutoresizingMaskIntoConstraints = false
        }
    }
    

    Важными строками являются два translatesAutoresizingMaskIntoConstraints = утверждений!

    Это удивительно удаляет все поля при всех моих обстоятельствах!

    Хотя textView не является первым респондентом, может случиться так, что есть некоторый странный нижний предел, который не может быть решен с помощью метода sizeThatFits, который упоминается в принятом ответе.
    При нажатии на textView внезапно исчезло странное нижнее поле, и все выглядело так, как должно, но только после того, как textView получил firstResponder.

    Итак, я прочитал здесь на SO , что включение и отключение translatesAutoresizingMaskIntoConstraints действительно помогает при ручной настройке фрейма / границ между вызовами.

    К счастью, это работает не только с настройкой кадра, но и с двумя строками setup(), расположенными между двумя вызовами translatesAutoresizingMaskIntoConstraints!

    Это, например, , очень полезно при расчете кадра вида с использованием systemLayoutSizeFitting на UIView . Возвращает правильный размер (чего раньше не было)!

    Как и в оригинальном ответе упоминается:
    Не забудьте отключить scrollEnabled в Инспекторе!
    Это решение работает правильно как в раскадровке, так и во время выполнения.

    Вот и все, теперь вы действительно сделано!

    ответ дан Fab1n, с репутацией 1399, 14.02.2018
  • 3 рейтинг

    Для swift 4, Xcode 9

    Используйте следующую функцию, чтобы изменить поле / отступ текста в UITextView

    открытый функционал UIEdgeInsetsMake (_ вверху: CGFloat, _ слева: CGFloat, _ внизу: CGFloat, _ справа: CGFloat) - & gt; UIEdgeInsets

    , так что в этом случае

     self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
    
    ответ дан Shan Ye, с репутацией 784, 26.10.2017
  • 2 рейтинг

    При выполнении врезного решения у меня все еще была прокладка справа и снизу. Также выравнивание текста вызывало проблемы. Единственный надежный способ, который я нашел, - это поместить текстовое представление в другое представление, обрезанное до границ.

    ответ дан rp90, с репутацией 439, 31.03.2011
  • 0 рейтинг

    Для меня (iOS 11 и Xcode 9. 4. 1) волшебным образом работала настройка textView. свойство шрифта для стиля UIFont.preferred(forTextStyle:UIFontTextStyle), а также первый ответ, упомянутый @Fattie. Но ответ @Fattie не работал, пока я не установил textView. свойство шрифта else UITextView ведет себя беспорядочно.

    ответ дан Nikhil Pandey, с репутацией 154, 17.06.2018
  • 0 рейтинг

    Вот небольшое простое расширение, которое удалит поля Apple по умолчанию из каждого текстового представления в вашем приложении.

    Примечание. Интерфейсный конструктор по-прежнему будет отображать старое поле, но ваше приложение будет работать так, как ожидается.

    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);
       }
    }
    
    ответ дан Cal S, с репутацией 1762, 4.03.2018
  • 0 рейтинг

    Последний Свифт

    сам. TextView. textContainerInset =. init (сверху: -2, слева: 0, снизу: 0, справа: 0) самостоятельно. TextView. textContainer. lineFragmentPadding = 0

    ответ дан Urvish Modi, с репутацией 758, 24.05.2018
  • -1 рейтинг

    Прокрутка textView также влияет на положение текста и делает его не центрированным по вертикали. Мне удалось отцентрировать текст в представлении, отключив прокрутку и установив верхнюю вставку в 0:

        textView.scrollEnabled = NO;
        textView.textContainerInset = UIEdgeInsetsMake(0, textView.textContainerInset.left, textView.textContainerInset.bottom, textView.textContainerInset.right);
    

    По какой-то причине я еще не понял, курсор все еще не центрирован до начала набора, но текст центрируется сразу же, как я начинаю печатать.

    ответ дан Alex, с репутацией 728, 25.12.2016
  • -1 рейтинг

    Я нашел еще один подход: получить представление с текстом из подпредставлений 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);
    }
    
    ответ дан Nikita, с репутацией 1056, 28.02.2013
  • -4 рейтинг
    [firstNameTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
    
    ответ дан to0nice4eva, с репутацией 37, 11.08.2011