Skip to content

Commit e188949

Browse files
committed
Add tests for custom header items and button management in STMarkdownTableView
- Implemented testCustomHeaderItemsAreVisibleAfterLayout to verify visibility and layout of custom header buttons. - Added testReassigningHeaderItemsRemovesOldButtons to ensure old buttons are removed when header items are reassigned. - Enhanced STMarkdownTableView to rebuild button stack correctly when header items change, ensuring proper button management and layout.
1 parent cceeed5 commit e188949

2 files changed

Lines changed: 67 additions & 3 deletions

File tree

Example/STBaseProjectExampleTests/STMarkdownFixTests.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,47 @@ final class STMarkdownTableViewModelCitationTests: XCTestCase {
259259
@MainActor
260260
final class STMarkdownTableViewCitationTapTests: XCTestCase {
261261

262+
func testCustomHeaderItemsAreVisibleAfterLayout() {
263+
let image = self.makeTestIcon()
264+
let style = STMarkdownStyle(
265+
font: .systemFont(ofSize: 14),
266+
textColor: .label,
267+
lineHeight: 18,
268+
kern: 0,
269+
tableHeaderItems: [
270+
STMarkdownTableHeaderItem(identifier: "custom-copy", image: image) { _ in },
271+
STMarkdownTableHeaderItem(identifier: "custom-fullscreen", image: image) { _ in }
272+
],
273+
tableHeaderButtonWidth: 16
274+
)
275+
let tableView = STMarkdownTableView(style: style)
276+
277+
tableView.frame = CGRect(x: 0, y: 0, width: 320, height: 120)
278+
tableView.layoutIfNeeded()
279+
280+
let buttons = self.headerButtons(in: tableView)
281+
XCTAssertEqual(buttons.map(\.accessibilityIdentifier), ["custom-copy", "custom-fullscreen"])
282+
XCTAssertTrue(buttons.allSatisfy { !$0.frame.isEmpty }, "自定义 headerItems 按钮应有稳定非零布局尺寸")
283+
XCTAssertTrue(buttons.allSatisfy { $0.image(for: .normal) != nil }, "自定义 headerItems 按钮应保留配置的图片")
284+
}
285+
286+
func testReassigningHeaderItemsRemovesOldButtons() {
287+
let image = self.makeTestIcon()
288+
let tableView = STMarkdownTableView(style: .default)
289+
tableView.headerItems = [
290+
STMarkdownTableHeaderItem(identifier: "first", image: image) { _ in },
291+
STMarkdownTableHeaderItem(identifier: "second", image: image) { _ in }
292+
]
293+
tableView.headerItems = [
294+
STMarkdownTableHeaderItem(identifier: "third", image: image) { _ in }
295+
]
296+
297+
tableView.frame = CGRect(x: 0, y: 0, width: 320, height: 120)
298+
tableView.layoutIfNeeded()
299+
300+
XCTAssertEqual(self.headerButtons(in: tableView).map(\.accessibilityIdentifier), ["third"])
301+
}
302+
262303
func testCitationTapCallbackFiredWhenCellSelected() {
263304
let style = STMarkdownStyle.default
264305
let tableView = STMarkdownTableView(style: style)
@@ -481,4 +522,22 @@ final class STMarkdownTableViewCitationTapTests: XCTestCase {
481522
private func gradientLayer(named name: String, in view: UIView) -> CAGradientLayer? {
482523
view.layer.sublayers?.first(where: { $0.name == name }) as? CAGradientLayer
483524
}
525+
526+
private func headerButtons(in view: UIView) -> [UIButton] {
527+
view.subviews.flatMap { subview -> [UIButton] in
528+
var buttons = self.headerButtons(in: subview)
529+
if let button = subview as? UIButton {
530+
buttons.insert(button, at: 0)
531+
}
532+
return buttons
533+
}
534+
}
535+
536+
private func makeTestIcon() -> UIImage {
537+
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 16, height: 16))
538+
return renderer.image { context in
539+
UIColor.black.setFill()
540+
context.fill(CGRect(x: 3, y: 3, width: 10, height: 10))
541+
}
542+
}
484543
}

Sources/STMarkdown/Table/STMarkdownTableView.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ open class STMarkdownTableView: UIView {
160160
self.setupCollectionView()
161161
self.setupHeader()
162162
self.headerItems = style.tableHeaderItems ?? self.makeDefaultHeaderItems()
163+
self.rebuildButtonStack()
163164
self.applyStyle()
164165
}
165166

@@ -211,7 +212,7 @@ open class STMarkdownTableView: UIView {
211212

212213
self.buttonStack.trailingAnchor.constraint(equalTo: self.headerBar.trailingAnchor, constant: -10),
213214
self.buttonStack.centerYAnchor.constraint(equalTo: self.headerBar.centerYAnchor),
214-
self.buttonStack.heightAnchor.constraint(equalTo: self.headerBar.heightAnchor),
215+
self.buttonStack.heightAnchor.constraint(equalToConstant: Self.headerHeight),
215216

216217
self.headerSeparator.leadingAnchor.constraint(equalTo: self.headerBar.leadingAnchor),
217218
self.headerSeparator.trailingAnchor.constraint(equalTo: self.headerBar.trailingAnchor),
@@ -222,11 +223,13 @@ open class STMarkdownTableView: UIView {
222223

223224
/// 从 headerItems 重建 buttonStack 中的所有按钮,每次 headerItems 变更时调用。
224225
private func rebuildButtonStack() {
225-
self.buttonStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
226+
self.buttonStack.arrangedSubviews.forEach {
227+
self.buttonStack.removeArrangedSubview($0)
228+
$0.removeFromSuperview()
229+
}
226230
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 15, weight: .regular)
227231
let buttonWidth = self.style.tableHeaderButtonWidth
228232
let secondaryColor = (self.style.tableHeaderTextColor ?? self.style.textColor).withAlphaComponent(0.6)
229-
230233
for item in self.headerItems {
231234
let button = UIButton(type: .system)
232235
let isSystemSymbol = item.image?.isSymbolImage ?? false
@@ -235,7 +238,9 @@ open class STMarkdownTableView: UIView {
235238
}
236239
button.setImage(item.image, for: .normal)
237240
button.tintColor = secondaryColor
241+
button.imageView?.contentMode = .scaleAspectFit
238242
button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
243+
button.heightAnchor.constraint(equalToConstant: buttonWidth).isActive = true
239244
button.accessibilityIdentifier = item.identifier
240245
button.addAction(UIAction { [weak self] _ in
241246
guard let self else { return }

0 commit comments

Comments
 (0)