大师学SwiftUI第12章 - 手势 Part 2

这篇具有很好参考价值的文章主要介绍了大师学SwiftUI第12章 - 手势 Part 2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

放大手势

放大手势常被称为捏合手势,因为常常在用户张开或捏合两个手指时进行识别。通常这个手势实现用于让用户放大或缩小图片。

发送给​​updating()​​、​​onChanged()​​和​​onEnded()​​方法的值是一个​​CGFloat​​,表示乘上当前比例的倍数,得到图片最终的比例,如下例所示。

示例12-9:定义一个​​MagnificationGesture​​手势

struct ContentView: View {
    @GestureState private var magnification: CGFloat = 1
    @State private var zoom: CGFloat = 1
    
    var body: some View {
        Image(.spot1)
            .resizable()
            .scaledToFit()
            .frame(width: 160, height: 200)
            .scaleEffect(zoom * magnification)
            .gesture(MagnificationGesture()
                .updating($magnification) { value, state, transaction in
                    state = value
                }
                .onEnded { value in
                    zoom = zoom * value
                }
            )
    }
}

示例12-9中的代码定义了两个状态,一个用于记录放大倍数,另一个用于存储最终值。这是为了允许用户多次放大或缩小。执行手势时,倍数值存储在​​magnification​​属性中,但​​zoom​​属性的值直到手势完成时才发生改变,因此在下次用户放大或缩小时,新的比例以上次为基准计算。

为设置图片为用户所选比例,我们对​​Image​​视图应用​​scaleEffect()​​修饰符,并通过将​​zoom​​属性值(用户设置的上一个比例)乘上​​magnification​​属性的值(手势所产生的倍数)计算新的比例。结果就是图片根据手指的移动放大或缩小。

✍️跟我一起做:使用示例12-9中的代码更新​​ContentView.swift​​文件。捏合两个手指来放大或缩小。在模拟器或画面中运行应用时,点击键盘上的Option键激活手势。

示例12-9中的示例允许用户任意放在和缩小图片,但大部分情况下我们需要限制视图的比例为合理值或符合应用的目的。要设置这些限制,我们需要在两处控制比例:对视图应用​​scaleEffect()​​修饰符时,以及手势结束最终的比例设置为​​zoom​​属性时。

示例12-10:确定最小和最大比例

struct ContentView: View {
    @GestureState private var magnification: CGFloat = 1
    @State private var zoom: CGFloat = 1
    
    var body: some View {
        Image(.spot1)
            .resizable()
            .scaledToFit()
            .frame(width: 160, height: 200)
            .scaleEffect(getCurrentZoom(magnification: magnification))
            .gesture(MagnificationGesture()
                .updating($magnification) { value, state, transaction in
                    state = value
                }
                .onEnded { value in
                    zoom = getCurrentZoom(magnification: value)
                }
            )
    }
    func getCurrentZoom(magnification: CGFloat) -> CGFloat {
        let minZoom: CGFloat = 1
        let maxZoom: CGFloat = 2
        
        var current = zoom * magnification
        current = max(min(current, maxZoom), minZoom)
        return current
    }
}

本例中,视图的缩放比例限定在最小为1,最大为2。因我们需要执行一些操作来限定比例为这些值,我们将处理移到一个方法​​getCurrentZoom()​​中,在需要时进行调用。该方法定义了最大最小比例这两个常量,然后通过乘上​​zoom​​属性和放大倍数来计算当前值,最后使用​​min()​​和​​max()​​函数来限定最小为1倍,最大为2倍的结果。​​min()​​函数比较当前比例和最大允许比例,返回两者中的最小值(如果值大于2,返回2),而​​max()​​函数比较结果和最小允许比例,返回两者中的最大值(如值小于1,返回1)。​​getCurrentZoom()​​方法由​​scaleEffect()​​修饰符调用,用于设置视图的比例,​​onEnded()​​方法设置最终比例。因此用户可以放大及缩小图片,但最大为2倍,最小为1倍。

✍️跟我一起做:使用示例12-10中的代码更新​​ContentView​​结构体。则可以按​​minZoom​​和​​maxZoom​​常量所设定的限制来设置视图大小。

