TIL: Swift UI 문제해결과정(1) 2025.06.23 ~ 2025.06.24

박춘팔·2025년 6월 23일
0

Swift TIL

목록 보기
6/9

스위프트UI를 공부하면서 아이폰 계산기 앱을 클론해보고 있다.

그러다가 문제가 생기는 부분이 Text와 관련되어서 그부분을 작성 해보려고 한다.

Text를 이용한 계산기 값 출력 부분 코드

HStack {
                    Spacer()

                    if textWidth <= 400 {
                        Text(total)
                            .padding()
                            .font(.system(size: computedFontSize))
                            .minimumScaleFactor(minFontSize / maxFontSize)
                            .foregroundColor(.white)
                            .lineLimit(1)
                            .background(GeometryReader {
                                proxy in Color.clear.preference(key: FontSizePreferenceKey.self, value: proxy.size.width)
                            })
                            .onPreferenceChange(FontSizePreferenceKey.self) { value in
                                textWidth = value
                            }

                    } else {
                        ScrollView(.horizontal, showsIndicators: false) {
                            Text(total)
                                .padding()
                                .font(.system(size: computedFontSize))
                                .foregroundColor(.white)
                                .lineLimit(1)
                                .fixedSize()
                        }
                        .background(GeometryReader {
                            proxy in Color.clear.preference(key: FontSizePreferenceKey.self, value: proxy.size.width)
                        })
                        .onPreferenceChange(FontSizePreferenceKey.self) { value in
                            textWidth = value
                        }
                    }

                }.onPreferenceChange(FontSizePreferenceKey.self) {
                    value in textWidth = value
                }
                .background(GeometryReader {
                    proxy in Color.clear
                        .onAppear {
                            containerWidth = proxy.size.width - 40
                        }
                        .onChange(of: proxy.size.width) {
                            _, newValue in containerWidth = newValue
                        }
                })

단순 값 출력이 뭐가 코드가 이렇게 길어? 할 수 있지만 초보라서 어쩔수 없다.

어쩌다 문제가 발생했을까

디테일을 챙기려다보니 문제가 발생한 것인데 어떤 디테일이냐면

아이폰 계산기에서는 숫자를 입력하면 디바이스의 width만큼 숫자가 늘어나다가 점점 숫자가 작아진다. 그러다가 임계점에 도달하면 단순 Text였던 뷰에 ScrollView가 래핑되어 좌우로 스크롤이 가능해진다.

그래서 내가 생각한 방법은

  1. 최대 폰트 크기(72) 시작
  2. Text의 minimumScaleFactor(0.5) 사용
  3. font size 옵저빙하다 최소 폰트 크기(36) 도달 시 scrollView로 레이아웃 변경

진행 도중 3번에서 문제가 발생했는데 Swift에서 minimumScaleFactor로 줄어든 fontSize를 반환해주거나 하지 않기 때문에 직접 계산을 해야한다는 것

그래서 구글링 해보니 레딧에서 두가지 방법으로 해결이 가능하다는 글을 보고 수정을 진행해봤다.

해결 가능한 방법

1. GeometryReader + onPreferenceChange

Text(total)
	.padding()
	.font(.system(size: computedFontSize))
	.minimumScaleFactor(minFontSize / maxFontSize)
	.foregroundColor(.white)
	.lineLimit(1)
	.background(GeometryReader { proxy in 
                Color.clear.preference(key: FontSizePreferenceKey.self, value: proxy.size.width)
	})
   	.onPreferenceChange(FontSizePreferenceKey.self) { value in
    			textWidth = value
	}

GeometryReader 와 onPreferenceChange란 무엇인가?

GeometryReader는 공식 doc에서 그 자체로 뷰이며 컨테이너 안 뷰의 위치와 크기를 함수로 정의한다고 설명한다.

나는 이 GeometryReader로 fontsize를 얻을 수 있기를 기대했으나 오로지 width값을 얻을 수 있었다.

그래서 역산해보려고 했으나 minimumScaleFactor가 fontsize를 얼만큼 작아지게하는지 어떤 비율을 적용하는지 알 방도가 없고 내가 알 수 있는 정보들은 총 텍스트의 width값고 디바이스의 witdh가 끝이었다.

2. UIKit UILabel의 adjustsFontSizeToFitWidth

TextSizeReader(
    text: total,
    font: UIFont.systemFont(ofSize: computedFontSize),
    minimumScaleFactor: minFontSize / maxFontSize,
    actualFontSize: $actualRenderedFontSize
)

이부분은 내일 적용해보고 업데이트 하도록 하겠다.

++ 2025.06.24 추가

아침에 일어나서 UIKit을 사용한 코드를 적용해보려고 했으나
다른 좋은 방법이 떠올랐다!

1번 방법의 계산 대상을 수정하는게 더 정확하겠는데? 라는 생각이 들었고
기존 계산 대상을 textWidth로 하고 있었는데 State변수 textheight를 추가했다.

1번의 가장 큰 문제가 minimumScaleFactor로 인해 가변으로 줄어드는 fontsize를 가져올 수 있는 방법이 없는것이었는데 대상을 textheight로 하게되면 정확하게 maxFontSize의 값과 일치하지는 않지만 fontSize + lineHeight 값이 나오게되고 가변으로 줄어드는 fontSize를 비교적 쉽게 유추 할 수 있다.

@State private var textHeight:CGFloat = 0

Text(total)
	.padding()
	.font(.system(size: computedFontSize))
	.minimumScaleFactor(minFontSize / maxFontSize)
	.foregroundColor(.white)
	.lineLimit(1)
	.background(GeometryReader { proxy in 
                Color.clear.preference(key: FontSizePreferenceKey.self, value: proxy.size.width)
	 // 윗줄 value: proxy.size.width -> proxy.size.height
	})
   	.onPreferenceChange(FontSizePreferenceKey.self) { value in
    			textHeight = value
	}
profile
이것 저것 다해보는 삶

0개의 댓글