提问人:benedom 提问时间:11/1/2022 更新时间:11/3/2022 访问量:639
TextView 在文本为一行时添加底部填充/空格
TextView adds bottom padding/space when text is one line
问:
问题
我遇到了一个奇怪的行为,它位于 a 内部,定义间距为 。用于在聊天气泡内显示消息。当消息只有一行时,将展开并添加 about 的底部间距/填充。查看视图层次结构,文本本身是一个位于 .此画布视图似乎绘制得太大,导致间距过大。UITextView
UIStackView
0
UITextView
UITextView
2.3 px
_UITextLayoutFragmentView
_UITextLayoutCanvasView
以下图像来自视图层次结构,其中显示问题的一行消息和包含两行消息的消息,其中问题未显示:https://i.stack.imgur.com/azhsq.jpg(链接,因为我还不能在 Stackoverflow 上发布图像)。
我试过了什么
我已经设置了插图:UITextView
messageTextView.textContainerInset = .zero
messageTextView.textContainer.lineFragmentPadding = .zero
messageTextView.contentInset = .zero
它删除了正常的填充(使用此答案/线程)。UITextView
我最初的想法是,在某处指定了最小高度,当里面的文本(一行)没有填充最小高度时,这会导致视图扩展。但是,我不知道这是否正确,或者是否有可能更改最小高度。缩小字体大小会产生更大的间距。messageTextView
聊天气泡用于根据内容自动调整其大小。在更改为 a 之前,我们使用了 一个工作正常且没有创建任何间距的 a。UIStackViews
UITextView
UILabel
有没有人遇到过类似的问题?
答:
- 使用此 SDK 并应用最小高度,然后它会自动管理高度
https://github.com/KennethTsang/GrowingTextView
评论
您显示的布局看起来正确无误...但有些事情并不完全正确。
我把它放在一起作为一个快速测试 - 它应该非常接近你所拥有的......
细胞 xib 在 IB 中的外观:
运行时的外观 - 5 条“消息”相关两次。第一组隐藏了“documentsStack 和 imagesStack”,第二组显示(没有子视图,但有 10 磅高度限制):
下面是 Debug View Hierarchy 外观:
所以。。。XIB的来源:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="315" id="efZ-1S-bN1" customClass="RightStandardMessageCell" customModule="qtest" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="442" height="315"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="efZ-1S-bN1" id="mpK-CA-Lnn">
<rect key="frame" x="0.0" y="0.0" width="442" height="315"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2vd-KS-ll8">
<rect key="frame" x="106" y="8" width="328" height="299"/>
<color key="backgroundColor" red="0.71935945749999997" green="0.8054707646" blue="0.8795467615" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="7Bs-WC-QCo">
<rect key="frame" x="118" y="20" width="304" height="275"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" translatesAutoresizingMaskIntoConstraints="NO" id="Ykv-rE-DFT">
<rect key="frame" x="0.0" y="0.0" width="304" height="227"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="Text View" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="xKc-db-bx1" userLabel="Message Text View" customClass="MyTextViewLabel" customModule="qtest" customModuleProvider="target">
<rect key="frame" x="220.5" y="0.0" width="83.5" height="227"/>
<color key="backgroundColor" red="0.41512373645565315" green="0.80431303791610775" blue="0.90702960527304444" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" red="0.79694263352245631" green="0.91265043646398214" blue="0.50891842927836861" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jKv-au-EZL">
<rect key="frame" x="0.0" y="231" width="304" height="10"/>
<color key="backgroundColor" systemColor="systemOrangeColor"/>
<constraints>
<constraint firstAttribute="height" constant="10" id="AoS-qw-PIV"/>
</constraints>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9wb-aV-6Ah">
<rect key="frame" x="0.0" y="245" width="304" height="10"/>
<color key="backgroundColor" systemColor="systemPurpleColor"/>
<constraints>
<constraint firstAttribute="height" constant="10" id="ZGO-O7-jpC"/>
</constraints>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="wQ2-iG-u2V">
<rect key="frame" x="0.0" y="259" width="304" height="16"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="83z-yh-Mfn" userLabel="Timestamp">
<rect key="frame" x="0.0" y="0.0" width="278" height="16"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="16" id="zeh-oM-fP6"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="checkmark.rectangle" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="fqI-0d-Wy4" userLabel="Checkmark Image View">
<rect key="frame" x="286" y="1" width="18" height="13.5"/>
<constraints>
<constraint firstAttribute="width" constant="18" id="9NX-a1-Fzz"/>
<constraint firstAttribute="height" constant="16" id="Pdb-F0-5qp"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.93024982769507736" green="0.76566540916270232" blue="0.97523039579391479" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstItem="2vd-KS-ll8" firstAttribute="top" secondItem="mpK-CA-Lnn" secondAttribute="top" constant="8" id="95G-hj-ZRa"/>
<constraint firstItem="7Bs-WC-QCo" firstAttribute="top" secondItem="2vd-KS-ll8" secondAttribute="top" constant="12" id="ARj-eW-yGu"/>
<constraint firstItem="2vd-KS-ll8" firstAttribute="width" relation="lessThanOrEqual" secondItem="mpK-CA-Lnn" secondAttribute="width" multiplier="0.85" id="F2v-hy-pn9"/>
<constraint firstItem="7Bs-WC-QCo" firstAttribute="leading" secondItem="2vd-KS-ll8" secondAttribute="leading" constant="12" id="KIV-td-SQh"/>
<constraint firstItem="2vd-KS-ll8" firstAttribute="trailing" secondItem="mpK-CA-Lnn" secondAttribute="trailing" constant="-8" id="P1I-QI-v0Y"/>
<constraint firstAttribute="bottom" secondItem="2vd-KS-ll8" secondAttribute="bottom" constant="8" id="VsS-Hf-Fv6"/>
<constraint firstItem="7Bs-WC-QCo" firstAttribute="trailing" secondItem="2vd-KS-ll8" secondAttribute="trailing" constant="-12" id="YAZ-d9-R8n"/>
<constraint firstItem="7Bs-WC-QCo" firstAttribute="bottom" secondItem="2vd-KS-ll8" secondAttribute="bottom" priority="999" constant="-12" id="ke7-OJ-E00"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="bubbleImageView" destination="2vd-KS-ll8" id="OIs-Qk-bNu"/>
<outlet property="documentsStack" destination="jKv-au-EZL" id="HU0-6P-C0b"/>
<outlet property="footerStack" destination="wQ2-iG-u2V" id="zUl-YI-Gh0"/>
<outlet property="imagesStack" destination="9wb-aV-6Ah" id="OlB-1t-tQ5"/>
<outlet property="messageStack" destination="Ykv-rE-DFT" id="SIz-up-iY1"/>
<outlet property="messageTextView" destination="xKc-db-bx1" id="805-2W-d4g"/>
<outlet property="outerStack" destination="7Bs-WC-QCo" id="bM8-CF-WYS"/>
<outlet property="timestamp" destination="83z-yh-Mfn" id="4hp-VP-93P"/>
</connections>
<point key="canvasLocation" x="489.85507246376818" y="264.17410714285711"/>
</tableViewCell>
</objects>
<resources>
<image name="checkmark.rectangle" catalog="system" width="128" height="93"/>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemOrangeColor">
<color red="1" green="0.58431372549019611" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemPurpleColor">
<color red="0.68627450980392157" green="0.32156862745098042" blue="0.87058823529411766" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
“文本视图像标签一样”类
class MyTextViewLabel: UITextView {
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
isEditable = false
isScrollEnabled = false
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
textContainerInset = .zero
textContainer.lineFragmentPadding = .zero
contentInset = .zero
dataDetectorTypes = .all
}
}
Cell 类
class RightStandardMessageCell: UITableViewCell {
@IBOutlet var bubbleImageView: UIImageView!
@IBOutlet var messageTextView: MyTextViewLabel!
@IBOutlet var timestamp: UILabel!
@IBOutlet var messageStack: UIStackView!
@IBOutlet var documentsStack: UIStackView!
@IBOutlet var imagesStack: UIStackView!
@IBOutlet var footerStack: UIStackView!
@IBOutlet var outerStack: UIStackView!
var debugColors: [UIColor] = []
var showDebugColors: Bool = false
var debugViews: [UIView] = []
override func awakeFromNib() {
super.awakeFromNib()
debugViews = [
contentView,
bubbleImageView, messageTextView, timestamp,
messageStack, documentsStack, imagesStack, footerStack,
outerStack,
]
debugViews.forEach { v in
debugColors.append(v.backgroundColor ?? .clear)
}
// because this is the "Right Standard" call
messageTextView.textAlignment = .right
}
override func layoutSubviews() {
super.layoutSubviews()
bubbleImageView.layer.cornerRadius = 12.0
bubbleImageView.layer.masksToBounds = true
for (v, c) in zip(debugViews, debugColors) {
v.backgroundColor = showDebugColors ? c : .clear
}
// always use the bubble image view background
bubbleImageView.backgroundColor = UIColor(red: 0.72, green: 0.80, blue: 0.90, alpha: 1.0)
contentView.backgroundColor = showDebugColors ? debugColors.first : .gray
}
}
和样品控制器
class MsgTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
var myData: [String] = [
"Hallo",
"This is a longer message.",
"Hier ist mal eine Nachricht welche sich über zwei Zeilen erstreckt.",
"Message with\nembedded\nnewline\ncharacters.",
"Message with data detection...\nhttps://apple.com\n770-555-1212\[email protected]"
]
var showDebugColors: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
// a button to toggle the cell's "debug" colors
let btn: UIButton = {
var cfg = UIButton.Configuration.filled()
cfg.title = "Toggle Debug Colors"
let b = UIButton(configuration: cfg)
b.addTarget(self, action: #selector(toggleDebugColors(_:)), for: .touchUpInside)
return b
}()
btn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(btn)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
btn.topAnchor.constraint(equalTo: g.topAnchor, constant: 12.0),
btn.centerXAnchor.constraint(equalTo: g.centerXAnchor),
tableView.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0),
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
])
tableView.register(UINib(nibName: "RightStandardMessageCell", bundle: nil), forCellReuseIdentifier: "c")
tableView.dataSource = self
tableView.delegate = self
}
// MARK: - Table view data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// we'll show the same data twice
// - first set with documentsStack and imagesStack hidden
// - second set with documentsStack and imagesStack showing
return myData.count * 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "c", for: indexPath) as! RightStandardMessageCell
cell.timestamp.text = "Row: \(indexPath.row)"
cell.messageTextView.text = myData[indexPath.row % myData.count]
// show the documentsStack and imagesStack for the 2nd set
cell.documentsStack.isHidden = indexPath.row < myData.count
cell.imagesStack.isHidden = indexPath.row < myData.count
cell.showDebugColors = self.showDebugColors
return cell
}
@objc func toggleDebugColors(_ sender: Any?) -> Void {
showDebugColors.toggle()
tableView.reloadData()
}
}
评论
UITextView
CanvasView
FragmentView
UITableView
bubbleImageView
UITextView
bubbleImageView
asset
UIView
评论