闲聊SwiftUI中的自定义组件

SwifUI提供了许多功能强大的内置组件,允许我们快速构建复杂的UI。这些组件不仅功能强大,而且书写方式既简单又优雅。 比如HStack组件,它将任何N个其他组件排成一行 ,比如,下面代码将两个组件排除水平一行:

HStack {
Text("春眠不觉晓,处处闻啼鸟...")
Image(systemName: "heart")
 //更多组件
}

想象一下,要描述并实现上面的需求,还有比HStack组件更简洁的方式吗?答案是没有!

组件的优点是不言而喻的,那么我们是否也可以有自己的组件呢,比如,我们希望有一个组件RedBox,它将我们的UI内容加上红色的边框,并像下面方式一样使用:

RedBox {
     Text("春眠不觉晓,处处闻啼鸟,夜来风雨声, 花落知多少")
}

答案是肯定的,这就是自定义组件。下面几行简单的代码就实现了我们的RedBox

struct  RedBox<Content:View> :View
{
    var content:  ()->Content 
    var body:some View 
    {
        ZStack  {
                 self.content()
        }
        .padding()
        .border(Color.red.opacity(0.5),width:2)
   }
}

这段代码的核心是如何表达我们的内容UI。我们应该用范型参数而不是直接的View结构体,而且该泛型参数Content必须是某种View类型,至于红色的边框,我们使用了border ViewModifier直接实现。

看看如何使用RedBox。下面代码分别使用RedBox组件将一段文字内容和两张图片内容加上红色的边框:

#Preview
{
    VStack {  
       RedBox {
       Text("春眠不觉晓,处处闻啼鸟,夜来风雨声, 花落知多少")
        }
      RedBox{
            HStack {
                Image(systemName: "heart")
                    .resizable()
                    .scaledToFit()
                    .foregroundStyle(Color.red)
                    .frame(width:50,height:50)
                Image(systemName: "cloud.heavyrain")
                    .resizable()
                    .scaledToFit()
                    .foregroundStyle(Color.green)
                    .frame(width:50,height:50 )
            }
        }
     }
  }

再看看运行效果:

在这里插入图片描述

完美!与我们的期望完全一致。

看到了吧,在SwiftUI中,实现组件就是这么容易,难的不是技术,而是你的想象。

RedBox 虽然非常简单,但也展示了实现组件的一般思路:

  • 分析组件功能需求,确定变化的部分和不变的部分
  • 对于变化的部分,使用变量表示,注意UI变量的表示方式
  • 对于不变的部分,使用现有组件实现

RedBox为例,其不变的部分是红色,我们用ViewModifier 实现,变化的部分是UI内容,也就是上面的Content,我们用一个闭包类型变量来描述。

也许有人说,RedBox的功能直接用ViewModifier就可以实现,为什么还要搞一个组件呢?你是对的,仅就RedBox而言,直接用ViewModifier 可以轻易实现,确实没有必要搞一个组件,因而这里引入另外一个问题,什么时候我们需要组件?什么时候我们不需要组件?答案是仁者见仁,智者见智。但还是有一些总体原则参考的。下面是作者的一些观点:

  • 如果仅仅是改变UI的风格,颜色,背景,字体等等,直接用ViewModifier实现。
  • 如果需要按固定结构组合不同的UI,形成新的更大的UI结构,则应用组件实现。
  • 很多时候,组件和ViewModifier都可以实现相同的功能 ,但组件有一个明确的名称,可以强化语义,逻辑更集中,代码可读性更好,复用性更好
  • 组件需要设计,需要抽像,但也不能过度设计。

按照上面的标准,RedBox应该打入冷宫。 好了,就聊到这里,谢谢各位捧场。

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