【问题标题】:How to make a custom Image resizable() with SwiftUI如何使用 SwiftUI 制作自定义图像 resizable()
【发布时间】:2019-06-15 12:10:42
【问题描述】:

我有意见

struct CustomImageView : View {
    var body: some View {
        Image("someImage")
    }
}

当我在外部引用此视图时,我无法调整图像大小。 我知道我可以传递参数,但我一直在寻找一种更简洁的方法来通过修饰符来做到这一点?

VStack {
   CustomImageView()
      .resizable()    // This does not work
}

resizable 似乎只能直接使用图像。 有谁知道如何使 CustomImageView 可调整大小?

更新:我知道我可以使用一个参数,但有没有使用修饰符来做到这一点?可调整大小只是一种属性,但还有其他属性。并且将它们全部列为单个变量将太多

基于@matteo-pacini 的实施答案 它使用 AlamofireImage 在 ImageView 中加载远程图像。

struct RemoteImage : View {
    var url: URLConvertible
    @ObjectBinding var imageLoader = AlamofireImageLoader()

    private (set) var _resizable: (capInsets: EdgeInsets, resizingMode: Image.ResizingMode) = (EdgeInsets(), .stretch)

    var body: some View {
        Image(uiImage: imageLoader.image)
            .resizable(capInsets: _resizable.capInsets, resizingMode: _resizable.resizingMode)
            .onAppear() {
                self.imageLoader.loadImage(url: self.url)
            }
    }

    func resizable(capInsets: EdgeInsets = EdgeInsets(), resizingMode: Image.ResizingMode = .stretch) -> RemoteImage {
        return RemoteImage(url: url, _resizable: (capInsets, resizingMode))
    }
}

class AlamofireImageLoader: BindableObject {
    var didChange = PassthroughSubject<Void, Never>()
    var image = UIImage() {
        didSet {
            DispatchQueue.main.async {
                self.didChange.send(Void())
            }
        }
    }

    convenience init(url: URLConvertible) {
        self.init()
        loadImage(url: url)
    }

    func loadImage(url: URLConvertible) {
        Alamofire.request(url).responseImage { response in
            if let image = response.result.value {
                self.image = image
            }
        }
    }
}

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:
    struct CustomImageView : View {
    
        private var isResizable = false
    
        var body: some View {
            let image = Image("someImage")
            return isResizable ? image.resizable() : image
        }
    
        func resizable() -> CustomImageView {
            return CustomImageView(isResizable: true)
        }
    }
    

    然后像这样使用它。

    
    struct ContentView: View {
        var body: some View {
            VStack {
                CustomImageView()
                    .resizable()
            }
        }
    }
    

    【讨论】:

    • 我知道我可以使用一个参数,但是有没有使用修饰符来做到这一点?可调整大小只是一种属性,但还有其他属性。并且将它们全部列为单个变量将太多
    • @iOSCalendarpatchthecode.com 更新为使用修饰符 - 我认为这是 Image 所做的 (docs)。
    • @FlowUI.SimpleUITesting.com 看到我的回答有一个解决方案:)
    • 在我的发现中,这似乎是我们在尝试创建一个在更高层次上感觉和行为像原生的自定义组件时所能达到的最接近的。要查看更好的示例,请查看来自 SDWebImageSwiftUIWebImage - github.com/SDWebImage/SDWebImageSwiftUI/blob/master/…
    【解决方案2】:

    问题是你在 CustomeImageView 上调用 .resizable(),它是 View 类型的。

    您需要在 Image 类型上调用 .resizable()。

    您的图片嵌套在正文中,即在 CustomImageView 中。

    struct CustomImageView : View {
        var body: some View {
            Image("someImage")
                .resizable()
        }
    }
    
    CustomImageView()
    

    这样做的原因是,它在 Image() 上调用 .resizable,而不是像以前那样调用 View。希望这会有所帮助!

    参考资料:

    https://developer.apple.com/documentation/swiftui/image https://developer.apple.com/documentation/swiftui/view

    【讨论】:

    • 对不起,但我想我不清楚。我知道图像上的可调整大小的工作,而不是 imageView。我正在尝试创建一个可重用的自定义 imageView。但问题是,当该视图返回给调用者时,它会丢失 resizable 特征,因为图像被包裹在视图中。为了使 customImageView 足够灵活以供其他类使用,我需要该可调整大小的特征可用。有没有办法做到这一点?
    【解决方案3】:

    试试这个:

    struct CustomImageView: View {
    
        @State var isResizeable: Bool = false
        @State var capInsets: EdgeInsets = EdgeInsets()
        @State var resizingMode: Image.ResizingMode = .stretch
    
        var body : some View {
    
            ZStack {
                if isResizeable {
                    Image("placeholder")
                        .resizable(capInsets: self.capInsets, resizingMode: self.resizingMode)
                }
                else {
                    Image("placeholder")
                }
            }
        }
    
        func resizeable(capInsets: EdgeInsets = EdgeInsets(), resizingMode: Image.ResizingMode = .stretch) -> CustomImageView {
            return CustomImageView(isResizeable: true, capInsets: capInsets, resizingMode: resizingMode)
        }
    }
    
    struct ContentView : View {
    
        var body: some View {
            CustomImageView(isResizeable: true)
        }
    }
    

    【讨论】:

      【解决方案4】:

      就像@FlowUI.SimpleUITesting.com 提到的其他答案一样,假设您将只编辑一个属性修饰符。如果您要添加其他人怎么办?

      只需在您的 CustomImageView 中添加:

      private let modifiers: (Image) -> Image
      
      init(modifiers: @escaping (Image) -> Image = { $0 }) {
          self.modifiers = modifiers
      }
      
      var body: some View {
          modifiers(Image("someImage"))
      }
      

      那么就这么简单地使用吧:

      CustomImageView(modifiers : {$0.resizable().whateverModiferThatReturnImage().anotherOne()})
        .frame(width: 200)
        .aspectRatio(contentMode: .fit)
        .asUsualModifiersThatReturnViews()
      

      【讨论】:

      • 这是一个更好的答案,当然将所有修饰符放在一起会更好,但这是我找到的最接近的解决方案
      • 是的,但是许多修饰符不返回图像,然后我们就有麻烦了(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多