旋转手势

旋转手势为用户用两根手势触摸屏幕并做环形移动。常用于旋转图片。就像前面的手势一样,如果希望用户多次执行手势,就需要存储两个状态,一个为当前旋转,另一个是最终旋转。手势所生成的值为​​Angle​​类型的结构体。我们之前使用过这个结构体。它包含两个类型方法,一个用角度创建实例(​​degrees​​(​​Double​​)),另一个通过弧度​​radians​​(​​Double​​)),但在我们示例中将通过手势来旋转图片,因此对当前角度加上手势所产生的变化角度。

示例12-11:定义​​RotationGesture​​识别器

struct ContentView: View {
    @GestureState private var rotationAngle: Angle = Angle.zero
    @State private var rotation: Angle = Angle.zero
    
    var body: some View {
        Image(.spot1)
            .resizable()
            .scaledToFit()
            .frame(width: 160, height: 200)
            .rotationEffect(rotation + rotationAngle)
            .gesture(RotationGesture()
                .updating($rotationAngle) { value, state, transaction in
                    state = value
                }
                .onEnded { value in
                    rotation = rotation + value
                }
            )
    }
}

本例中应用​​rotationEffect()​​修饰符来旋转视图。角度通过计算两个状态属性而得。我们在手势结束时将当前旋转加上之前的旋转来保存当前状态,以妨用记希望从这个角度再次旋转图片。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-3:由用户旋转的图片

✍️跟我一起做:使用示例12-11中的代码更新​​ContentView​​视图。此时可以像图12-3中那样旋转视图。在模拟器或画布中运行应用时,按住键盘上的Option键来启用该手势。

拖拽手势

拖拽操作可以将内容从一个应用移动到另一个应用,或是从同一个应用的一个区域移动到另一个区域。这个工具可在屏幕上能共享两个或多个窗口时使用,如iPad和Mac电脑。在Mac电脑端,流程非常简单。我们可以同时打开两个或多个窗口,使用鼠标将一个窗口的内容拖拽到另一个窗口上。在iPad上,我们需要进行分屏。为此,iPad顶部有三个小点的图标,可以点击它来将屏幕分享给其它应用。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-4:iPad上的分屏工具

在点击三点图标时,系统显示有三个选项的菜单(见图12-4右侧)。Full Screen选项将整个屏幕传给应用,Split View选项将屏幕一分为二,左侧显示当前应用,右侧显示另一个应用,Slide Over选项将应用移到显示在另一个应用之上的浮层窗口。如果选择第二或第三个选项,屏幕上会显示两个应用,可以在应用间拖拽内容。

要允许用户将内容拖出或拉入应用,我们需要告诉系统哪些应用可以拖出或接收拉入。为此SwiftUI中包含了如下的修饰符。

  • draggable(Transferable, preview: Closure):该修饰符指定视图为拖拽操作源。第一个参数是一个遵循​​Transferable​​协议的值,表示会在处理过程中传输的数据。​​preview​​参数提供的视图在用户执行拖拽手势时显示。
  • dropDestination(for: Type, action: Closure):该修饰符指定拖拽操作的目标视图。​​for​​参数是我们希望视图接收值的数据类型的指针,​​action​​参数传入的闭包处理手势所传输的数据。

拖拽手势在视图中执行,但传输的数据由代码来决定。这并不表示我们不能传输所希望传输的数据,只是数据必须以应用能够识别的方式呈现。为此,框架定义了​​Transferable​​协议。该协议准备待发送的数据并处理在操作中接收的数据。虽然自定义数据类型可以遵循这一协议,但有些Swift数据类型和SwiftUI视图默认已进行了支持。例如在希望让用户将图片从一个应用拖到另一个应用时,我们可以使用​​Image​​视图。

示例12-12:允许用户拖拽图片

struct ContentView: View {
    var body: some View {
        VStack {
            Image(.husky)
                .resizable()
                .scaledToFit()
                .frame(width: 300, height: 400)
                .draggable(Image(.husky))
            Spacer()
        }
    }
}

