Compare commits

..

3 Commits

Author SHA1 Message Date
fish 9ce3991de2 修复输入动画边框被裁剪问题
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-20 21:39:42 +08:00
fish bae0af27ef 拼写输入短词居中长词可滚动
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-20 21:37:18 +08:00
fish 3f5e4cad41 拼写输入框支持水平滚动,避免长单词被压缩
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-20 21:34:18 +08:00
@@ -5,6 +5,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
private let hiddenField = UITextField()
private let stack = UIStackView()
private let scrollView = UIScrollView()
private var chars: [String] = []
private var blankPositions: [Int] = []
@@ -20,18 +21,31 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.clipsToBounds = false
addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
stack.axis = .horizontal
stack.spacing = 6
stack.alignment = .center
stack.isUserInteractionEnabled = true
addSubview(stack)
scrollView.addSubview(stack)
stack.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stack.topAnchor.constraint(equalTo: topAnchor),
stack.bottomAnchor.constraint(equalTo: bottomAnchor),
stack.centerXAnchor.constraint(equalTo: centerXAnchor),
stack.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor),
stack.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor)
stack.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
stack.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
stack.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
stack.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor)
])
hiddenField.delegate = self
@@ -126,17 +140,9 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
private func rebuildBoxes() {
stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
let count = CGFloat(max(chars.count, 1))
let available = (window?.screen.bounds.width ?? 390) - 32
var spacing: CGFloat = 6
var boxWidth = (available - spacing * (count - 1)) / count
if boxWidth < 16 {
spacing = 3
boxWidth = (available - spacing * (count - 1)) / count
}
boxWidth = min(36, boxWidth)
stack.spacing = spacing
let fontSize = min(22, max(12, boxWidth * 0.62))
let boxWidth: CGFloat = 32
let fontSize: CGFloat = 20
stack.spacing = 6
boxViews = chars.enumerated().map { index, ch in
let box = makeBox(fontSize: fontSize)
box.tag = index
@@ -153,6 +159,22 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
return box
}
refreshBoxes()
DispatchQueue.main.async { [weak self] in
self?.updateAlignment()
}
}
private func updateAlignment() {
let totalWidth = CGFloat(chars.count) * 32 + CGFloat(max(chars.count - 1, 0)) * 6
let available = scrollView.bounds.width
if totalWidth <= available {
let inset = max(0, (available - totalWidth) / 2)
scrollView.contentInset = UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
scrollView.isScrollEnabled = false
} else {
scrollView.contentInset = .zero
scrollView.isScrollEnabled = true
}
}
@objc private func boxTapped(_ gesture: UITapGestureRecognizer) {