SwiftUI:如何查找图像的高度并使用它来设置框架的大小 [英] SwiftUI: How to find the height of an image and use it to set the size of a frame

查看:48
本文介绍了SwiftUI:如何查找图像的高度并使用它来设置框架的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我一直试图弄清楚如何在SwiftUI中找到图像的高度已经有一段时间了,但没有成功.本质上,我有纵向/横向图像,要在600 pt高处显示纵向图像,而横向图像则要显示,以便使用图像的宽度,因此高度不限.话虽如此,我想在GeometryReader中使用它,因为我正在使用的偏移量会使用它,因此当您向下滚动时,图像不会滚动,但是如果向上滚动,它会滚动.我不相信我可以共享图像,但是无论如何,这应该足以使它成功运行!

So I've been trying to figure out how to find the height of an image in SwiftUI for a while now with no success. Essentially I have portrait/landscape images, which the portrait ones I want to display at about 600 pt tall, whereas the landscape images I want to display so the width of the image is used, so the height is whatever. That being said, I'm wanting it inside of a GeometryReader, as the offset I am using uses it so that when you scroll down, the image doesn't scroll, but if you scroll up, it does. I don't believe I can share images, but in any case, this should be enough code to run it successfully!

struct ContentView: View {
    
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
  
    var backButton: some View {
        Button(action: {
            withAnimation {
                self.mode.wrappedValue.dismiss()
            }
        }) {
            Image(systemName: "chevron.left.circle.fill")
                .opacity(0.8)
                .font(.system(size: 30))
                .foregroundColor(.black)
                .background(Color.gray.mask(Image(systemName: "chevron.left").offset(x: 9.4, y: 7.6)))
                
        }
    }

    var body: some View {
        ScrollView(showsIndicators: false) {
            
                GeometryReader { geometry in
                    Image("image1")
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(maxWidth: UIScreen.main.bounds.width, minHeight: 350, maxHeight: 600, alignment: .top)
                        .clipped()
                        .overlay(
                            Rectangle()
                                .foregroundColor(.clear)
                                .background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
                        )
                       .offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)

                }
                .frame(minWidth: UIScreen.main.bounds.width, maxWidth: UIScreen.main.bounds.width, minHeight: 350, idealHeight: 600, maxHeight: 600)

                //Message
                VStack(alignment: .leading) {
                    Text("\(07/22/20) - Day \(1)")
                        .font(.body)
                        .fontWeight(.light)
                        .foregroundColor(Color.gray)
                        .padding(.leading)
                    Text("what I Love)
                        .font(.title)
                        .fontWeight(.bold)
                        .padding([.leading, .bottom])

                    Text("paragraph")
                        .padding([.leading, .bottom, .trailing])
                }
   
        }
        .edgesIgnoringSafeArea(.all)
        .navigationBarBackButtonHidden(true)
        .navigationBarItems(leading: backButton)
    }
}

任何帮助将不胜感激!

这是两张供参考的图片-抱歉,我没意识到您能够做到,尽管我早该想到了!

Here are two images for reference- Sorry I didn't realize you were able to, though I should've figured that!

推荐答案

如果我正确理解,您想要图像的大小,以便可以在其自己的框架中使用它的尺寸吗?您可以创建一个接受图像名称并返回所需图像的函数,同时还为您设置的 width height 设置 @State vars可以在框架中使用.

If I understood correctly, you want the size of the image so you can use it's dimensions in it's own frame? You could make a function that takes in an image name and returns your desired image while also setting @State vars for the width and height which you can use in the frame.

    @State var width: CGFloat = 0
    @State var height: CGFloat = 0
    
    func image(_ name: String) -> UIImage {
        let image = UIImage(named: name)!
        let width = image.size.width
        let height = image.size.height

        DispatchQueue.main.async {
            if width > height {
                // Landscape image
                // Use screen width if < than image width
                self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
                // Scale height
                self.height = self.width/width * height
            } else {
                // Portrait
                // Use 600 if image height > 600
                self.height = height > 600 ? 600 : height
                // Scale width
                self.width = self.height/height * width
            }
        }
        return image
    }

用法:

    GeometryReader { geometry in
        Image(uiImage: image("image1"))
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: width, height: height)
            .overlay(
                Rectangle()
                    .foregroundColor(.clear)
                    .background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
            )
            .offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)

添加了 DispatchQueue.main.async 块作为在视图更新期间修改状态"警告的快速修复.可行,但可能不是绝对的最佳方法.最好将图像放入其自己的 @State 中,并在视图的 onAppear 方法中进行设置.

edit: Added the DispatchQueue.main.async block as a quick fix for 'Modifying state during view update' warning. Works but probably not the absolute best way to go about it. Might be better to put the image into it's own @State and set it in the view's onAppear method.

edit 2:将图像移动到它自己的 @State var中,我认为这是一个更好的解决方案,因为它可以使视图更具可重用性,因为您可以传递图像而不是对名称的硬编码.视图中的图像.

edit 2: Moved the image into it's own @State var which I believe is a better solution as it will make the view more reusable as you can pass an image instead of hard coding the name of the image in the view.

    @State var image: UIImage {
        didSet {
            let width = image.size.width
            let height = image.size.height
            DispatchQueue.main.async {
                if width > height {
                    // Landscape image
                    self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
                    self.height = self.width/width * height
                } else {
                    
                    self.height = height > 600 ? 600 : height
                    self.width = self.height/height * width
                }
            }
        }
    }

用法:

    GeometryReader { geometry in
        Image(uiImage: image)
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: width, height: height)
            .overlay(
                Rectangle()
                    .foregroundColor(.clear)
                    .background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
            )
            .offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)

将不得不通过传入UIImage来更新ContentView的声明方式:

Will have to update how the ContentView is declared by passing in a UIImage:

ContentView(image: UIImage(named: "image0")!)

这篇关于SwiftUI:如何查找图像的高度并使用它来设置框架的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