这是一个简单的应用,使用​​Image​​视图显示一张哈士奇的照片,但因为我们应用了​​draggable​​修饰符,用户可以将照片拖到另一个应用中。为告知系统可在应用间分享什么数据,我们在修饰符中传入了同一张图片的另一个​​Image​​视图。​​Image​​视图符合​​Transferable​​协议,因此系统知道如何传输数据,外部应用也知道如何进行处理。图12-5中展示了在iPad上运行该应用并与照片库共享屏幕。在将哈士奇插入右侧的相簿时,图片会加入该相簿。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-5:应用间的拖拽操作

✍️跟我一起做:创建一个多平台项目。下载husky.png并添加至资源目录。使用示例12-2中的代码更新​​ContentView​​视图。在iPad模拟器上运行应用。点击屏幕上方的三个点,选择Split View选项(参见图12-4)。打开图片库。应该会看到如图12-5所示的界面。打开其中的一个相簿,将哈士奇拖入其中。图片就会加入到相簿之中。

系统通过所拖拽的视图创建图片,使用它对用户展示预览,但我们可以将其它的视图会给​​draggable()​​修饰符,来创建一个自定义预览。例如,下例换成了一个SF图标。

示例12-13:为手势提供自定义预览

truct ContentView: View {
    var body: some View {
        VStack {
            Image(.husky)
                .resizable()
                .scaledToFit()
                .frame(width: 300, height: 400)
                .draggable(Image(.husky), preview: {
                    Image(systemName: "scope")
                        .font(.system(size: 50))
                })
            Spacer()
        }
    }
}

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-6:自定义预览

另一方面,如果我们希望允许用户将内容拖放到我们的应用中,就需要提供一个接收数据的视图。要将视图转换为接收拖拽操作的目标,必须应用​​dropDestination()​​修饰符。该修饰符接收到的数据类型决定了视图可接收的数据类型以及处理的闭包。和之前一样,这一类型必须符合​​Transferable​​协议。例如,可以使用​​Image​​视图。

示例12-14:将图片拖入​​Image​​视图

struct ContentView: View {
    @State private var picture: Image = Image(.nopicture)
    var body: some View {
        VStack {
            picture
                .resizable()
                .scaledToFit()
                .frame(minWidth: 0, maxWidth: .infinity)
                .frame(height: 400)
                .dropDestination(for: Image.self, action: { elements, location in
                    if let image = elements.first {
                        picture = image
                        return true
                    }
                    return false
                })
            Spacer()
        }
    }
}

赋值给​​action​​参数的闭包接收两个值:包含用记拖入内容的列表,以及内容所拖入视图位置的​​CGPoint​​结构体。因我们心​​Image​​结构体处理数据,用户只能拖入图片或是自动转换为​​Image​​视图的值,因此可以直接赋值给​​@State​​属性在屏幕上显示。注意闭包必须返回布尔值来表示操作的结果。如果我们可以获取并处理这些值,返回​​true​​,否则返回​​false​​。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-7:将图片拖入应用

✍️跟我一起做:使用示例12-14中的代码更新​​ContentView​​视图。下载nopicture.png并添加到资源目录。在iPad模拟器上运行应用,用分屏与图片库共享屏幕。将哈士奇照片拖回到应用中。nopicture.png图就会更换为哈士奇了。

​dropDestination()​​修饰符可使用绑定属性来告知应用由用户拖拽的内容何时进入或离开视图所占区域。例如,我们可以在上例中添加​​@State​​属性,在内容进入或离开该区域时更改视图的颜色。

示例12-15:向用户提供反馈

struct ContentView: View {
    @State private var picture: Image = Image(.nopicture)
    @State private var didEnter: Bool = false
    var body: some View {
        VStack {
            picture
                .resizable()
                .scaledToFit()
                .frame(minWidth: 0, maxWidth: .infinity)
                .frame(height: 400)
                .overlay(didEnter ? Color.green.opacity(0.2) : Color.clear)
                .dropDestination(for: Image.self, action: { elements, location in
                    if let image = elements.first {
                        picture = image
                        return true
                    }
                    return false
                }, isTargeted: { value in
                    didEnter = value
                })
            Spacer()
        }
    }
}

