我正在尝试在 SwiftUI 中实现这样的目标:
我可以创建带有圆角的按钮,我也可以将文本放在它的中心,但仅此而已。
我需要能够在顶部放置背景图像和页脚标题/文本和图标!
这是我目前所拥有的:
Button(action: {
//self.dismiss?()
})
{
HStack(spacing: 10) {
Image(systemName: "pencil").renderingMode(.template)
Text(audio.name)
//.font(.headline)
.frame(width: 160, height: 200)
.background(Color.gray)
.addBorder(Color.white, width: 1, cornerRadius: 10)
}
}
当我尝试我的代码时,我得到一个带圆角的按钮,文本在中间,但 Image(systemName: "pencil")
由于某种原因在按钮之外!
有人可以指导我如何实现这一目标吗?
值得一提的是,背景图片来自远程服务器。
答案 0 :(得分:3)
首先,为了处理加载图像的后端,创建一个处理状态和网络的 Observable 对象。
import Combine
class ImageManager: ObservableObject {
// Property that fires an update onto the interface when it has any changes to its value
@Published var image: UIImage? = nil
init(link: String) {
// Standard way of loading data from a link.
guard let url = URL(string: link) else { return }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
// handle the error here !
print(error)
} else if let data = data {
// Never forget to update on the main thread ! ?
DispatchQueue.main.async {
self.image = UIImage(data: data)
}
}
}
task.resume()
}
}
其次,构建处理与 Observable 对象通信的 Image 视图,如下所示:
struct ImageLoader: View {
// The property wrapper '@ObservedObject' makes our ImageLoader change its interface according to updates received from our ImageManager
@ObservedObject private var manager: ImageManager
init(link: String) {
manager = ImageManager(link: link)
}
var body: some View {
Image(uiImage: manager.image ?? UIImage())
.resizable()
.aspectRatio(contentMode: .fill)
// Make the view greyish as long there is no image loaded to present
.redacted(reason: manager.image == nil ? .placeholder:[])
}
}
第三,构建最终视图。您可以使用叠加层在卡片顶部添加视图以及
<块引用>.frame(maxWidth:, maxHeight, alignment:)
有效地构建您的叠加视图,而无需过多的附加视图。 ?
struct MovieCard: View {
@State var thumbnailLink = "https://media.senscritique.com/media/000010045541/source_big/Tomb_Raider.png"
var body: some View {
ImageLoader(link: thumbnailLink)
.frame(width: 200, height: 200)
// Overlay is a very simple way to add content on top of your view ! ?
.overlay(
VStack {
// Using the system heart icon see https://developer.apple.com/sf-symbols/
Image(systemName: "suit.heart.fill")
.font(.title3)
.padding()
// Using maxWidth, maxHeight and alignement is usefull to not use additionnal views in your code (such as spacers, stacks, etc…)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.foregroundColor(.red)
Text("Movie title")
.font(Font.body.bold())
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(Color.red.opacity(0.7))
}
)
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
.shadow(color: Color.black.opacity(0.3), radius: 6, x: 0, y: 3)
.onTapGesture {
// Handle the action when the card is touched
}
}
}
答案 1 :(得分:2)
将框架和背景修饰符移动到 hstack:
HStack {
Image(systemName: "pencil").renderingMode(.template)
Spacer()
Text("title goes here")
Spacer()
}.frame(width: 160, height: 200)
.background(Color.gray)
}
您还可以在 Spacer()
和 Image
之间添加一个 Text
,在 Spacer()
之后添加一个 Text
,以正确对齐所有内容
答案 2 :(得分:2)
有很多元素可以使它正确,所以我在下面的相关位置发表了评论。
Button(action: { }) {
Image("Tomb_Raider")
//declare your image as resizable, otherwise it will keep its original size
.resizable()
//declare the frame of the image (i.e. the size you want it to resize to)
.frame(width: 160, height: 200)
// place the red rectangle with text in an overlay
// as opposed to HStack where elements are side by side
// here the image will be placed under the rest
.overlay(
//This HStack places the text in the middle with some padding
HStack {
Spacer()
Text("Title goes Here")
.font(.headline)
.foregroundColor(.white)
.padding(.vertical)
Spacer()
}
//set the background of the text to be semitransparent red
.background(Color.red.opacity(0.6)),
//this defines the alignment of the overlay
alignment: .bottom)
//clip everything to get rounded corners
.clipShape(RoundedRectangle(cornerRadius: 10))
}
这就是最终结果的样子: