iOS聊天机器人OpenAI API动态表格网格样式优化问询
优化iOS中NSAttributedString表格的行列分隔线方案
1. 自定义表格富文本构建逻辑
放弃依赖OpenAI返回的纯文本分隔线,在visitTable(_ table: Table)方法中手动构建带专业边框样式的表格富文本,完全控制分隔线的样式:
mutating internal func visitTable(_ table: Table) -> NSAttributedString { let mutableAttributedString = NSMutableAttributedString() // 计算列宽(基于屏幕宽度减去边距后均分) let totalAvailableWidth = UIScreen.main.bounds.width - 40 let columnCount = table.header?.cells.count ?? table.rows.first?.cells.count ?? 0 guard columnCount > 0 else { return mutableAttributedString } let columnWidth = totalAvailableWidth / CGFloat(columnCount) // 处理表头 if let header = table.header { let headerRow = buildStyledTableRow(cells: header.cells, columnWidth: columnWidth, isHeader: true) mutableAttributedString.append(headerRow) // 添加加粗的表头底部分隔线 let headerSeparator = NSAttributedString(string: "\n", attributes: [ NSAttributedString.Key.strokeColor: UIColor.black, NSAttributedString.Key.strokeWidth: 2.0 ]) mutableAttributedString.append(headerSeparator) } // 处理表格行 for row in table.rows { let rowString = buildStyledTableRow(cells: row.cells, columnWidth: columnWidth, isHeader: false) mutableAttributedString.append(rowString) // 添加细灰色的行分隔线 let rowSeparator = NSAttributedString(string: "\n", attributes: [ NSAttributedString.Key.strokeColor: UIColor.lightGray, NSAttributedString.Key.strokeWidth: 1.0 ]) mutableAttributedString.append(rowSeparator) } return mutableAttributedString } // 辅助方法:构建带样式的单行富文本 private func buildStyledTableRow(cells: [TableCell], columnWidth: CGFloat, isHeader: Bool) -> NSAttributedString { let rowMutableString = NSMutableAttributedString() let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center paragraphStyle.lineBreakMode = .byWordWrapping // 单元格基础样式 let baseAttributes: [NSAttributedString.Key: Any] = [ .font: isHeader ? UIFont.boldSystemFont(ofSize: 16) : UIFont.systemFont(ofSize: 14), .paragraphStyle: paragraphStyle, .foregroundColor: isHeader ? UIColor.darkGray : UIColor.black ] for (index, cell) in cells.enumerated() { // 用Markdownosaur解析单元格内的高亮内容 let cellContent = visitTableCell(cell) let styledCellContent = NSMutableAttributedString(attributedString: cellContent) styledCellContent.addAttributes(baseAttributes, range: NSRange(location: 0, length: styledCellContent.length)) // 添加左侧边框 let leftBorder = NSAttributedString(string: "| ", attributes: [ .strokeColor: UIColor.lightGray, .strokeWidth: 1.0 ]) rowMutableString.append(leftBorder) rowMutableString.append(styledCellContent) // 添加右侧边框(最后一列单独处理) if index == cells.count - 1 { let rightBorder = NSAttributedString(string: " |", attributes: [ .strokeColor: UIColor.lightGray, .strokeWidth: 1.0 ]) rowMutableString.append(rightBorder) } } rowMutableString.append(NSAttributedString(string: "\n")) return rowMutableString }
2. 修改Markdownosaur的表格分隔线解析规则
如果希望保留原有Markdown解析流程,仅替换分隔线样式,可以修改Markdownosaur中处理表格分隔线的逻辑,将纯文本---|---转换为带下划线样式的富文本:
// 在Markdownosaur的表格解析模块中添加此方法 func parseStyledTableSeparator(_ separatorLine: String) -> NSAttributedString { let separatorAttributes: [NSAttributedString.Key: Any] = [ .underlineStyle: NSUnderlineStyle.single.rawValue, .underlineColor: UIColor.black, .font: UIFont.systemFont(ofSize: 1) // 缩小字体让下划线更贴合专业表格样式 ] // 清理分隔线中的竖线,替换为空格避免干扰 let cleanSeparator = separatorLine.replacingOccurrences(of: "|", with: " ") return NSAttributedString(string: cleanSeparator, attributes: separatorAttributes) }
3. 基于CoreText的自定义绘制(最高自由度)
若需要极致的样式控制(如圆角边框、渐变线条等),可以在承载富文本的控件子类中重写draw(_ rect: CGRect)方法,直接用CoreText绘制表格边框:
// 自定义UITextView子类 class TableTextView: UITextView { override func draw(_ rect: CGRect) { super.draw(rect) guard let tableAttrString = self.attributedText else { return } let context = UIGraphicsGetCurrentContext() guard let ctx = context else { return } // 配置边框样式 ctx.setStrokeColor(UIColor.lightGray.cgColor) ctx.setLineWidth(1.0) // 计算列分隔线位置 let columnCount = 5 // 根据实际表格列数动态获取 let totalWidth = self.bounds.width - 40 let columnWidth = totalWidth / CGFloat(columnCount) // 绘制列分隔线 for columnIndex in 1..<columnCount { let xPos = 20 + columnWidth * CGFloat(columnIndex) ctx.move(to: CGPoint(x: xPos, y: 20)) ctx.addLine(to: CGPoint(x: xPos, y: self.bounds.height - 20)) ctx.strokePath() } // 绘制行分隔线(需根据文本布局计算行高和位置) // 可通过CoreText的CTFramesetter获取每行的位置信息,此处省略具体实现 } }
内容的提问来源于stack exchange,提问作者artit
相关产品推荐
相关产品推荐

