Итак, у меня возникают проблемы в проекте, когда определенные строки не отображаются должным образом на некоторых старых iPhone с определенными версиями iOS (в частности, это не работает для iPhone 5 с iOS10, тогда как для iOS9.3, как ни странно). Чтобы уменьшить проблему, я написал этот код:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Long HTML, although we'll make it even larger to prove a point
        let string = "<h1>Thing 1</h1><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. </p><h1>Thing 2</h1><p>Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. </p><h1>Thing 3</h1><p>Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. </p><h1>Thing 4</h1><p>Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. </p><h1>Thing 5</h1><p>Integer lacinia sollicitudin massa. Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam. Aenean laoreet. Vestibulum nisi lectus, commodo ac, facilisis ac, ultricies eu, pede. Ut orci risus, accumsan porttitor, cursus quis, aliquet eget, justo. Sed pretium blandit orci. </p><h1>Thing 6</h1><p>Ut eu diam at pede suscipit sodales. Aenean lectus elit, fermentum non, convallis id, sagittis at, neque. Nullam mauris orci, aliquet et, iaculis et, viverra vitae, ligula. Nulla ut felis in purus aliquam imperdiet. Maecenas aliquet mollis lectus. Vivamus consectetuer risus et tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. </p>"

        let attrStr = try! NSAttributedString(
            data: (string + string + string + string + string + string + string + string).data(using: String.Encoding.unicode,allowLossyConversion: true)!,
            options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
            documentAttributes: nil)

        label.attributedText = attrStr
        label.backgroundColor = UIColor(red:0.00, green:1.00, blue:0.00, alpha:1.0)
    }
}

Достаточно просто. Конечно, на самом деле проблема сложнее, но идея та же.

Итак, в iPhone 7 все работает нормально:

enter image description here

Однако при загрузке на iPhone 4s:

enter image description here

При отладке в обоих случаях кажется, что attrStr установлен правильно.

Есть идеи? Моя теория заключается в том, что старые телефоны слишком медленные, чтобы отображать это вовремя, но я не совсем уверен, как это исправить.

Спасибо!

РЕДАКТИРОВАТЬ: Для тех, кто спросил, это Раскадровка:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="JzW-qG-LFG">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="9PR-d2-hNU">
            <objects>
                <viewController id="JzW-qG-LFG" customClass="ViewController" customModule="things" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="VGp-YT-QQN"/>
                        <viewControllerLayoutGuide type="bottom" id="SeT-t7-CD0"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="gtg-CO-E9d">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Id1-A1-RaT">
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstAttribute="trailingMargin" secondItem="Id1-A1-RaT" secondAttribute="trailing" id="0qp-Rk-PC2"/>
                            <constraint firstItem="Id1-A1-RaT" firstAttribute="leading" secondItem="gtg-CO-E9d" secondAttribute="leadingMargin" id="3Vc-he-HqH"/>
                            <constraint firstItem="Id1-A1-RaT" firstAttribute="top" secondItem="VGp-YT-QQN" secondAttribute="bottom" id="7IE-fY-4H0"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" id="Opz-px-hsl"/>
                    <connections>
                        <outlet property="label" destination="Id1-A1-RaT" id="TNv-G9-ASE"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="qlV-6d-ISJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2848.8000000000002" y="-280.20989505247377"/>
        </scene>
    </scenes>
</document>
10
pyriku 27 Ноя 2016 в 21:35

3 ответа

Лучший ответ

Проблема здесь в том, что недокументированный предел высоты UIView составляет 8192 пункта. Как только метка достигает 8192 точек (или больше), она больше не обновляет буфер кадра. (Предположительно оконный сервер просто игнорирует метку CALayer, если уровень слишком велик.) Все, что уже было в буфере кадра, остается там. Предположительно поведение не определено и может различаться в зависимости от устройства и версии iOS.

(Изменить: подумав об этом больше, я подозреваю, что предел составляет 16 384 пикселей, а не 8 192 точки. Я не думаю, что сервер окон имеет дело с точками.)

Для демонстрации я взял ваш код и раскадровку и добавил три вещи:

  1. Я ограничил высоту вашей метки не более 8185 точек.
  2. Я добавил ползунок, который обновляет константу ограничения высоты. Ползунок позволяет диапазон от 8185 до 8200.
  3. Я добавил еще одну метку, отображающую константу ограничения высоты.

