import SwiftUI struct MainHomeBusinessInfoSection: View { var body: some View { BusinessInfoExpandableTextView( text: I18n.Settings.companyInfo, lineLimit: 3, moreTitle: I18n.HomeRecommendation.more, collapseTitle: I18n.HomeRecommendation.collapse, font: .body5, foregroundColor: Color.gray500 ) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, SodaSpacing.s14) } } private struct BusinessInfoExpandableTextView: View { let text: String let lineLimit: Int let moreTitle: String let collapseTitle: String let font: SodaTypography let foregroundColor: Color @State private var isExpanded = false @State private var fullTextHeight: CGFloat = 0 @State private var limitedTextHeight: CGFloat = 0 var body: some View { VStack(alignment: .leading, spacing: SodaSpacing.s8) { Text(text) .appFont(font) .foregroundColor(foregroundColor) .lineLimit(isExpanded ? nil : lineLimit) .background(measuringText(lineLimit: nil, height: $fullTextHeight)) .background(measuringText(lineLimit: lineLimit, height: $limitedTextHeight)) if fullTextHeight > limitedTextHeight + 1 { Button { isExpanded.toggle() } label: { Text(isExpanded ? collapseTitle : moreTitle) .appFont(.body5) .foregroundColor(.white) } .buttonStyle(.plain) } } } private func measuringText(lineLimit: Int?, height: Binding) -> some View { Text(text) .appFont(font) .lineLimit(lineLimit) .fixedSize(horizontal: false, vertical: true) .hidden() .background( GeometryReader { proxy in Color.clear .onAppear { height.wrappedValue = proxy.size.height } .onChange(of: proxy.size.height) { newHeight in height.wrappedValue = newHeight } .onChange(of: text) { _ in height.wrappedValue = proxy.size.height } } ) } } struct MainHomeBusinessInfoSection_Previews: PreviewProvider { static var previews: some View { MainHomeBusinessInfoSection() .padding(.vertical, SodaSpacing.s20) .background(Color.black) .previewLayout(.sizeThatFits) } }