SwiftUI:内容是图像的 ViewModifier

Posted

技术标签:

【中文标题】SwiftUI:内容是图像的 ViewModifier【英文标题】:SwiftUI: ViewModifier where content is an Image 【发布时间】:2019-11-11 15:57:44 【问题描述】:

我收到错误“Type 'PlayButtonModifier' does not conform to protocol 'ViewModifier'”,我不明白为什么,更重要的是,如何正确处理。

我只是尝试为Image 创建一个ViewModifier,以便我可以在其上使用例如.resizable(),它仅在Image 中定义

ViewModifier 协议中,为Content 定义了一个Typealias。我的天真想法是这应该可行:

struct PlayButtonModifier: ViewModifier 
    typealias Content = Image

    func body(content: Content) -> some View 
        content
    

嗯,不。太容易了。结构的隐式类型别名也会发生同样的事情:

struct PlayButtonModifier: ViewModifier 
    func body(content: Image) -> some View 
        content
    

同样的错误。

这里有什么问题?怎么会是正确的?

【问题讨论】:

Content is opaque typealias here...this post 将帮助您澄清该区域。 嗨@Asperi,您的链接背后的答案很好地解释了幕后发生的事情。这次真是万分感谢。现在 1 Mio $ 问题:我该如何使用它? Apple 付出了所有努力,甚至包括 Swift 中的语法更改,只是为了能够修改标准的普通视图?甚至没有图像或文本?我仍然相信,其中有一些我还没有发现的东西。 所有修饰符实际上都是一个函数,即。 .resizable()。 ViewModifier 是通用视图修改的通用机制。对于特定的修改,您可以创建特定的功能、可计算的属性、专用的视图等。唯一的要求 - 那些应该生成一些视图作为输出。 【参考方案1】:

在这种修改特定于特定视图类型的情况下,例如Image,您可以直接在该视图类型上添加扩展:

extension Image 
    func myImageModifier() -> some View 
        self
            .resizable()
            .aspectRatio(1.0, contentMode: .fit)
            .clipShape(Circle())
   

下面是完整的游乐场文本示例。如果您在游乐场“资源”文件夹中添加一张名为“Otter.png”的可爱水獭图片,您会得到更漂亮的结果:)

import PlaygroundSupport
import SwiftUI

let image = (UIImage(named: "Otter.png") ?? UIImage(systemName: "exclamationmark.square")!)

struct ContentView: View 
    var body: some View 
        VStack 
            Text("hello world")
            Image(uiImage: image)
                .myImageModifier()
        
    


extension Image 
    func myImageModifier() -> some View 
        self
            .resizable()
            .aspectRatio(1.0, contentMode: .fit)
            .clipShape(Circle())
    


PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

【讨论】:

【参考方案2】:

感谢cmets和Asperi的讨论,我终于用了下面的代码sn-p。基本上,它是 ViewModifier 的实现,专门用于图像。

protocol ImageModifier 
    /// `Body` is derived from `View`
    associatedtype Body : View

    /// Modify an image by applying any modifications into `some View`
    func body(image: Image) -> Self.Body


extension Image 
    func modifier<M>(_ modifier: M) -> some View where M: ImageModifier 
        modifier.body(image: self)
    

使用很简单:

struct MyImageModifier: ImageModifier 
    func body(image: Image) -> some View 
        image.resizable().scaledToFit()
    


struct MyView: View 
    var body: some View 
        Image(systemName: "play").modifier(MyImageModifier())
    

我不是 100% 满意,因为必须将修饰符定义为返回 some View 或返回 Image。这两种情况都有缺点,不能与 SwiftUI 完美集成。

当定义 ImageModifier 以返回 Image 时,它减少了将图像修改为仅特定于图像的修饰符(实际上是 resizable())的可能性,并且在将其定义为返回 some View 时,我无法链接ImageModifiers 作为第二个修饰符必须是 ViewModifier

【讨论】:

以上是关于SwiftUI:内容是图像的 ViewModifier的主要内容,如果未能解决你的问题,请参考以下文章

Storeboard 图像到 SwiftUI

如何向 swiftUI ScrollView 指示内容大小已更改?

SwiftUI 内容在较小的 iPhone 屏幕上被截断

SwiftUI当总内容宽度小于屏幕宽度时,如何在动态水平滚动视图中居中内容

无法从 SwiftUI 框架中的资产目录访问的图像

SwiftUI 列表中基于约束的图像布局