​didEnter​​属性存储一个布尔值。如果内容进入视图区,​​dropDestination()​​修饰符对该属性赋值​​true​​,因此我们可以使用它来向用户提供反馈。本例中我们对​​Image​​视图创建一个浮层。如果​​didEnter​​属性为​​true​​,显示绿色浮层,否则为透明色。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-8:拖拽操作反馈

✍️跟我一起做:使用示例12-15中的代码更新​​ContentView​​视图。在iPad模拟器上运行应用,像之前一样进行分屏。在将图片拖到上面时拖放区会变成绿色。

至此我们使用的是​​Image​​视图来传输数据。该数据遵循​​Transferable​​协议,因此无需做其它配置直接通过拖拽传输数据。但也可以使用自定义数据类型,包括结构体和类。我们只需要让它们符合​​Transferable​​协议即可。该协议只要求实现如下类型属性。

  • transferRepresentation:该类型属性返回表示待传输数据的结构体。

该属性必须返回符合​​TransferRepresentation​​协议的结构体。框架定义了多个结构创建这些表现。最常用的是发送和接收编解码数据的​​CodableRepresentation​​、用于原始数据的​​DataRepresentation​​、用于文件的​​FileRepresentation​​以及用于预定义表现的​​ProxyRepresentation​​。以下是可用于创建这些结构体的初始化方法。

  • CodableRepresentation(for: Type, contentType: UTType):这个初始化方法创建展示可编码和解码数据的结构体。​​for​​参数是数据类型本身的指针,而​​contentType​​参数决定允许用户拖拽值的类型。
  • DataRepresentation(contentType: UTType, exporting: Closure, importing: Closure):这个初始化方法创建表示原始数据的结构体。​​contentType​​参数定义允许用户拖拽值的类开,​​exporting​​参数提供在拖拽视图时传输的数据,​​importing​​参数通过用户放入数据的数据类型创建实例。该结构体还包含另两个仅导入或导出数据的初始化方法:​​DataRepresentation(importedContentType: UTType, importing: Closure)​​和​​DataRepresentation(exportedContentType: UTType, exporting: Closure)​​。
  • FileRepresentation(contentType: UTType, shouldAttemptToOpenInPlace: Bool, exporting: Closure, importing: Closure):此初始化方法创建一个表示文件的结构体。​​contentType​​参数指定允许用户拖拽的文件类型,​​shouldAttemptToOpenInPlace​​参数表示接收者是否可以访问原始文件,​​exporting​​参数拖拽操作中发送的文件,​​importing​​参数通过放入操作所接到的信息创建文件。这个结构体还包含两个仅用于导入或导出文件的初始化方法:​​FileRepresentation(importedContentType: UTType, shouldAttemptToOpenInPlace: Bool, importing: Closure)​​和​​FileRepresentation(exportedContentType: UTType, shouldAllowToOpenInPlace: Bool, exporting: Closure)​​。
  • ProxyRepresentation(exporting: Closure, importing: Closure):这一初始化方法创建使用已有适合该类型的传输表现来创建一个结构体。​​exporting​​参数提供拖拽元素时使用的传输表现的指针,​​importing​​参数提供放下元素时使用的传输表现的指针。这个结构体还包含两个仅用于导入或导出数据的初始化方法​​ProxyRepresentation(importing: Closure)​​和​​ProxyRepresentation(exporting: Closure)​​。

这些结构体是为准备待发送数据,以及处理在拖拽操作中接收的数据。但不论使用哪个结构体,值都以​​Data​​结构体进行传输。为了让应用知道如何处理这一数据,我们需要通过​​UTType​​结构体声明内容类型。我们在第10章中已经介绍过这一结构体。稍后会学习我们可以定义自己的类型,但也可以使用由框架提供的标准类型。在下例中,在视图拖入其它应用时我们使用​​png​​类型传输PNG图片。

示例12-16:拖拽自定义值

import SwiftUI

struct ImageRepresentation: Transferable {
    let name: String
    let image: UIImage
    
