-
[아이매드] - SwiftUI 더보기 버튼프로젝트/아이매드 2023. 4. 18. 17:14728x90반응형
요즘 프로젝트 제작에 많이 힘쓰고 있다.
프로젝트를 하던 중 특정 텍스트가 길어질 경우 앞 일부분만 사용자에게 보여주고 더 보고 싶을때 펼쳐서 볼 수 있는 더보기 기능이 필요했다. 텍스트 길이에 따른 높이를 계산하여 height를 설정해야 하고, 특정 줄 수 이하일 경우 더보기 버튼을 보여지지 않게 해야한다.
과정은 다음과 같다.
1. 전체 텍스트의 높이
2. 지정한 폰트에 따른 한줄의 텍스트 높이 * 초기 상태로 설정할 줄 수
3. 2와 3을 비교하여 더보기 버튼 추가 유무 설정
일단 하나씩 살펴보자
private func getHeightForText(_ text: String) -> CGFloat { let constraintRect = CGSize(width: UIScreen.main.bounds.width, height: .greatestFiniteMagnitude) let boundingBox = text.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil) return ceil(boundingBox.height) }
getHeightForText는 text의 전체 높이를 계산하는 함수이다. 매개변수로 텍스트를 받고 constraintRect에서 표시할 뷰의 박스 사이즈를 설정한다. 폭은 화면전체,높이는 무한대로 설정하는데 여기서 greatestFiniteMagnitude는 표현할 수 있는 가장 유효한 수로 최대한의 높이를 나타내는 것이다. 그런데 기존에 많이 사용하는 .infinity를 쓰지 않았다. 둘다 무한대를 나타나는 상수다. 한번 차이점을 보자
infinity : Double이나 Float에 사용되길 추천
greatestFiniteMagnitude : CGFloat에 사용되길 추천
혹시라도 CGFloat과 Float/Double의 차이를 모른다면 이곳을 들어가보길 추천한다.
그리고 text.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)로 텍스트의 높이를 계산하는데 우리가 설정한 계산할 박스 사이즈인 constraintRect와 usesLineFragmentOrigin를 사용하는데 이것은 글의 프레그먼트를 상단으로 설정하는 것이다 false로 설정할 경우 중간으로 설정된다. context는 텍스트의 색깔,크기,폰트등을 설정하는 것이나 필요가 없어서 nil로 설정하였다.
마지막으로 ceil을 함수로 계산한 높이의 실수를 올림하여 정수 형태로 반환한다. (반올림의 경우 문자열을 자를 우려가 있음)
private var shouldShowMoreButton:Bool { let textHeight = getHeightForText(text) let lineHeight = UIFont.preferredFont(forTextStyle: font).lineHeight let maxTextHeight = CGFloat(maxLines) * lineHeight print("\(textHeight) \(lineHeight) \(maxTextHeight)") return textHeight > maxTextHeight }
이 함수의 결과에 따라 더보기 버튼의 표시 유무를 결정한다.
우리가 계산한 전체 텍스트의 전체 높이와 특정 폰트의 높이를 계산하고 그 폰트의 높이의 보여줄 라인수를 곱하여 비교한다.
전체코드
struct ExpandableTextView: View { let text: String let maxLines: Int let font:UIFont.TextStyle @State private var expanded = false var body: some View { VStack(alignment: .leading){ HStack{ if expanded { Text(text) .lineLimit(nil) } else { Text(text) .lineLimit(maxLines) } Spacer() } .font(Font(UIFont.preferredFont(forTextStyle: font))) if shouldShowMoreButton{ Button(action: { withAnimation(.linear){ expanded.toggle() } }, label: { HStack{ Text(expanded ? "접기" : "더보기") Image(systemName: expanded ? "chevron.up" : "chevron.down") }.foregroundColor(.gray) .font(.caption) }) .padding(.top) } } } private var shouldShowMoreButton:Bool { let textHeight = getHeightForText(text) let lineHeight = UIFont.preferredFont(forTextStyle: font).lineHeight let maxTextHeight = CGFloat(maxLines) * lineHeight print("\(textHeight) \(lineHeight) \(maxTextHeight)") return textHeight > maxTextHeight } private func getHeightForText(_ text: String) -> CGFloat { let constraintRect = CGSize(width: UIScreen.main.bounds.width, height: .greatestFiniteMagnitude) let boundingBox = text.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil) return ceil(boundingBox.height) } }
'프로젝트 > 아이매드' 카테고리의 다른 글
[아이매드] - SwiftUI로 StickyView 만들기 (0) 2024.07.28 [아이매드]- 배포 후 두번째 리젝(Guideline 1.2 - Safety - User-Generated Content, Guideline 1.5 - Safety) (1) 2024.07.24 [아이매드]- 배포 후 첫번째 리젝(Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage) (0) 2024.07.24 [아이매드]- 배포 후 첫번째 리젝(Guideline 1.2 - Safety - User-Generated Content) (0) 2024.07.24 [아이매드] - SwiftUI로 사진 선택 후 이미지 규격 변경하기 (0) 2024.07.17