Collection View コードを処理するこの TatodexController があります。API 呼び出しからデータを取得し、ポケモン変数に保存します。この var は、すべてのポケモンのすべての属性 (名前、身長、能力など) を保持する Pokemon 構造体でデコードされます。
私の CollectionView では、画像、名前、その他の poke 関連の情報を表示できますが、次のように機能する機能を追加しました。
- ポケモン セルを長押しすると、情報ビューが表示され、ポケモン情報のチャンクが表示されるはずですが、TatodexController から更新されたデータを取得していません。
これは、私の TatodexController の関連コードがどのように見えるかです:
class TatodexController: UICollectionViewController, InfoViewDelegate {
var pokemon: Pokemon?
var pokemons = [Pokemon]()
let service = Service()
. . .
let infoView: InfoView = {
let view = InfoView()
view.layer.cornerRadius = 5
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
fetchPokemons()
}
. . .
@objc func handleDismissal() {
dismissInfoView(pokemon: nil)
}
}
解析と一部の InfoView 構成を処理する拡張機能は次のとおりです。
extension TatodexController {
. . .
func dismissInfoView(pokemon: Pokemon?) {
UIView.animate(withDuration: 0.5, animations: {
self.visualEffectView.alpha = 0
self.infoView.alpha = 0
self.infoView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
}) { (_) in
self.infoView.removeFromSuperview()
self.navigationItem.rightBarButtonItem?.isEnabled = true
guard let pokemon = pokemon else { return }
self.showInfoController(withPoke: pokemon)
}
}
func fetchPokemons() {
service.fetchPokes { (result) in
DispatchQueue.main.async {
switch result {
case .success(let poke):
self.pokemon = poke
self.pokemons.append(poke)
self.collectionView.reloadData()
self.pokemons.sort { (poke1, poke2) -> Bool in
return poke1.name! < poke2.name!
}
case .failure(let error):
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
self.show(alert, sender: nil)
}
}
}
}
}
そして、私の InfoViewDelegate を構成する拡張機能は次のとおりです。
extension TatodexController: TatodexCellDelegate {
func presentInfoView(withPokemon pokemon: Pokemon) {
configureSearchBar(showSearch: false)
navigationItem.rightBarButtonItem?.isEnabled = false
view.addSubview(infoView)
infoView.configureViewComponents()
infoView.delegate = self
infoView.pokemon = self.pokemon
configureInfoView()
}
func configureInfoView() {
infoView.anchor(top: nil, left: nil, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: view.frame.width - 64, height: 480)
infoView.layer.cornerRadius = view.frame.width / 6
infoView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
infoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -40).isActive = true
infoView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
infoView.alpha = 0
UIView.animate(withDuration: 0.3) {
self.visualEffectView.alpha = 1
self.infoView.alpha = 1
self.infoView.transform = .identity
}
}
}
私の InfoView クラスの関連コードは次のとおりです。
protocol InfoViewDelegate {
func dismissInfoView(pokemon: Pokemon?)
}
class InfoView: UIView {
var delegate: InfoViewDelegate?
var pokemon: Pokemon? {
didSet {
guard let pokemon = self.pokemon,
let type = pokemon.types,
let typeName = type[0].type?.name,
let defense = pokemon.defense,
let attack = pokemon.attack,
let id = pokemon.id,
let height = pokemon.height,
let weight = pokemon.weight,
let imageUrl = pokemon.sprites?.front else { return }
if id == pokemon.id {
imageView.kf.setImage(with: URL(string: imageUrl))
}
nameLabel.text = pokemon.name?.capitalized
configureLabel(label: typeLabel, title: "Type", details: "\(typeName)")
configureLabel(label: defenseLabel, title: "Defense", details: "\(defense)")
configureLabel(label: attackLabel, title: "Base Attack", details: "\(attack)")
configureLabel(label: heightLabel, title: "Height", details: "\(height)")
configureLabel(label: weightLabel, title: "Weight", details: "\(weight)")
configureLabel(label: pokedexIdLabel, title: "Pokedex Id", details: "\(id)")
}
}
let skillLabel: UILabel = {
let label = UILabel()
return label
}()
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var nameContainerView: UIView = {
let view = UIView()
view.backgroundColor = Colors.softRed
view.addSubview(nameLabel)
view.layer.cornerRadius = 5
nameLabel.center(inView: view)
return view
}()
let nameLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 24, weight: .thin)
label.text = "Lucario"
return label
}()
. . .
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func handleViewMoreInfo() {
guard let pokemon = self.pokemon else { return }
delegate?.dismissInfoView(pokemon: pokemon)
}
. . .
}
そしてもちろん、このコードの最後のチャンクでは、データを取得していません。TatodexController のポケモン情報を InfoView に接続していないためだと思いますが、その方法はわかりません。たとえば、ポケモンのセルを長押しすると、InfoView が表示され、実際のポケモンの名前ではなく、「ルカリオ」(私のデフォルト値) と表示されます。
助けやアドバイスをいただければ幸いです。別のコードを確認する必要がある場合は、喜んでこの投稿を更新します。
編集 1: TatodexCell での handleLongPress 関数
@objc func handleLongPress(sender: UILongPressGestureRecognizer) {
if sender.state == .began {
guard let poke = self.pokemon else { return }
delegate?.presentInfoView(withPokemon: poke)
}
}