    static var transferRepresentation: some TransferRepresentation {
        DataRepresentation(exportedContentType: .png, exporting: { value in
            return value.image.pngData()!
        })
    }
}
struct ContentView: View {
    @State private var picture: UIImage = UIImage(named: "nopicture")!
    var body: some View {
        VStack {
            Image(uiImage: picture)
                .resizable()
                .scaledToFit()
                .draggable(ImageRepresentation(name: "My Picture", image: picture))
                .dropDestination(for: Data.self, action: { elements, location in
                    if let data = elements.first, let image = UIImage(data: data) {
                        picture = image
                        return true
                    }
                    return false
                })
            Spacer()
        }
    }
}

这个应用中我们只希望传输图片,因此定义了一个结构体​​ImageRepresentation​​,让它遵循​​Transferable​​协议、实现​​transferRepresentation​​属性,以及定义一个​​DataRepresentation​​结构体获取图像数据并返回。

虽然我们传输的是表示图像的数据,但使用了自定义的数据类型来进行处理。在用户拖拽视图时,​​draggable()​​修饰符创建了一个​​ImageRepresentation​​结构体实例,将它发送给赋值给​​DataRepresentation​​结构体的闭包,这样就可以在​​image​​属性中获取到​​UIImage​​对象并使用​​pngData()​​方法转换数据并返回。外部应用接收这一数据,因​​UTType​​结构体将其识别为PNG图片并照此处理。注意为了知道用户在拖哪张图片,我们将​​picture​​属性的数据类型修改为了​​UIImage​​对象,因此需要使用​​Image(uiImage:)​​初始化方法来在屏幕上显示图片。因为使用​​UIImage​​对象代替​​Image​​视图来处理图片,我们还更新了​​dropDestination()​​修饰符来处理这个值。过程很简单。我们告诉​​dropDestination()​​修饰符所接收到的值是一个​​Data​​结构体,然后使用​​Image(uiImage:)​​初始化方法将值转换为图片(参见第10章中的图)。现在用户可以在视图和外部应用之间拖放图片了,数据和图片之间会自动完成相互转换。

✍️跟我一起做:使用示例12-16中的代码更新​​ContentView.swift​​文件。在iPad模拟器上运行应用。打开图片库。此时就可以在应用音拖放图片了。

在上例中,我们使用​​DataRepresentation​​结构体来准备拖拽操作(导出)中所发送的数据,但使用​​Data​​类型接收由用户所拖拽的图片。这是因为我们对其它应用所发送的数据没有控制权。但只要应用知道如何处理我们就可以接收及发送自定义数据类型。例如,允许拖拽我们应用中的内容时,我们可以控制整个流程,因此可以传输任意我定义数据类型。唯一的要求是数据要进行编码。这很容易通过​​Codable​​协议和​​CodableRepresentation​​结构体来实现,但因为我们使用了自定义数据类型,我们还需要定义自定义的​​UTType​​。以下是该结构体的初始化方法。

  • UTType(exportedAs: String, conformingTo: UTType?):此初始化方法创建一个自定义的​​UTType​​,由赋值给​​exportedAs​​参数的字符串标识。​​conformingTo​​参数预定义的​​UTType​​,自定义类型将其用作指针。

​UTType​​结构体需要一个标识符,必须通过设置来进行创建。我们需要进入项目设置(图5-4,6号图),打开Info面板,展开Exported Type Identifiers,点击+按钮插入值。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-9:自定义内容类型

需要的值有Description、Identifier和Conforms To。Description只是描述类型的文本,Identifier必须唯一,因此推荐使用反向域名,就像示例中寻样,Conforms To选项是一个紧密匹配我们的类型的预定义的​​UTType​​。本例中我们使用​​public.data​​类型,这样系统知道在传输的是原始数据。

建立好自定义内容类型后,我们需要扩展​​UTType​​结构体,包含一个表示它的类型属性。下例中,我们创建一个管理数据的自定义结构体(一个图片和一个标识符),使用​​product​​属性扩展​​UTType​​结构体存储自定义义类型。

示例12-17:使用自定义内容类型

