Tutorial Prático · Quando ainda bate na tradicional peixinha de madeira? (dois)

revisão de premissa

No último capítulo, concluímos a parte básica do projeto "Electronic Wooden Fish", incluindo estilos básicos de interface do usuário, lógica de interação e efeitos de animação. Neste capítulo, vamos perceber a reprodução de som, a página de configuração personalizada e sua lógica de interação do aplicativo "Electronic Wooden Fish".

Preparação de áudio: Percussão de peixe de madeira

Toda vez que o peixe de madeira é clicado, o aplicativo eletrônico de peixe de madeira precisa fazer um som de batida "boom". Podemos encontrar e baixar o som de percussão do peixe de madeira na Internet, e arrastar o arquivo baixado para dentro do projeto, conforme a figura abaixo:

Aqui, lembre-se da duração do áudio baixado (geralmente 1 segundo), bem como o nome do arquivo e a extensão do arquivo (geralmente mp3, m4a), que precisam ser chamados com precisão no código subsequente.

Em seguida, vamos implementar o código relacionado à reprodução de áudio. A reprodução de áudio precisa usar uma nova estrutura: AVFoundation.

AVFoundation é a estrutura Objective-C da Apple para processamento de dados de mídia baseados em tempo em sistemas iOS e OS X para que os usuários desenvolvam aplicativos de tipo de mídia.

A estrutura AVFoundation pode ser usada para obter o efeito de reprodução de som. Primeiro, você precisa introduzir a estrutura AVFoundation no projeto. Como é uma estrutura que vem com a Apple, você pode importá-la diretamente para o projeto, conforme mostrado na seguinte código:

import AVFoundation
复制代码

Para comodidade do projeto, podemos criar um novo arquivo Swift para colocar o código relevante para a reprodução do áudio. Crie um novo arquivo Swift chamado AudioPlayer. No arquivo AudioPlayer, introduza o framework AVFoundation, predefina um player e crie um método para usar o player, conforme mostrado no código a seguir:

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("音频文件出现问题")
    }
}
复制代码

No código acima, pré-criamos um player soundPlayer, e em seguida criamos um método playAudio para tocar o som, passando em dois parâmetros, forResource é usado para determinar o nome do arquivo de áudio a ser reproduzido, e ofType é a extensão do arquivo .

Depois de confirmar os parâmetros finais, dê os dois valores de parâmetro para o caminho caminho, e depois dê o caminho para o endereço url, para que o jogador possa usá-lo posteriormente. Use o reprodutor de som AVAudioPlayer para reproduzir o som no código e imprima a mensagem de erro se a tentativa falhar.

Após a conclusão, volte para o arquivo Content e chame o método playAudio quando o peixe de madeira for clicado, conforme o código a seguir:

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

Bater na janela de visualização funcionou bem (risos).

页面跳转:打开设置页面

接下来,我们再升级一下,尝试编辑“功德值”参数等相关内容。我们创建一个新的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天后未获授权禁止转载,侵权必究!

おすすめ

転載: juejin.im/post/7164048431659352101