如何解决Swiftui:使用文本字段用户输入重命名文档目录中的音频文件
我无法弄清楚如何重命名涉及多个视图的音频文件。我从 Voice Recorder App 找到了大部分代码,并尝试添加重命名功能,该功能接受来自用户点击编辑铅笔时触发的文本字段警报的用户输入。
- 在警报保存时,应从警报文本字段
userRecordingName
(主inputRecordingName
视图)更新Communicator
属性 - 应触发警报保存
rename
功能(RecordingsList
视图) -
renameRecordings
函数被触发(AudioRecorder
视图) - 如果不为空,则使用新的
userRecordingName
字符串重新加载主视图中的记录行
我知道这很多,但是如果有人知道从文本字段重命名 URL lastPathComponent
并更新列表视图,那将非常有用!!
数据模型:
class Recording: ObservableObject {
let fileURL: URL
let createdAt: Date
@Published var userRecordingName: String
init(fileURL: URL,createdAt: Date,userRecordingName: String ) {
self.fileURL = fileURL
self.createdAt = createdAt
self.userRecordingName = userRecordingName
}
}
主视图(需要 RecNameAlert 帮助):
struct Communicator: View {
@Observedobject var audioRecorder: AudioRecorder = .shared
@State var isPresented: Bool = false
@State var inputRecordingName: String = ""
var body: some View {
NavigationView {
ZStack{
vstack {
HStack {
EditButton()
}
RecordingsList(audioRecorder: audioRecorder,isRenameClicked: $isPresented)
if self.isPresented {
Button(action: {
self.isPresented = true
}) {
Image(systemName: "pencil.circle")
}.buttonStyle(BorderlessButtonStyle())
}
if audioRecorder.recording == false {
Button(action: {print(self.audioRecorder.startRecording())}) {
Image(systemName: "circle.fill")
}
} else {
Button(action: {self.audioRecorder.stopRecording()}) {
Image(systemName: "stop.fill")
}
}
} //End vstack
.navigationBarTitle("Voice recorder")
RecNameAlert(title: "Name Recording",isShown: $isPresented,inputRecordingName: $inputRecordingName,onSave: { text in
// ??? userRecordingName from Recording Object = text ???
})
}// End ZStack
}
}
}
录音提醒:
struct RecNameAlert: View {
let screenSize = UIScreen.main.bounds
var title: String = ""
@Binding var isShown: Bool
@Binding var inputRecordingName: String
var onSave: (String) -> Void = { _ in}
var onCancel: () -> Void = { }
var body: some View {
vstack {
Text(title)
TextField("",text: $inputRecordingName)
.textFieldStyle(RoundedBorderTextFieldStyle())
HStack{
Button("Save") {
self.isShown = false
self.onSave(self.inputRecordingName)
}
Button("Cancel") {
self.isShown = false
self.onCancel()
}
}
} // End vstack
.padding()
.frame(width: screenSize.width * 0.7,height: screenSize.height * 0.3)
.background(Color(.lightGray))
.clipShape(RoundedRectangle(cornerRadius: 20.0,style: .continuous))
.offset(y: isShown ? 0 : screenSize.height)
.animation(.spring())
.shadow(color: Color(.white),radius: 6,x:-9,y:-9)
}
}
录音列表和行:
struct RecordingsList: View {
@Observedobject var audioRecorder: AudioRecorder = .shared
@Observedobject var audioPlayer = AudioPlayer()
@Binding var isRenameClicked: Bool
var body: some View {
List {
ForEach(audioRecorder.recordings,id: \.createdAt) { recording in
RecordingRow(rowRecording: recording,isRenameClicked: self.$isRenameClicked )
}// End For Each
.onDelete(perform: delete)
} // End List
} // End Body View
func delete(at offsets: IndexSet) {
var urlsToDelete = [URL]()
for index in offsets {
urlsToDelete.append(audioRecorder.recordings[index].fileURL)
}
audioRecorder.deleteRecording(urlsToDelete: urlsToDelete)
}
// ??? On save in the alert Box,I need to run this function ???
func rename(at offsets: IndexSet) {
var urlToRename = [URL]()
for index in offsets {
urlToRename.append(self.audioRecorder.recordings[index].fileURL)
}
audioRecorder.renameRecordings(urlToRename: urlToRename)
}
}
struct RecordingRow: View {
@Observedobject var audioPlayer = AudioPlayer()
@Observedobject var audioRecorder = AudioRecorder()
@Observedobject var rowRecording: Recording
@Binding var isRenameClicked: Bool
var body: some View {
HStack {
vstack{
// If userRecordingName not empty,present rowRecording.userRecodingName text instead of fileURL
Text(self.rowRecording.fileURL.lastPathComponent)
}
Spacer()
Button(action: {
self.isRenameClicked = true
}) {
Image(systemName: "pencil.circle")
}.buttonStyle(BorderlessButtonStyle())
} //End HStack
}
AudioRecorder 和函数(播放、停止、删除、重命名)
import Foundation
import SwiftUI
import AVFoundation
import Combine
class AudioRecorder: NSObject,ObservableObject {
override init() {
super.init()
fetchRecordings()
}
let objectwillChange = PassthroughSubject<AudioRecorder,Never>()
var audioRecorder: AVAudioRecorder!
static let shared = AudioRecorder()
@Published var recordings = [Recording]()
var recording = false {
didSet {
objectwillChange.send(self)
}
}
//Folded
func startRecording() { }
func stopRecording() {}
func fetchRecordings() {
recordings.removeAll()
let fileManager = FileManager.default
let documentDirectory = fileManager.urls(for: .documentDirectory,in: .userDomainMask)[0]
let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory,includingPropertiesForKeys: nil)
for audio in directoryContents {
let recording = Recording(fileURL: audio,createdAt: getCreationDate(for: audio),userRecordingName: audio.lastPathComponent)
recordings.append(recording)
}
recordings.sort(by: { $0.createdAt.compare($1.createdAt) == .orderedAscending})
objectwillChange.send(self)
}
func deleteRecording(urlsToDelete: [URL]) {
for url in urlsToDelete {
print(url)
do {
try FileManager.default.removeItem(at: url)
} catch {
print("File Could not be deleted!")
}
}
fetchRecordings()
}
// *Need Help Here*
func renameRecordings(urlToRename: [URL]) {
let fileManager = FileManager.default
let documentDirectory = fileManager.urls(for: .documentDirectory,in: .userDomainMask)[0]
for url in urlToRename {
//*Needs to be text variable from alert Box*
let dstURL = documentDirectory.appendingPathComponent("NewName.m4a")
do {
try FileManager.default.moveItem(at: url,to: dstURL)
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
}
fetchRecordings()
}
} //End AudioRecorder
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。