在 SwiftUI 的按钮中放置背景图像和文本/图标?

时间:2021-02-03 16:27:40

标签: swiftui

我正在尝试在 SwiftUI 中实现这样的目标:

enter image description here

我可以创建带有圆角的按钮,我也可以将文本放在它的中心,但仅此而已。

我需要能够在顶部放置背景图像和页脚标题/文本和图标!

这是我目前所拥有的:

                            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") 由于某种原因在按钮之外!

有人可以指导我如何实现这一目标吗?

值得一提的是,背景图片来自远程服务器。

3 个答案:

答案 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
            }
        }
    }

enter image description here

答案 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))
    }
        

这就是最终结果的样子:

enter image description here