fix(diary): keep pencil strokes sharp at any zoom level
페이지가 논리 768×1024pt 고정 + 스케일 변환이라 PKCanvasView 래스터가 비정수 축소에선 뭉개지고 확대에선 픽셀이 보였음 → 캔버스(내부 렌더 뷰 포함)의 contentScaleFactor를 기본 1.5배 슈퍼샘플링 + 줌 배율 추종(기기 스케일 ×2.5 상한)으로 조정. 레이아웃 변경과 핀치 종료 시점에 갱신. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
This commit is contained in:
parent
8d4d20fc76
commit
5916e17b25
@ -288,6 +288,11 @@ private struct DiaryZoomContainer<Content: View>: UIViewRepresentable {
|
||||
func scrollViewDidZoom(_ scrollView: UIScrollView) {
|
||||
(scrollView as? DiaryZoomScrollView)?.centerZoomedView()
|
||||
}
|
||||
|
||||
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
|
||||
// 핀치가 끝난 배율에 맞춰 캔버스 래스터 해상도를 다시 맞춘다 (확대 시 픽셀 번짐 방지)
|
||||
(scrollView as? DiaryZoomScrollView)?.updateCanvasSharpness()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,6 +301,7 @@ final class DiaryZoomScrollView: UIScrollView {
|
||||
var pageSize: CGSize = DiaryPageMetrics.size
|
||||
weak var zoomedView: UIView?
|
||||
private var didSetInitialZoom = false
|
||||
private var lastCanvasScale: CGFloat = 0
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
@ -315,6 +321,7 @@ final class DiaryZoomScrollView: UIScrollView {
|
||||
didSetInitialZoom = true
|
||||
}
|
||||
centerZoomedView()
|
||||
updateCanvasSharpness()
|
||||
}
|
||||
|
||||
/// 콘텐츠가 화면보다 작을 때 가운데 정렬
|
||||
@ -325,6 +332,40 @@ final class DiaryZoomScrollView: UIScrollView {
|
||||
zoomedView.center = CGPoint(x: contentSize.width / 2 + dx,
|
||||
y: contentSize.height / 2 + dy)
|
||||
}
|
||||
|
||||
/// 펜슬 캔버스의 래스터 해상도를 현재 줌 배율에 맞춘다.
|
||||
/// 페이지는 논리 768×1024pt 고정이라 화면 fit/확대가 전부 스케일 변환인데,
|
||||
/// PKCanvasView는 자기 contentScaleFactor로만 래스터하므로 그대로 두면
|
||||
/// 축소 표시(비정수 배율 미니피케이션)에선 획이 뭉개지고 확대에선 픽셀이 보인다.
|
||||
/// → 기본 1.5배 슈퍼샘플링 + 확대 배율 추종(기기 스케일 × 최대 2.5)으로 항상 선명하게.
|
||||
func updateCanvasSharpness() {
|
||||
guard let zoomedView else { return }
|
||||
let display = max(traitCollection.displayScale, 1)
|
||||
let target = display * min(max(zoomScale, 1) * 1.5, 2.5)
|
||||
guard abs(target - lastCanvasScale) > 0.01 else { return }
|
||||
lastCanvasScale = target
|
||||
Self.applyCanvasScale(target, in: zoomedView)
|
||||
}
|
||||
|
||||
/// 서브트리에서 PKCanvasView를 찾아 자신+내부 렌더 뷰들의 contentsScale을 올린다
|
||||
private static func applyCanvasScale(_ scale: CGFloat, in view: UIView) {
|
||||
if view is PKCanvasView {
|
||||
setScaleRecursively(scale, view: view)
|
||||
return
|
||||
}
|
||||
for subview in view.subviews {
|
||||
applyCanvasScale(scale, in: subview)
|
||||
}
|
||||
}
|
||||
|
||||
private static func setScaleRecursively(_ scale: CGFloat, view: UIView) {
|
||||
view.contentScaleFactor = scale
|
||||
view.layer.contentsScale = scale
|
||||
view.setNeedsDisplay()
|
||||
for subview in view.subviews {
|
||||
setScaleRecursively(scale, view: subview)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 배치 요소 (사진/도형)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user