SwiftUI中如何将文本居中显示在黑色覆盖层内?
解决SwiftUI文本在渐变覆盖层内的居中定位问题
我在SwiftUI里遇到文本定位问题,没法把白色文本居中显示在底部的渐变覆盖层里,想要文本对齐到下图红线标记的黑框中部,试了各种对齐方式和padding设置都没达到预期效果。

相关代码片段
image .resizable() .aspectRatio(contentMode: .fill) .frame(width: customSize.width, height: customSize.height) .clipped() .overlay( VStack(alignment: .leading) { Spacer() HStack { VStack(alignment: .leading) { if let name = channel.tvgName { Text(formatTitle(name)) .font(.title3.bold()) .foregroundColor(.white) .lineLimit(1) .shadow(radius: 5) .padding(.all, 0) } else { Text(formatTitle(channel.tvgId ?? "")) .font(.title3.bold()) .foregroundColor(.white) .lineLimit(1) .shadow(radius: 5) .padding(.all, 0) } } Spacer() } .padding([.leading, .bottom, .trailing], 50) .background(LinearGradient( gradient: Gradient(colors: [Color.blue, Color.blue.opacity(0.1)]), startPoint: .bottom, endPoint: .top )) } ) .cornerRadius(10) .shadow(radius: 5)
完整视图代码
import SwiftUI import CachedAsyncImage struct ChannelDetailsView: View { var channel: PlaylistItem var reader: GeometryProxy @State var customSize: CGSize = CGSize(width: 256, height: 418) @State private var showByGroup = UserDefaults.standard.bool(forKey: "showByGroup") var body: some View { VStack(spacing: 0) { if let logo = channel.tvgLogo { CachedAsyncImage(url: URL(string: logo)) { phase in switch phase { case .empty: ProgressView() .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.gray.opacity(0.3)) .cornerRadius(10) .frame(width: customSize.width, height: customSize.height) case .success(let image): image .resizable() .aspectRatio(contentMode: .fill) .frame(width: customSize.width, height: customSize.height) .clipped() .overlay( VStack(alignment: .leading) { Spacer() HStack { VStack(alignment: .leading) { if let name = channel.tvgName { Text(formatTitle(name)) .font(.title3.bold()) .foregroundColor(.white) .lineLimit(1) .shadow(radius: 5) .padding(.all, 0) } else { Text(formatTitle(channel.tvgId ?? "")) .font(.title3.bold()) .foregroundColor(.white) .lineLimit(1) .shadow(radius: 5) .padding(.all, 0) } } Spacer() } .padding([.leading, .bottom, .trailing], 50) .background(LinearGradient( gradient: Gradient(colors: [Color.blue, Color.blue.opacity(0.1)]), startPoint: .bottom, endPoint: .top )) } ) .cornerRadius(10) .shadow(radius: 5) case .failure: Image(systemName: "play.display") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 50, height: 50) .padding() .background(Color.gray.opacity(0.3)) .cornerRadius(10) .frame(width: customSize.width, height: customSize.height) @unknown default: EmptyView() } } } } .onAppear(perform: { customSize = reader.size }) .frame(width: customSize.width, height: customSize.height) .background(Color.black.opacity(0.2)) .cornerRadius(10) .shadow(radius: 5) .onAppear { print("width: \(reader.size.width)") print("height: \(reader.size.height)") } .onChange(of: reader.size) { oldValue, newValue in customSize = newValue } } func formatTitle(_ title: String) -> String { var formattedTitle = title formattedTitle = formattedTitle.replacingOccurrences(of: "4K", with: "", options: .caseInsensitive) let regex = try! NSRegularExpression(pattern: "\\(\\d{4}\\)", options: []) formattedTitle = regex.stringByReplacingMatches(in: formattedTitle, options: [], range: NSRange(location: 0, length: formattedTitle.count), withTemplate: "") formattedTitle = formattedTitle.trimmingCharacters(in: .whitespacesAndNewlines) return formattedTitle } } extension View { func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { clipShape(RoundedCorner(radius: radius, corners: corners)) } } struct RoundedCorner: Shape { var radius: CGFloat = .infinity var corners: UIRectCorner = .allCorners func path(in rect: CGRect) -> Path { let path = UIBezierPath( roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius) ) return Path(path.cgPath) } }
解决方案
问题根源在于嵌套布局的对齐设置冗余,以及过度padding挤压文本空间,调整方式如下:
修改后的核心代码片段
image .resizable() .aspectRatio(contentMode: .fill) .frame(width: customSize.width, height: customSize.height) .clipped() .overlay( VStack { Spacer() HStack { Text(formatTitle(channel.tvgName ?? channel.tvgId ?? "")) .font(.title3.bold()) .foregroundColor(.white) .lineLimit(1) .shadow(radius: 5) .frame(maxWidth: .infinity, alignment: .center) } .padding([.leading, .bottom, .trailing], 20) .background(LinearGradient( gradient: Gradient(colors: [Color.blue, Color.blue.opacity(0.1)]), startPoint: .bottom, endPoint: .top )) } ) .cornerRadius(10) .shadow(radius: 5)
关键调整点
- 移除外层
VStack的.leading对齐,保留Spacer确保渐变层贴在图片底部 - 简化文本判断逻辑,用
channel.tvgName ?? channel.tvgId ?? ""合并分支 - 给
Text添加.frame(maxWidth: .infinity, alignment: .center),强制文本在渐变层宽度范围内居中 - 缩小渐变层的padding值(从50改为20,可按需调整),避免内边距过大导致文本偏移
内容的提问来源于stack exchange,提问作者Damiano Miazzi
相关产品推荐
相关产品推荐