Вот что происходит в симуляторе iPhone SE под управлением iOS 10.2:

demo of 8192 point height problems

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

Я думаю, вы не видите этого в своем тесте iPhone 7, потому что у iPhone 7 экран шире, чем у iPhone SE. Все iPhone с экранами 3,5 и 4 дюйма имеют ширину 320 точек. iPhone с экранами 4,7 дюйма имеет ширину 375 точек, а iPhone с экранами 5,5 дюймов - 414 точек.

Чем шире экран, тем шире UILabel. Это означает, что в каждой строке умещается больше текста, поэтому метка не должна быть такой высокой, чтобы вместить весь текст. Я подозреваю, что на больших экранах ваши метки короче 8192 пунктов, поэтому они не влияют на поведение undefined.

Обходные :

  • Если вы не собираетесь позволять пользователю прокручивать, чтобы увидеть весь текст, просто установите ограничение высоты на этикетку.

  • Если вы хотите позволить пользователю прокручивать, попробуйте использовать UIWebView или WKWebView вместо UILabel для отображения текста. Я считаю, что эти просмотры могут обрабатывать контент высотой более 8192 баллов.

Кстати, вы не первый, кто столкнулся с этой проблемой: Представление UILabel исчезает, когда высота больше 8192. Однако в настоящее время у вашего вопроса есть открытая награда, что не позволяет закрыть его как дубликат.

13
Community 23 Май 2017 в 11:53

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

Я запустил метку программно, и это решение работает на iPhone 4s под управлением iOS 9.3:

enter image description here

Вот рабочий исходный код:

override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel(frame: CGRect(x: 0.0, y: 44.0, width: view.frame.size.width, height: view.frame.size.height - 88.0))
    label.numberOfLines = 0
    label.isUserInteractionEnabled = false
    label.contentMode = .left
    label.textAlignment = .natural
    label.lineBreakMode = .byTruncatingTail
    label.baselineAdjustment = .alignBaselines
    label.adjustsFontSizeToFitWidth = false
//  label.translatesAutoresizingMaskIntoConstraints = false //setting this causes the text to be layout wrong
    label.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]

    view.addSubview(label)

    // Long HTML, although we'll make it even larger to prove a point
    let string = "<h1>Thing 1</h1><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. </p><h1>Thing 2</h1><p>Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. </p><h1>Thing 3</h1><p>Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. </p><h1>Thing 4</h1><p>Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. </p><h1>Thing 5</h1><p>Integer lacinia sollicitudin massa. Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam. Aenean laoreet. Vestibulum nisi lectus, commodo ac, facilisis ac, ultricies eu, pede. Ut orci risus, accumsan porttitor, cursus quis, aliquet eget, justo. Sed pretium blandit orci. </p><h1>Thing 6</h1><p>Ut eu diam at pede suscipit sodales. Aenean lectus elit, fermentum non, convallis id, sagittis at, neque. Nullam mauris orci, aliquet et, iaculis et, viverra vitae, ligula. Nulla ut felis in purus aliquam imperdiet. Maecenas aliquet mollis lectus. Vivamus consectetuer risus et tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. </p>"

    let attrStr = try! NSAttributedString(
        data: (string + string + string + string + string + string + string + string).data(using: String.Encoding.unicode,allowLossyConversion: true)!,
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil)

    label.attributedText = attrStr
    label.backgroundColor = UIColor(red:0.00, green:1.00, blue:0.00, alpha:1.0)
}

Полный рабочий проект можно загрузить с здесь.

1
Jeshua Lacock 30 Ноя 2016 в 09:34

Вы определенно правы. Это вопрос времени.

NSHTMLTextDocumentType из NSDocumentTypeDocumentAttribute печально известно из-за принимая очень долгое время. По мере увеличения длины строки attrStr (добавляя пару строк + в данные) вы сможете реплицировать ошибку для устройств более высокого уровня после определенной длины строки. Я могу воспроизвести это в эмуляторе iPhone 6 plus, используя iOS 10.1, поскольку эмулятор работает с меньшей вычислительной мощностью, чем фактическое устройство.

Если это возможно для вас, вы можете попробовать использовать DTCoreText для решения этой проблемы. Эта библиотека обрабатывает строку HTML с помощью методов, отличных от встроенных, что сокращает время отрисовки. Это сделает ошибку менее заметной на мобильных устройствах более низкого уровня.

1
Community 23 Май 2017 в 12:24