Поэтому в настоящее время мне приходится вручную добавлять новые станции в наше приложение CarPlay. Однако у нас есть JSON, который наше приложение использует для iPhone и iPad. Поэтому мне интересно, как мне создать список, который использует эту информацию, вместо того, чтобы создавать ее вручную.
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) {
let DRN1 = CPListItem(text: "DRN1", detailText: "Perth's No.1 Online Station.")
let Hits = CPListItem(text: "DRN1 Hits", detailText: "Top 40 songs and yesturdays hits.")
let United = CPListItem(text: "DRN1 United", detailText: "Perth's Dedicated LGBTIQA+ Station.")
let Dance = CPListItem(text: "DRN1 Dance", detailText: "Playing the hottest dance tracks.")
if #available(iOS 14.0, *) {
let nowplay = CPNowPlayingTemplate.shared
DRN1.setImage(UIImage(imageLiteralResourceName:"DRN1Logo"))
DRN1.handler = { item, completion in
print("selected DRN1")
AdStichrApi.station = "DRN1"
MusicPlayer.shared.startBackgroundMusic(url:"https://api.example.com.au:9000/station/DRN1", type: "radio")
Nowplayinginfo().getsong()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
interfaceController.pushTemplate(nowplay, animated: true,completion:nil)
completion()
}
}
Hits.setImage(UIImage(imageLiteralResourceName:"DRN1Hits"))
Hits.handler = { item, completion in
print("selected Hits")
MusicPlayer.shared.player?.pause()
AdStichrApi.station = "DRN1Hits"
MusicPlayer.shared.startBackgroundMusic(url:"https://api.example.com.au:9000/station/DRN1Hits", type: "radio")
Nowplayinginfo().getsong()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
//interfaceController.presentTemplate(nowplay, animated: false)
interfaceController.pushTemplate(nowplay, animated: true,completion:nil)
completion()
}
}
United.setImage(UIImage(imageLiteralResourceName:"DRN1United"))
United.handler = { item, completion in
print("selected United")
AdStichrApi.station = "DRN1United"
MusicPlayer.shared.startBackgroundMusic(url:"https://api.example.com.au:9000/station/DRN1United", type: "radio")
// do work in the UI thread here
Nowplayinginfo().getsong()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
interfaceController.pushTemplate(nowplay, animated: true,completion:nil)
completion()
}
}
Dance.setImage(UIImage(imageLiteralResourceName:"DRN1Dance"))
Dance.handler = { item, completion in
print("selected Dance")
AdStichrApi.station = "dance"
MusicPlayer.shared.startBackgroundMusic(url:"https://api.example.com.au:9000/station/dance", type: "radio")
Nowplayinginfo().getsong()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
completion()
interfaceController.pushTemplate(nowplay, animated: true,completion:nil)
}
}
} else {
// Fallback on earlier versions
}
let listTemplate = CPListTemplate(title: "Select a Station", sections: [CPListSection(items:[DRN1,United,Hits,Dance])])
Однако в моем приложении для iOS я просто использую
Api().getStations { (stations) in
self.stations = stations
}
Который извлекает JSON из бэкэнда и предоставляет мне каждую доступную станцию.
Мне интересно, как я могу создать CPList, используя эту информацию.
Пример: Я нашел этот пример, но он извлекает локальные данные, и в настоящее время мне не нужна панель вкладок.
https://github.com/T0yBoy/CarPlayTutorial/дерево/мастер/CarPlayTutorial
Насколько я понимаю, все, что мне нужно сделать, это создать список
for station in (radios) {
let item = CPListItem(text: station.name, detailText: station.name)
item.accessoryType = .disclosureIndicator
item.setImage(UIImage(named: station.imageurl))
item.handler = { [weak self] item, completion in
guard let strongSelf = self else { return }
// strongSelf.favoriteAlert(radio: radio, completion: completion)
}
radioItems.append(item)
}
Я знаю, что мне нужно сделать что-то вроде
Api().getStations { (stations) in
self.radios = stations
INSERT THE STATIONS INTO A LIST for
let listTemplate = CPListTemplate(title: "Select a Station", sections: [CPListSection(items:stations)])
}
Вот как это все еще должно выглядеть после создания списка из API

