SwiftUI中UIViewRepresentable的使用(UIKit与SwiftUI的桥梁)

news2024/12/25 0:47:09

UIViewRepresentable是一个协议,用于创建一个SwiftUI视图,该视图包装了一个UIKit视图。通过实现UIViewRepresentable协议,我们可以在SwiftUI中使用自定义的UIKit视图,并与SwiftUI进行交互。

实现UIViewRepresentable

创建一个遵循UIViewRepresentable协议的自定义结构体,比如我们用TextField举例,创建一个TextFieldViewRepresentable,并实现该协议最基础的两个协议方法。

  • makeUIView(context:):创建并返回UIKit视图。
  • updateUIView(_:context:):更新UIKit视图。
struct TextFieldViewRepresentable: UIViewRepresentable {

  func makeUIView(context: Context) -> some UIView {
    let textField = UITextField()
    return textField
  }
  
  func updateUIView(_ uiView: UIViewType, context: Context) {

  }
}

如果在makeUIView方法中明确了要返回的UIKit控件的类型,那么方法的返回值就可以改为指定的类型,而不是some UIView,改完后,把updateUIView方法删了,再重新添加,就会发现updateUIView方法中的uiView的类型不是UIViewType了,而是我们在makeUIView方法中的返回类型。

struct TextFieldViewRepresentable: UIViewRepresentable {

  func makeUIView(context: Context) -> UITextField {
    let textField = UITextField()
    textField.backgroundColor = UIColor.gray
    return textField
  }
  
  func updateUIView(_ uiView: UITextField, context: Context) {

  }
}

SwiftUI中调用:

struct UIViewRepresentableDemo: View {
  var body: some View {
    VStack {
      Text("Hello, World!")
      TextFieldViewRepresentable()
    }
  }
}

UIKit向SwiftUI传值

上面的代码中,我们在TextField中输入任何内容都不会显示在SwiftUI的界面上的,也就是SwiftUI拿不到TextField中输入的内容,这里我们就需要绑定一个值来传递了。

要想拿到输入的内容,我们组要一个协调员去处理TextFieldDelegate的方法,这里就需要实现makeCoordinator()方法。makeCoordinator()方法也是UIViewRepresentable的协议方法。下面在TextFieldViewRepresentable结构体里面定义一个协调员Coordinator

struct TextFieldViewRepresentable: UIViewRepresentable {

  @Binding var text: String

  func makeUIView(context: Context) -> UITextField {
    let textField = UITextField()
    textField.backgroundColor = UIColor.gray
    textField.delegate = context.coordinator
    return textField
  }
  
  func makeCoordinator() -> Coordinator {
    return Coordinator(text: $text)
  }

  class Coordinator: NSObject, UITextFieldDelegate {
    @Binding var text: String

    init(text: Binding<String>) {
      self._text = text
    }

    func textFieldDidChangeSelection(_ textField: UITextField) {
      text = textField.text ?? ""
    }
  }
}

上面代码中我们创建一个类Coordinator,注意是class类型,该类实现了UITextFieldDelegate协议。

Coordinator类中定义了一个@Binding修饰的text属性,用于绑定输入的值。在textFieldDidChangeSelection协议方法中进行赋值。

TextFieldViewRepresentable中我们也定义了一个@Binding修饰的text属性,用于绑定SwiftUI中的@State修饰的String类型的值。

在实现的makeCoordinator()方法中,创建并返回Coordinator的具体实例,并绑定text

makeUIView方法中,这里我们通过contextcoordinator属性能拿到刚才通过makeCoordinator()方法创建的Coordinator实例,并将UITextField的代理设置为该实例。

textField.delegate = context.coordinator

SwiftUI部分调用代码:

struct UIViewRepresentableDemo: View {
  @State private var text: String = ""

  var body: some View {
    VStack {
      Text(text)
      TextFieldViewRepresentable(text: $text)
        .frame(height: 50)
        .padding()
    }
  }
}

使用效果如下,在输入框输入的时候,界面显示出了输入的内容。
在这里插入图片描述