import SwiftUI
import Observation
import UniformTypeIdentifiers

struct PictureRepresentation: Identifiable, Codable, Transferable {
    var id = UUID()
    var image: Data
    
    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(for: PictureRepresentation.self, contentType: .product)
    }
}

extension UTType {
    static var product = UTType(exportedAs: "org.alanhou.pictures")
}

@Observable class ApplicationData {
    var listPictures: [PictureRepresentation]
    
    init() {
        listPictures = [
            PictureRepresentation(image: UIImage(named: "spot1")!.pngData()!),
            PictureRepresentation(image: UIImage(named: "spot2")!.pngData()!),
            PictureRepresentation(image: UIImage(named: "spot3")!.pngData()!)
        ]
    }
}

定义好了包含数据的​​PictureRepresentation​​以及扩展了​​UTType​​来包含内容类型,我们使用三个实例初始化模型,分别包含图片spot1、spot2和spot3。这个应用允许用户将这些图片从屏幕顶部拖到底部更大的视图中,我们会从列表中删除图片,所以包含了​​UUID​​值来进行标识。界面中要用到​​ForEach​​循环在顶部列出所有可用的图片,在底部有另一个视图供用户完成拖放。

示例12-18:拖拽自定义值

struct ContentView: View {
    @Environment(ApplicationData.self) private var appData
    @State private var currentPicture: UIImage = UIImage(named: "nopicture")!
    var body: some View {
        VStack {
            HStack(spacing: 10) {
                ForEach(appData.listPictures) { picture in
                    Image(uiImage: UIImage(data: picture.image) ?? UIImage(named: "nopicture")!)
                        .resizable()
                        .frame(width: 80, height: 100)
                        .draggable(picture)
                }
            }.frame(height: 120)
            Image(uiImage: currentPicture)
                .resizable()
                .scaledToFit()
                .dropDestination(for: PictureRepresentation.self, action: { elements, location in
                    if let picture = elements.first {
                        currentPicture = UIImage(data: picture.image) ?? UIImage(named: "nopicture")!
                        appData.listPictures.removeAll(where: { $0.id == picture.id })
                        return true
                    }
                    return false
                })
            Spacer()
        }
    }
}

#Preview {
    ContentView().environment(ApplicationData())
}

​draggable()​​和​​dropDestination()​​修饰符与​​PictureRepresentation​​结构体相配合传输数据。在用户将图片播放到目标视图中时,数据会解码并创建一个​​PictureRepresentation​​结构体实例,我们就可以处理这些值了。本例中,我们将图片赋值给​​Image​​视图,然后从列表中移除原始图片。结果如下所示。

大师学SwiftUI第12章 - 手势 Part 2,空间计算visionOS增强现实开发,swiftui,swift,ios,apple vision pro,空间计算

图12-10:拖放自定义数据

✍️跟我一起做:根据示例12-17中的模型创建一个Swift文件​​ApplicationData.swift​​。再用示例12-18中的代码更新​​ContentView​​视图。下载spot1.jpg、spot2.jpg和spot3.jpg并添加到资源目录。进入项目设置(图5-4,6号图),打开Info面板,展开Exported Type Identifiers,点击+按钮插入值,参见图12-9。在iPhone模拟器上运行应用。把图片拖放到nopicture.png上。原始图片会删除,效果见图12-10(右图)。

其它相关内容请见​虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记​​

代码请见:​​GitHub仓库​​文章来源地址https://www.toymoban.com/news/detail-796991.html