@ShawnFrank, так что это первое представление, да. Я пытаюсь понять, как заставить его загружаться в CarPlay. Я знаю, что мне нужно сделать что-то вроде примера, который я опубликовал выше.





Попробуйте это:
// In some function in the CarPlaySceneDelegate
Api().getStations { (stations) in
var stationItems: [CPListItem] = []
self.radios = stations
for station in stations {
let item = CPListItem(text: station.name,
detailText: station.description
image: station.image)
item.handler = { [weak self] item, completion in
// manage what should happen on tap
// like navigate to NowPlayingView
}
stationItems.append(item)
}
loadList(withStations: stationItems)
}
// Load the list template
private func loadList(withStations stations: [CPListItem]) {
let section = CPListSection(items: stations)
let listTemplate = CPListTemplate(title: "Select a station",
sections: [section])
// Set the root template of the CarPlay interface
// to the list template with a completion handler
interfaceController?.setRootTemplate(listTemplate,
animated: true) { success, error in
// add anything you want after setting the root template
}
}
Цикл for для добавления станций в массив CPListItem можно заменить функцией map, но я сделал это для ясности.
Обновлять
В своем class CarPlaySceneDelegate исправьте написание от
var interfactController: CPInterfaceController?
к
var interfaceController: CPInterfaceController?
В своем templateApplicationScene didConnect комментарии interfactController?.setRootTemplate(listTemplate, animated: false) на данный момент
и добавьте к нему эту строку self.interfaceController = interfaceController
Итак, обновленная функция выглядит так:
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController) {
// Add this
self.interfaceController = interfaceController
Api().getStations { (stations) in
var stationItems: [CPListItem] = []
self.stations = stations
for station in stations {
let item = CPListItem(text: station.name,
detailText: station.name
// image: imageLiteralResourceName:"DRN1Logo")
)
item.handler = { [weak self] item, completion in
// manage what should happen on tap
// like navigate to NowPlayingView
print(item)
}
stationItems.append(item)
}
self.loadList(withStations: stationItems)
}
}
Вы видите лучшие результаты?
Я получаю Не могу найти 'interfaceController' в области видимости
Я загрузил проект Xcode github.com/redimongo/iOS-радио-приложение Не уверен, что это поможет
@RussellHarrower - я просмотрел ваш репозиторий на github и обновил свой ответ, см. Раздел Обновлять
спасибо - это работает :) Только сейчас нужно разобраться, как отправить listenURL: station.listenlive внутри CPListItem - кажется, вы не можете добавлять дополнительные аргументы
@RussellHarrower - Рад, что у тебя все получилось! Не уверен, что я полностью понял вторую часть вопроса, однако вы, вероятно, могли бы открыть новый вопрос с этим, если вы не можете понять это и поделиться со мной ссылкой здесь, я попытаюсь взглянуть на это. Если этот ответ помог вам получить то, что вы хотите, рассмотрите возможность пометить его как ответ - это поможет мне и другим :)
Это было легко, просто нужно было сделать, если пусть listenNow = station.first(where: {$0.name == item.text}) { внутри item.handler = {[weak self] item, завершение в
Ах, хорошо, я понимаю, что вы имеете в виду. Я помню, что когда только начинал, у меня были трудности с пониманием CarPlay, но приятно видеть, что вы разбираетесь в этом быстрее.
Просто интересно, знаете ли вы, как преобразовать строковое URL-изображение в UIImage для этого?
@RussellHarrower — вы можете использовать Data(contentsOf: url), чтобы получить представление данных изображения из URL-адреса. Тогда вы можете использовать UIImage(data: data). Однако вам также может понадобиться управлять временем загрузки с помощью асинхронных вызовов. Взгляните на: hackingwithswift.com/example-code/uikit/…
Да, определенно загружайте их асинхронно и кешируйте. У нас есть фрагмент с удобным инициализатором для элемента списка (gist.github.com/fruitcoder/…). Если вам нужна дополнительная информация о том, как она используется, вы можете найти ее здесь medium.com/br-следующий/….
Является ли шаблон списка первым представлением, которое пользователь должен увидеть со списком станций? И ваш вопрос отображает только список или отображает список после того, как API отправил ответ?