SwiftUI向UIKit传值

有些时候SwiftUI界面不断刷新的时候,也需要想UIKit组件传递数据,比如刚才的代码,修改一下增加了一个SwiftUITextField组件。
在这里插入图片描述
UIKitTextField输入的时候,SwiftUITextField也显示了输入的字符串,因为我们已经将text值传到SwiftUI界面了。
但是当SwiftUITextField在输入的时候,UIKitTextField确没有任何显示。要实现这个,我们需要用到前面提到的updateUIView方法了,该方法在SwiftUI界面刷新的时候调用。

func updateUIView(_ uiView: UITextField, context: Context) {
  uiView.text = text
}

text是通过@Binding绑定的值,我们将这个textUITextField即可。

定义修饰符方法

TextFieldViewRepresentable是我们定义的一个用在SwiftUI中的结构体,我们给它加一些方法,这样在SwiftUI中通过点语法就可以修改TextFieldViewRepresentable的某些属性了。

TextFieldViewRepresentable组件可能用在很多地方,不同的用处可能会设置不同的样式属性等,比如说背景色,如果在SwiftUI中直接调用.background(Color.red)方法,是不起作用的,因为没有直接修改到UITextField

在这里插入图片描述
那么现在在TextFieldViewRepresentable中添加一个属性和一个方法。

var backgroundColor: UIColor?
func backgroundColor(_ color: UIColor) -> TextFieldViewRepresentable {
  var clone = self
  clone.backgroundColor = color
  return clone
}

该方法传入UIColor,并返回TextFieldViewRepresentable实例,即当前的self,这样在SwiftUI中就可以连续调用点语法了。

makeUIView方法中,我们给UITextField设置backgroundColor

func makeUIView(context: Context) -> UITextField {
  let textField = UITextField()
  textField.delegate = context.coordinator
  textField.placeholder = "Please input..."
  textField.borderStyle = .roundedRect
  textField.backgroundColor = backgroundColor
  return textField
}

最终调用和效果如下:
在这里插入图片描述
切记自定义的方法要在SwiftUI中初始化组件后就调用,如果在系统的修饰符方法后调用则会报错的,因为其他修饰符方法返回的是some View类型,该类型下是没有我们定义的方法的。

完整代码

struct UIViewRepresentableDemo: View {
  @State private var text: String = ""

  var body: some View {
    VStack {
      Text(text)
      HStack {
        Text("SwiftUI:")
        TextField("Please input...", text: $text)
          .textFieldStyle(.roundedBorder)
      }
      HStack {
        Text("UIKit:")
        TextFieldViewRepresentable(text: $text)
          .backgroundColor(UIColor.cyan)
          .frame(height: 50)
          .padding()
      }
    }
  }
}

struct TextFieldViewRepresentable: UIViewRepresentable {

  @Binding var text: String
  var backgroundColor: UIColor?

  func makeUIView(context: Context) -> UITextField {
    let textField = UITextField()
    textField.delegate = context.coordinator
    textField.placeholder = "Please input..."
    textField.borderStyle = .roundedRect
    textField.backgroundColor = backgroundColor
    return textField
  }
  
  func updateUIView(_ uiView: UITextField, context: Context) {
    uiView.text = text
  }

  func backgroundColor(_ color: UIColor) -> TextFieldViewRepresentable {
    var clone = self
    clone.backgroundColor = color
    return clone
  }

  func makeCoordinator() -> Coordinator {
    return Coordinator(text: $text)
  }

  class Coordinator: NSObject, UITextFieldDelegate {
    @Binding var text: String

    init(text: Binding<String>) {
      self._text = text
    }

    func textFieldDidChangeSelection(_ textField: UITextField) {
      text = textField.text ?? ""
    }
  }
}

写在最后

本文主要介绍了在SwiftUI中如何包装UIKit组件,当SwiftUI组件无法满足我们的App设计需求的时候,可以使用UIKit组件。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1821056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DT浏览器很好用

