Tutorial Práctico · ¿Cuándo se sigue tocando el tradicional pescado de madera? (dos)

revisión de la premisa

En el último capítulo, completamos la parte básica del proyecto "Electronic Wooden Fish", incluidos los estilos básicos de interfaz de usuario, la lógica de interacción y los efectos de animación. En este capítulo, veamos la reproducción de sonido, la página de configuración personalizada y su lógica de interacción de la aplicación "Electronic Wooden Fish".

Preparación de audio: percusión de pez de madera

Cada vez que se hace clic en el pez de madera, la aplicación electrónica de pez de madera debe hacer un sonido de golpe de "boom". Podemos encontrar y descargar el sonido de percusión de peces de madera en Internet y arrastrar el archivo descargado al proyecto, como se muestra en la siguiente figura:

Aquí, recuerde la duración del audio descargado (generalmente 1 segundo), así como el nombre y la extensión del archivo (generalmente mp3, m4a), que deben llamarse con precisión en el código posterior.

A continuación, implementemos el código relacionado con la reproducción de audio. La reproducción de audio necesita usar un nuevo marco: AVFoundation.

AVFoundation es el marco Objective-C de Apple para procesar datos multimedia basados ​​en el tiempo en sistemas iOS y OS X para que los usuarios desarrollen aplicaciones de tipo multimedia.

El marco AVFoundation se puede utilizar para lograr el efecto de reproducir sonido. Primero, debe introducir el marco AVFoundation en el proyecto. Dado que es un marco que viene con Apple, puede importarlo directamente al proyecto, como se muestra en la siguiente código:

import AVFoundation
复制代码

Para la conveniencia del proyecto, podemos crear un nuevo archivo Swift para colocar el código relevante para reproducir audio. Cree un nuevo archivo Swift llamado AudioPlayer. En el archivo AudioPlayer, introduzca el marco AVFoundation, preestablezca un reproductor y luego cree un método para usar el reproductor, como se muestra en el siguiente código:

import AVFoundation
import Foundation
import SwiftUI

var soundPlayer: AVAudioPlayer?

func playAudio(forResource: String, ofType: String) {
    let path = Bundle.main.path(forResource: forResource, ofType: ofType)!
    let url = URL(fileURLWithPath: path)

    do {
        soundPlayer = try AVAudioPlayer(contentsOf: url)
        soundPlayer?.play()
    } catch {
        print("音频文件出现问题")
    }
}
复制代码

En el código anterior, creamos previamente un reproductor soundPlayer y luego creamos un método playAudio para reproducir sonido, pasando dos parámetros, forResource se usa para determinar el nombre del archivo de audio que se reproducirá y ofType es la extensión del archivo. .

Después de confirmar los parámetros finales, proporcione los dos valores de parámetro a la ruta de la ruta y luego proporcione la ruta a la URL de la dirección, para que el jugador pueda usarla más tarde. Use el reproductor de sonido AVAudioPlayer para reproducir el sonido en el código e imprima el mensaje de error si el intento falla.

Después de completar, regrese al archivo de contenido y llame al método playAudio cuando se haga clic en el pez de madera, como se muestra en el siguiente código:

playAudio(forResource: "dong", ofType: "mp3")
复制代码

Golpearlo en la ventana de vista previa funcionó bien (risas).

页面跳转:打开设置页面

接下来,我们再升级一下,尝试编辑“功德值”参数等相关内容。我们创建一个新的SwiftUI文件,命名为DetailView,如下图所示:

回到ContentView文件,我们先来实现页面跳转交互逻辑。从ContentView跳转到DetailView页面的交互,是通过导航视图右边的按钮进行跳转,按钮部分可以使用navigationBarItems导航栏元素修饰符创建,如下代码所示:

.navigationBarItems(trailing: Image(systemName: "slider.horizontal.3"))
复制代码

如此我们创建了按钮的样式部分,但设置按钮不能进行交互,若是我们在创建按钮,并且实现按钮的交互动作,那么在navigationBarItems导航栏元素修饰符中的代码就太过于复杂,且不够清晰。

我们可以创建按钮元素视图,将再这个视图赋予navigationBarItems导航栏元素修饰符,以减少在修饰符中存在太多的不同性质的代码,如下代码所示:

func settingBtn() -> some View {
    Button(action: {
        
    }) {
        Image(systemName: "slider.horizontal.3")
            .foregroundColor(.white)
    }
}
复制代码

页面跳转部分,需要提前声明一个Bool类型的参数来控制跳转动作,如下代码所示:

@State var showDetailView:Bool = false
复制代码

页面跳转可以使用Sheet模态弹窗打开方式,在Library选择Modifiers修饰符栏目,找到sheet的修饰符,拖到VStack纵向布局容器中,并绑定声明好的触发条件及确定好需要打开的页面,如下代码所示:

.sheet(isPresented: $showDetailView) {
	DetailView()
}
复制代码

创建好页面跳转方法后,将触发条件给予到点击按钮处,并在点击设置按钮时,切换showDetailView的状态,如下代码所示:

self.showDetailView.toggle()
复制代码

在预览窗口点击顶部导航菜单的“设置”按钮,即可打开DetailView页面。

设置页面:自定义内容

来到DetailView页面,先设想下我们需要设置的内容,整个电子木鱼App可以设置哪些内容?

联想在ContentView页面使用@State声明的变量,两个页面参数需要进行联动,则在DetailView页面需要使用@Bingding声明相同的变量,用于两个页面的数据绑定,如下代码所示:

@Binding var gameType: String
@Binding var totalNumber: Int
@Binding var number: Int
复制代码

使用@Binding做数据双向绑定需要注意2点,一是在DetailView页面声明的用于绑定的变量缺少默认值,因此在视图预览的时候需要给予默认值方可正常预览,如下代码所示:

DetailView(gameType: .constant(""), totalNumber: .constant(0), number: .constant(0))
复制代码

二是在DetailView页面声明的变量,若其他页面需要跳转到该页面,则需要绑定DetailView页面声明的值。

我们在ContentView页面需要跳转到DetailView页面,因此回到ContentView页面,在跳转的地方绑定对应的参数值,如下代码所示:

DetailView(gameType: $gameType, totalNumber: $totalNumber, number: $number)
复制代码

完成后,项目不再提示报错信息后,我们回到DetailView页面来完善页面相关内容。

样式部分,可以使用Form表单作为主体框架,在Library选择Views栏目,找到Form表单控件,拖入到主体视图中,如下图所示:

参数设置部分,虔诚内容可以使用输入框作为设置,在Library选择Views栏目,找到TextField输入框控件,拖入到Form表单中,输入框内容绑定使用@Bingding绑定的gameType参数,如下代码所示:

TextField("请输入内容", text: $gameType)
复制代码

初始总量部分,我们可以使用步进器作为设置数值的控件,在Library选择Views栏目,找到Stepper步进器控件,拖入到Form表单中,Stepper步进器的值绑定初始总量totalNumber。

文字部分为了更好地展示该项设置的内容,可以使用字段拼接内容,同理,每次敲击木鱼增加的数值也可以使用Stepper步进器,如下代码所示:

Form {
    TextField("请输入内容", text: $gameType)
    Stepper(value: $totalNumber, in: 0...9999) {
        Text(gameType + ":" + "(totalNumber)")
    }
    Stepper(value: $number, in: 1...9999) {
        Text(gameType + " + " + "(number)")
    }
}
复制代码

由于在DetailView页面并没有传入相应的值,因此在预览窗口只能看到缺少值的效果,我们在ContentView页面中点开设置查看绑定参数值后的效果,如下图所示:

很好,我们尝试调试了下项目,运转不错。

最后,我们还需要增加关闭弹窗的交互动作,和上面提及过的方法一致,我们可以创建按钮元素视图,将再这个视图赋予navigationBarItems导航栏元素修饰符,作为收起弹窗的按钮,如下代码所示:

func closeBtn() -> some View {
	Button(action: {

		}) {
			Image(systemName: "xmark.circle.fill")
			.foregroundColor(.white)
		}
}
复制代码

然后对整个表单外层增加一个NavigationStack导航栏,并给Form表单增加navigationBarItems修饰符,创建关闭按钮的样式,顺便再把标题加上如下代码所示:

.navigationBarTitle("编辑内容", displayMode: .inline)
.navigationBarItems(trailing: closeBtn())
复制代码

完成之后,创建一个环境变量用于实现关闭弹窗交互,并在点击关闭按钮时调用它,如下代码所示:

//声明环境变量
@Environment(.presentationMode) var presentationMode

//调用
self.presentationMode.wrappedValue.dismiss()
复制代码

如此就完成了关闭弹窗的交互效果,回到ContentView视图试试效果,如下图所示:

项目预览:整体项目效果展示

完成之后,我们回到ContentView页面,预览下整体效果,如下图所示:

iShot_2022-11-09_23.29.49.gif

项目总结

在本次项目中,我们通过“电子木鱼”项目学习了如何使用SwiftUI这一声明式创建页面元素,也接触了完全使用Library通过拖拽组件和修饰符的方式来构建页面。

动画和交互方面,首次使用了AVFoundation框架,结合SwiftUI实现了敲击木鱼的“咚咚咚”音频播放,在运行项目听到“咚”的那一刻,也都忍不住想笑出声,总算能体会到为何“电子木鱼”App能够火起来的原因。

如果一款软件为人们带来快乐,即使它没有特别的功能,也不失为一款优秀的作品。

版权声明

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

Supongo que te gusta

Origin juejin.im/post/7164048431659352101
Recomendado
Clasificación