到了这里,关于大师学SwiftUI第12章 - 手势 Part 2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • visionOS空间计算实战开发教程Day 2 使用RealityKit显示3D素材

    我们在​​Day1​​中学习了如何创建一个visionOS应用,但在第一个Demo应用中我们的界面内容还是2D的,看起来和其它应用并没有什么区别。接下来我们先学习如何展示3D素材,苹果为方便开发人员,推出了RealityKit,接下来看如何使用。 首先我们需要一个3D素材,Apple在​​Q

    2024年02月05日
    浏览(35)
  • [visionOS][Apple Vision Pro][SwiftUI] 定义一个UIImage变量,可动态改变,并显示在Image控件

    实际上,不需要加.onChange也可以的,这个只是响应myImage变化,跟Image更新图片没关系。 用@State标记一个属性时,SwitfUI会自动监听这个属性的变更,当这个属性发生改变,SwiftUI 会自动重新计算绘制视图。

    2024年02月16日
    浏览(49)
  • SwiftUI 布局协议 - Part1

    今年 SwiftUI 新增最好的功能之一必须是布局协议。它不但让我们参与到布局过程中,而且也给了我们一个很好的机会去更好的理解布局在 SwiftUI 中的作用。 早在2019年,我写了一篇文章 SwiftUI 中 frame 的表现 ,其中,我阐述了父视图和子视图如何协调形成最终视图效果。那里描

    2024年02月05日
    浏览(46)
  • 将Apple Vision Pro和visionOS与计算机视觉结合使用

    在2023年6月5日的WWDC大会上,苹果宣布推出多年来最大规模的硬件和软件组合产品。今年的“One more thing”(“还有一件事”)发布是苹果视觉专业版(Apple Vision Pro),这是一款集成了苹果生态系统的新型空间计算头戴式设备。 苹果视觉专业版是一个垂直整合的硬件和软件平

    2024年02月08日
    浏览(47)
  • 线性代数与解析几何——Part4 欧式空间 & 酉空间

    线性代数与解析几何——Part4 欧式空间 酉空间 1. 欧氏空间 1. 定义 性质 2. 内积表示与标准正交基 3. 欧氏空间的同构 4. 欧氏空间的线性变换 5. 欧氏空间的子空间 2. 酉空间 1. 定义 性质 2. 酉变换 3. Hermite变换 4. 规范变换 1. 定义 性质 定义7.1.1 设 V V V 是实数域 R bold{R} R 上的线

    2024年02月09日
    浏览(45)
  • Android 12.0 SystemUI控制系统手势左右滑返回功能

      在12.0的系统rom定制化产品开发中,在10.0以后系统默认手势中有三键导航和系统手势导航,在系统systemui设置默认系统手势导航以后,左右滑动手势返回功能 是在SystemUI中具体实现的,现在有需要要求控制左右滑动手势返回功能的启用和禁用,所以要分析手势返回功能的具体

    2024年02月03日
    浏览(54)
  • Leetcoder Day12|二叉树part01

    语言:Java/C++  目录 二叉树理论基础 二叉树种类 满二叉树 完全二叉树 二叉搜索树 平衡二叉搜索树 二叉树的存储方式 二叉树的遍历方式 二叉树的定义 二叉树的递归遍历 二叉树的迭代遍历 二叉树的统一迭代法 今日心得 二叉树种类 在数据结构中对二叉树的考察往往是重点

    2024年01月20日
    浏览(66)
  • Leetcoder Day12| 二叉树 part02

    语言:Java/C++  给你一个二叉树,请你返回其按层序遍历得到的节点值。 (即逐层地,从左到右访问所有节点)。 在昨天的二叉树理论基础里有提到,层序遍历需要借助队列实现。 队列先进先出,符合一层一层遍历的逻辑 这里要注意的是,定义每一层元素列表的时候ListIn

    2024年01月20日
    浏览(37)
  • SwiftUI Swift CoreData 计算某实体某属性总和

    有一个名为 Item 的实体,它有一个名为 amount 的 Double 属性,向你的 View 添加一个计算属性: 熊猫小账本 一个简洁的记账 App,用于记录日常消费开支收入,使用 iCloud 保存同步数据。 支持备注,自定义时间偶尔忘记记账也没关系。 搜索历史记账,支持分类、金额、备注。 启

    2024年02月07日
    浏览(40)
  • 代码随想录算法训练51 | 动态规划part12

    本题加了一个冷冻期,状态就多了,有点难度,大家要把各个状态分清,思路才能清晰  视频讲解: 动态规划来决定最佳时机,这次有冷冻期!| LeetCode:309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili 代码随想录 相对122.买卖股票的最佳时机II ,本题只需要在计算卖出操

    2024年01月18日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包