简单的浏览器&#xff0c;又是强大的浏览器&#xff0c;界面简洁大方&#xff0c;操作起来非常流畅&#x1f60e;&#xff0c;几乎不会有卡顿的情况。 搜索功能也十分强大&#x1f44d;&#xff0c;能够快速精准地找到想要的信息。 而且还有出色的兼容性&#xff0c;各种网页都…

qt 实现模拟实际物体带速度的移动(水平、垂直、斜角度)——————附带完整代码

文章目录 0 效果1 原理1.1 图片旋转1.2 物体带速度移动 2 完整实现2.1 将车辆按钮封装为一个类&#xff1a;2.2 调用方法 3 完整代码参考 0 效果 实现后的效果如下 可以显示属性&#xff08;继承自QToolButton&#xff09;: 鼠标悬浮显示文字 按钮显示文字 1 原理 类继承…

单链表经典算法题 1

前言 学习了单链表&#xff0c;我们就做一些题来巩固一下。还有就是解题方法不唯一&#xff0c;我就只讲述为自己的方法。 目录 前言 1.移除链表元素 思路 代码 2.反转链表 思路 代码 3.链表的中间节点 思路 代码 总结 1.移除链表元素 思路 我们创建一个新的表…

FM全网自动采集聚合影视搜索源码

源码介绍 FM 全网聚合影视搜索(响应式布局)&#xff0c;基于 TP5.1 开发的聚合影视搜索程序&#xff0c;本程序无数据库&#xff0c;本程序内置P2P 版播放器&#xff0c;承诺无广告无捆绑。片源内部滚动广告与本站无关,谨防上当受骗&#xff0c;资源搜索全部来自于网络。 环境…

Java面向对象之static关键字,可变参数,递归,数组常见算法,对象数组,方法参数

第一章.static关键字 1.static的介绍以及基本使用 1.概述:static是一个静态关键字 2.使用:a.修饰一个成员变量:static 数据类型 变量名b.修饰一个方法:修饰符 static 返回值类型 方法名(形参){方法体return 结果}3.调用静态成员:类名直接调用(不用new对象)4.静态成员特点:a.静…

智慧守护 畅游无忧——北斗应急呼叫柱,为景区安全加码

在大自然的怀抱中&#xff0c;中型及大型公园、景区以其壮丽风光吸引着成千上万的游客前来探索&#xff0c;成为了人们休闲娱乐的好去处。然而&#xff0c;广袤的区域、复杂的地形和分散的人流也给安全保障带来了前所未有的挑战。传统的巡逻方式难以覆盖每一个角落&#xff0c;…

2.nginx常用命令

使用nginx命令需要进入nginx目录里面执行。 /usr/local/nginx/sbin/ 查看nginx的版本号 启动nginx ./nginx 关闭nginx ./nginx -s stop 查看nginx的是否运行的命令 重新加载nginx 针对配置目录中配置文件nginx.cnf修改后需要重新加载 /usr/local/nginx/conf/nginx.cnf …

WebSocket 详解--spring boot简单使用案例

一、什么是WebSocket WebSocket 是一种网络通信协议&#xff0c;专为在单个 TCP 连接上进行全双工通信而设计。WebSocket 允许客户端和服务器之间的消息能够实时双向传输。这与传统的 HTTP 请求-响应模式有很大的不同。 二、WebSocket 的关键特性 双向通信&#xff1a;WebSocke…

vi/vim使用命令

你是否在编辑文件时以为键盘坏了&#xff0c;为什么不能删除呢&#xff0c;为什么不能敲代码呢&#xff0c;等你初识vi&#xff0c;会觉得这个东西为什么设计得这么难用&#xff0c;这篇教程带你熟练得用上这款经典的工具 Vi 是在 Unix 系统上广泛使用的编辑器&#xff0c;Vim …

java原子变量

在Java中&#xff0c;原子变量是一种特殊的变量&#xff0c;它们提供了一种不需要显式加锁的情况下进行线程安全的操作。Java.util.concurrent.atomic包提供了原子变量类&#xff0c;如AtomicInteger&#xff0c;AtomicLong等&#xff0c;它们利用底层硬件的原子操作来保证线程…

