SwiftUI实现跨视图圆形头像与指定顶部圆角的视图问题
SwiftUI个人中心界面:头像下方视图添加左上/右上圆角问题
我正在学习SwiftUI,要实现类似截图的个人中心界面,已经完成背景图和圆形头像的设置,但无法为头像下方的视图添加左上、右上圆角,不清楚该为哪个视图设置。以下是我的实现代码:
struct ProfileMainView: View { @EnvironmentObject var profile: ProfileViewModel @EnvironmentObject var carouselState: CarouselStateModel @EnvironmentObject var profileManager: ProfileManager @State var showExpose: Bool = false @State private var editMode = false @State private var viewMode = true @State private var shouldDisplayProfileCreation = false @State private var errorMessage = "" @State private var showError = false @EnvironmentObject var shippingAddressManager: ShippingAddressManager @State private var authDelegate: AuthDelegate? @State private var searchText = "" @State private var isEditMode = false @EnvironmentObject var userPaymentManager: UserPaymentManager let payments = [ PayModel(number: "4444", fullname: "", source: PaymentTender.Source.visa), PayModel(number: "1414", fullname: "", source: PaymentTender.Source.visa), PayModel(number: "2020", fullname: "", source: PaymentTender.Source.visa) ] let fav = ["beltBar", "beltBar"] var body: some View { ScrollView(.vertical, showsIndicators: false) { VStack { // MARK: - Top View VStack { ZStack { Image("backgroundImage") .resizable() .frame(width: UIScreen.main.bounds.width, height: 150, alignment: .center) .background(Color.charcoalBg) .clipped() .overlay( HStack(alignment: .center) { if showExpose { WebImage(url: URL(string: profile.photo)) .onSuccess { image, data, cacheType in } .resizable() .placeholder(Image("profilePic")) .indicator(.activity) .transition(.fade(duration: 0.5)) .scaledToFill() .frame(width: 100) .overlay(Circle().stroke(Color.white, lineWidth: 5)) .clipShape(Circle()) } else { WebImage(url: URL(string: profile.photo)) .onSuccess { image, data, cacheType in } .resizable() .placeholder(Image("profilePic")) .indicator(.activity) .transition(.fade(duration: 0.5)) .scaledToFill() .frame(width: 100) .overlay(Circle().stroke(Color.white, lineWidth: 5)) .clipShape(Circle()) } } .frame(height: 100, alignment: .center) .offset(y: 75) ) Spacer() HStack { Spacer() Button { print("notificationOnProfile button action") } label: { Image("notificationOnProfile") } } .padding(.trailing, 30) .padding(.top, 30) } } // MARK: - Profile Name View VStack(spacing: 5.0) { HStack(spacing: 4.0) { Text("Profile Name") .font(.custom("Roboto-Medium", size: (showExpose ? 16 : 16))) .foregroundColor(.black) Image("star") } Text("Email") .font(.custom("Roboto-Regular", size: 12)) .foregroundColor(Color.fontGrayProfile.opacity(0.6)) } .padding(EdgeInsets(top: 45, leading: 0, bottom: 0, trailing: 0)) // MARK: - Payments View VStack(alignment: .leading, spacing: 10) { HStack { Text("Payments") .foregroundColor(Color.fontGrayProfile) .font(.custom("Roboto-Medium", size: 14)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.leading, 20) .padding(.top, 14) Button { print("") } label: { Image("Pencil") .resizable() .frame(width: 20.0, height: 20.0) .padding(.trailing, 22) .padding(.top, 14) } } Divider().background(Color.black.opacity(0.1)) .padding([.leading, .trailing], 20) .padding(.bottom, 4) VStack(alignment: .leading, spacing: 17) { ForEach(payments) { int in Text("int\(int.title)") .padding(.bottom, 20) } } } .frame(maxWidth: .infinity) .cornerRadius(14) .background( Rectangle() .fill(Color.white) .cornerRadius(14) .shadow( color: Color(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, opacity: 0.1), radius: 20, x: 0, y: 0 ) ) .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) // MARK: - Shipping Address View VStack(alignment: .leading, spacing: 10) { HStack { Text("Shipping Address") .foregroundColor(Color.fontGrayProfile) .font(.custom("Roboto-Medium", size: 14)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.leading, 20) .padding(.top, 14) Button { print("") } label: { Image("Pencil") .resizable() .frame(width: 20.0, height: 20.0) .padding(.trailing, 22) .padding(.top, 14) } } Divider().background(Color.black.opacity(0.1)) .padding([.leading, .trailing], 20) .padding(.bottom, 4) VStack(alignment: .leading, spacing: 17) { ForEach(payments) { int in Text("int\(int.title)") .padding(.bottom, 20) } } } .frame(maxWidth: .infinity) .cornerRadius(14) .background( Rectangle() .fill(Color.white) .cornerRadius(14) .shadow( color: Color(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, opacity: 0.1), radius: 20, x: 0, y: 0 ) ) .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) } .alert(isPresented: $showError) { Alert(title: Text(AppConstants.appName), message: Text(errorMessage), dismissButton: .default(Text("OK"))) } .navigationBarHidden(true) } .edgesIgnoringSafeArea(.all) } }
解决方案
要实现头像下方视图的左上、右上圆角,你需要把**头像下方的所有内容(Profile Name、Payments、Shipping Address等)**统一包裹在一个容器中,给这个容器设置顶部圆角,具体操作如下:
- 新建一个
VStack,将Profile Name View、Payments View、Shipping Address View全部移入其中,给这个容器设置白色背景和仅顶部的圆角:
// 替换原代码中头像下方的三个View部分 VStack { // MARK: - Profile Name View VStack(spacing: 5.0) { HStack(spacing: 4.0) { Text("Profile Name") .font(.custom("Roboto-Medium", size: (showExpose ? 16 : 16))) .foregroundColor(.black) Image("star") } Text("Email") .font(.custom("Roboto-Regular", size: 12)) .foregroundColor(Color.fontGrayProfile.opacity(0.6)) } .padding(EdgeInsets(top: 45, leading: 0, bottom: 0, trailing: 0)) // MARK: - Payments View VStack(alignment: .leading, spacing: 10) { // 原Payments View内容 } .frame(maxWidth: .infinity) .background(Color.white) .cornerRadius(14) .shadow(color: Color.black.opacity(0.1), radius: 20, x: 0, y: 0) .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) // MARK: - Shipping Address View VStack(alignment: .leading, spacing: 10) { // 原Shipping Address View内容 } .frame(maxWidth: .infinity) .background(Color.white) .cornerRadius(14) .shadow(color: Color.black.opacity(0.1), radius: 20, x: 0, y: 0) .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) } .background(Color.white) .cornerRadius(14, corners: [.topLeft, .topRight]) .clipped()
简化原卡片的背景设置:移除原
background中的Rectangle,直接给容器设置background(Color.white)和cornerRadius,避免重复设置导致的视觉冲突。确保最外层布局衔接自然:顶部背景图和下方圆角容器之间不要留间隙,这样就能实现背景图下方接带顶部圆角的白色区域,和目标效果一致。
内容的提问来源于stack exchange,提问作者SwiftNewbie
相关产品推荐
相关产品推荐

