UICollectionViewについての質問です。
・解決したいこと
cellがうまくリアルタイムで更新されない
・実装したいこと
写真右上の✖︎ボタンをタップしたらそのcellを削除したい(リアルタイムで更新させたい)
・試したこと
buttonが押下されたときにcollectionView.loadData()やlayoutSubviews()を使用しましたがうまくいきません。
バックはしっかりと実装できていてViewだけが更新されません。
そのためControllerを再表示するとしっかりとそのcellは削除されます。
ソースコードを添付しますがprotocolを使っているので見にくいかもしれません。申し訳ありません。
controller側のソースコード
Swift
1import UIKit 2 3private let reuseIdentifier = "UserCell" 4private let headerIdentifier = "HeaderView" 5 6class BlockedListController: UICollectionViewController { 7 8 //MARK: - Properties 9 10 private var users = [User]() { 11 didSet { collectionView.reloadData() } 12 } 13 14 private var ifNoOneLabel: UILabel = { 15 let label = UILabel() 16 label.isHidden = true 17 label.text = "現在ブロック中のアカウントはいません????" 18 label.textAlignment = .center 19 label.textColor = .white 20 label.font = UIFont.boldSystemFont(ofSize: 14) 21 return label 22 }() 23 24 private var ifNoOneLabel2: UILabel = { 25 let label = UILabel() 26 label.isHidden = true 27 label.text = "ブロックしたアカウントはここに表示されます" 28 label.textAlignment = .center 29 label.textColor = .white 30 label.font = UIFont.systemFont(ofSize: 12) 31 return label 32 }() 33 34 //MARK: - Lifecycle 35 36 override func viewDidLoad() { 37 super.viewDidLoad() 38 configureUI() 39 blockedUsersAreExist() 40 fetchBlockedUsers() 41 } 42 43 override func viewDidLayoutSubviews() { 44 super.viewDidLayoutSubviews() 45 fetchBlockedUsers() 46 } 47 48 //MARK: - API 49 50 private func fetchBlockedUsers() { 51 UserService.fetchBlockedUsers { users in 52 self.users = users 53 } 54 } 55 56 private func blockedUsersAreExist() { 57 UserService.blockedUsersAreExist { bool in 58 self.ifNoOneLabel.isHidden = !bool 59 self.ifNoOneLabel2.isHidden = !bool 60 } 61 } 62 63 //MARK: - Helpers 64 65 private func configureUI() { 66 collectionView.backgroundColor = .backgroundColor 67 collectionView.register(BlockedListCell.self, forCellWithReuseIdentifier: reuseIdentifier) 68 collectionView.register(BlockedListHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier) 69 70 let stack = UIStackView(arrangedSubviews: [ifNoOneLabel, ifNoOneLabel2]) 71 stack.axis = .vertical 72 stack.spacing = 4 73 74 collectionView.addSubview(stack) 75 stack.centerX(inView: collectionView) 76 stack.anchor(top: collectionView.topAnchor, paddingTop: 240) 77 } 78} 79 80//MARK: - UICollectionViewDataSource 81 82extension BlockedListController { 83 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 84 return users.count 85 } 86 87 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 88 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! BlockedListCell 89 cell.delegate = self 90 cell.viewModel = UserCellViewModel(user: users[indexPath.row]) 91 return cell 92 } 93} 94 95//MARK: - UICollectionViewDelegate 96 97extension BlockedListController { 98 override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 99 let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! BlockedListHeader 100 header.delegate = self 101 return header 102 } 103} 104 105//MARK: - UICollectionViewDelegateFlowLayout 106 107extension BlockedListController: UICollectionViewDelegateFlowLayout { 108 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 109 return 1 110 } 111 112 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 113 return 1 114 } 115 116 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 117 let width = (view.frame.width - 2) / 3 118 return CGSize(width: width, height: width) 119 } 120 121 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { 122 return CGSize(width: view.frame.width, height: 60) 123 } 124} 125 126//MARK: - BlockedListHeaderDelegate 127 128extension BlockedListController: BlockedListHeaderDelegate { 129 func handleDismissal() { 130 navigationController?.popViewController(animated: true) 131 } 132} 133 134//MARK: - BlockedListCellDelegate 135 136extension BlockedListController: BlockedListCellDelegate { 137 func unblockUser(withUid uid: String) { 138 UserService.unblockUser(withUid: uid) { _ in 139 self.fetchBlockedUsers() 140 self.collectionView.reloadData() 141 } 142 } 143}
cell側のソースコード
Swift
1import UIKit 2import SDWebImage 3 4protocol BlockedListCellDelegate: AnyObject { 5 func unblockUser(withUid uid: String) 6} 7 8class BlockedListCell: UICollectionViewCell { 9 10 //MARK: - Properties 11 12 weak var delegate: BlockedListCellDelegate? 13 14 var viewModel: UserCellViewModel? { 15 didSet { populateUserData() } 16 } 17 18 private let profileImageView: UIImageView = { 19 let iv = UIImageView() 20 iv.contentMode = .scaleAspectFill 21 iv.backgroundColor = .lightGray 22 iv.clipsToBounds = true 23 return iv 24 }() 25 26 private let fullnameLabel: UILabel = { 27 let label = UILabel() 28 label.textColor = .white 29 label.font = UIFont.boldSystemFont(ofSize: 14) 30 return label 31 }() 32 33 private lazy var unblockButton: UIButton = { 34 let button = UIButton(type: .system) 35 button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) 36 button.setDimensions(height: 30, width: 30) 37 button.tintColor = .lightGray 38 button.addTarget(self, action: #selector(handleUnblock), for: .touchUpInside) 39 return button 40 }() 41 42 //MARK: - Lifecycle 43 44 override init(frame: CGRect) { 45 super.init(frame: frame) 46 configureUI() 47 } 48 49 required init?(coder: NSCoder) { 50 fatalError("init(coder:) has not been implemented") 51 } 52 53 //MARK: - Actions 54 55 @objc func handleUnblock() { 56 guard let uid = viewModel?.user.uid else { return } 57 delegate?.unblockUser(withUid: uid) 58 } 59 60 //MARK: - Helpers 61 62 private func configureUI() { 63 addSubview(profileImageView) 64 profileImageView.setDimensions(height: 80, width: 80) 65 profileImageView.layer.cornerRadius = 80 / 2 66 profileImageView.centerX(inView: self) 67 profileImageView.centerY(inView: self) 68 69 addSubview(fullnameLabel) 70 fullnameLabel.centerX(inView: profileImageView) 71 fullnameLabel.anchor(top: profileImageView.bottomAnchor, paddingTop: 8) 72 73 addSubview(unblockButton) 74 unblockButton.anchor(top: topAnchor, right: rightAnchor, paddingTop: 6, paddingRight: 6) 75 } 76 77 private func populateUserData() { 78 guard let viewModel = viewModel else { return } 79 fullnameLabel.text = viewModel.fullname 80 profileImageView.sd_setImage(with: viewModel.profileImageUrl, completed: nil) 81 } 82} 83 84
回答1件
あなたの回答
tips
プレビュー