在 SwiftUI 的按钮中放置背景图像和文本/图标?
Posted
技术标签:
【中文标题】在 SwiftUI 的按钮中放置背景图像和文本/图标?【英文标题】:Placing background image and text/icon in a button in SwiftUI? 【发布时间】:2021-02-03 16:27:40 【问题描述】:我正在尝试在 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")
由于某种原因不在按钮之外!
有人可以指导我如何实现这一目标吗?
值得一提的是,背景图片来自远程服务器。
【问题讨论】:
【参考方案1】:首先,为了处理加载图像的后端,创建一个处理状态和网络的 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, 对齐方式:)
在没有太多额外视图的情况下有效地构建您的叠加视图。 ?
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
【讨论】:
这也很棒。如果背景图片在远程服务器上怎么办? 只需构建一个简单的 ImageLoader 对象,它关心 URLSession、加载状态等……然后将Image("Tomb_Raider")
替换为您的 ImageLoader 对象。 ?
我会在我的答案中添加更多内容,以便提供适当的详细信息?
来了!我在那里详细一点。希望它可以帮助您更好地理解一种处理方式?玩得开心!【参考方案2】:
将框架和背景修饰符移动到 hstack:
HStack
Image(systemName: "pencil").renderingMode(.template)
Spacer()
Text("title goes here")
Spacer()
.frame(width: 160, height: 200)
.background(Color.gray)
您还可以在Image
和Text
之间添加Spacer()
,在Text
之后添加Spacer()
,以正确对齐所有内容
【讨论】:
【参考方案3】:有很多元素可以让它正确,所以我在下面的相关位置放置了 cmets。
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))
这就是最终结果的样子:
【讨论】:
这太棒了。感谢cmets。如果背景图片在远程服务器上怎么办? 没问题。我已经从这里下载了图片:upload.wikimedia.org/wikipedia/en/thumb/2/29/… 并将其放在资产目录中 抱歉,我的意思是如果远程加载背景图片会怎样。 不,不是。它保存在本地。我想构建一些东西来回答你的布局问题 很公平!很感激。以上是关于在 SwiftUI 的按钮中放置背景图像和文本/图标?的主要内容,如果未能解决你的问题,请参考以下文章
我可以在 SwiftUI 的单个列表部分中放置多个文本行吗?