VRChat 2024年裁员原因与背景深度分析

VRChat&#xff0c;作为2022年元宇宙/VR社交领域的巨头&#xff0c;近期在2024年宣布裁员计划&#xff0c;其背后原因和背景值得业界尤其是仍在纯元宇宙虚拟空间创业的同仁们重点关注。 一、创始人决策失误 根据CEO的邮件披露&#xff0c;VRChat的创始人因缺乏经验和过度自信…

HTTP 概述

HTTP 概述 HTTP 是一种用于获取资源&#xff08;如 HTML 文档&#xff09;的协议。 它是 Web 上任何数据交换的基础&#xff0c;它是一种客户端-服务器协议&#xff0c;这意味着请求由接收方&#xff08;通常是 Web 浏览器&#xff09;发起。 一个完整的文档是从获取的不同子文…

10 SpringBoot 静态资源访问

我们在开发Web项目的时候&#xff0c;往往会有很多静态资源&#xff0c;如html、图片、css等。那如何向前端返回静态资源呢&#xff1f; 以前做过web开发的同学应该知道&#xff0c;我们以前创建的web工程下面会有一个webapp的目录&#xff0c;我们只要把静态资源放在该目录下…

N32G45XVL-STB之移植LVGL(8.4.0)

目录 概述 1 系统软硬件 1.1 软件版本信息 1.2 ST7796-LCD 1.3 MCU IO与LCD PIN对应关系 2 认识LVGL 2.1 LVGL官网 2.2 下载V8.4.0 3 移植LVGL 3.1 硬件驱动实现 3.2 添加LVGL库文件 3.3 移植和硬件相关的代码 3.3.1 驱动接口相关文件介绍 3.3.2 重新接口函数 3…

Lecture3——线性最优化(Linear Optimization)

一&#xff0c;本文重点 线性最优化&#xff08;LP&#xff09;和标准线性最优化&#xff08;Standard LP form&#xff09;的定义如何将LP转换为Standard LP用Python解决LP问题将非线性最优化问题&#xff08;NLP&#xff09;转换为LP 二&#xff0c;定义 1&#xff0c;线性…

Java多线程面试重点-1

0. 什么是并发&#xff1f;什么是并行&#xff1f; 并发&#xff1a;把时间分成一段一段&#xff0c;每个线程轮流抢占时间段。 如果时间段非常短&#xff0c;线程切换非常快&#xff0c;被称为伪并行。并行&#xff1a;多个线程可以同时运行。 并发与并行造成的影响&#xff…

k8s之kubelet证书时间过期升级

1.查看当前证书时间 # kubeadm alpha certs renew kubelet Kubeadm experimental sub-commands kubeadm是一个用于引导Kubernetes集群的工具&#xff0c;它提供了许多命令和子命令来管理集群的一生周期。过去&#xff0c;某些功能被标记为实验性的&#xff0c;并通过kubeadm a…

vue3 前端验证码-删除最后一个,焦点聚焦在前一个值上,并不会删除值

删除最后一个数字&#xff0c;焦点聚焦在前一个值上&#xff0c;并不会删除值 <inputv-for"(box, index) in boxes":key"index"ref"inputRefs":value"box"input"onInputChange(index)"keyup"onKeyDown($event, inde…

WARNING: pip is configured with locations that require TLS/SSL

在pycharm中运行pip下载软件包遇到该问题&#xff1a;WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available 原因&#xff1a;没有安装openssl&#xff1b; 到https://slproweb.com/products/Win32OpenSSL.ht…

u-boot(五) - 启动流程概述

一&#xff0c;XIP设备 一上电&#xff0c;CPU必定从XIP设备得到第1条指令。 XIP设备是指一种可以直接在存储器中执行程序代码的设备&#xff0c;而不需要将代码复制到内存中。XIP的全称是eXecute In Place&#xff0c;即芯片内执行。这类设备包括片内的SRAM、NOR Flash、Boot…