【问题标题】:Remove specific cell at certain position in collectionView删除collectionView中特定位置的特定单元格
【发布时间】:2020-07-07 16:24:52
【问题描述】:

我有一个应用程序,当用户为某个“挑战”提交图片时,它会从包含许多挑战列表的 collectionView 中删除该挑战。目前,为了确定完成了哪个挑战,我手动为直接对应于其索引的 7 个单元中的每一个分配了一个 ID(第一个单元的 ID 为 0,索引为 0)。有了这些信息,一旦我返回到带有 collectionView 的视图,它就会通过从数据数组中删除该项目并重新加载 collectionView 来删除该索引处的对象。问题是,一旦我删除了一个单元格,索引就会与原始索引/ID 不同,这意味着它之后会删除错误的单元格。

如何通过找到在 CustomCell 类中实现的单元格的唯一 ID 来确定实际删除哪个单元格。

在代码中,WeeklyViewController 是持有挑战集合视图的 VC。

import UIKit

struct CustomData {
    var img: UIImage
    var points: String
    var mainLabel: String
    var timeText: String
    var score: String
    var region: String
    var lineStaticImage: UIImage
    var subtitle: String
    var challengeID: Int
}

class WeeklyViewController: UIViewController {
    var n = Int()
    var selImage = UIImage()
    var recievedCompleteChallengeID = Int()
    var recivedCompleteChallengeBool = Bool()

    @IBOutlet weak var descLabel: UILabel!
    
    var data = [CustomData]()
    
    func completer() {
        
        var masterchallengeList = ["Turn the lights of when you leave the room", "Turn the A/C off when you leave the house/room", "Compost your food from a couple of meals", "Don't let the run the water when brushing", "Walk, Bike, or Run to work, school, or your house", "Tell a friend to practice composting", "Take a walk around your neighborhood"]
        
        var masterSubtitles = ["This week, whenever you leave the room, remember to take a look at the lights and determine whether they can be turned off...and then do it!", "When you leave your house or a section of your household, make it a point to turn off the fan/air-conditioning if it doesn't need to stay running", "Try looking up fun and interesting composting techniques and practice them with a few meal scraps", "Make sure to only use the water when you actually need it while brushing, and not when you are blankly staring into the mirror", "Try to avoid using your car or any mode of transport that uses gasoline; rather, hop on your bike, skateboard, or your own feet", "Once you figured out how you want to compost meal scraps, share it with a friend and ask them to send you a picture", "Many times, we forget that there can be an adventure other than our phones and computers, so open the door and go around your neighborhood" ]
         
        data = [
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[0], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Community", lineStaticImage: #imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[0], challengeID: 0),
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[1], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Carbon Footprint", lineStaticImage: #imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[1], challengeID: 1),
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[2], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Community", lineStaticImage: #imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[2],challengeID: 2),
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[3], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Carbon Footprint", lineStaticImage:#imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[3],challengeID: 3),
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[4], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Community", lineStaticImage: #imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[4],challengeID: 4),
            CustomData(img: #imageLiteral(resourceName: "green"), points: "5", mainLabel: masterchallengeList[5], timeText: "⏰ Ends at midnight", score: "+\(Int.random(in: 1 ..< 50))", region: "Carbon Footprint", lineStaticImage: #imageLiteral(resourceName: "blueline"), subtitle: masterSubtitles[5],challengeID: 5)
         ]
    }

    fileprivate let collectionView: UICollectionView = {
        let layout =  UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.translatesAutoresizingMaskIntoConstraints = false
        cv.register(CustomCell.self, forCellWithReuseIdentifier: "cell")
        return cv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        completer()
        view.addSubview(collectionView)
        collectionView.backgroundColor = .clear
        collectionView.topAnchor.constraint(equalTo: descLabel.bottomAnchor, constant: 40).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
        collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40).isActive = true
        
        collectionView.contentInset.left = 20
        collectionView.delegate = self
        collectionView.dataSource = self
        print(recivedCompleteChallengeBool)
        print(recievedCompleteChallengeID)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        challengeRemover()
    }
    
    func challengeRemover() {
        if recivedCompleteChallengeBool {
            data.remove(at: recievedCompleteChallengeID)
            collectionView.reloadData()
            print("removed at \(recievedCompleteChallengeID)")
        }
    }
}

extension WeeklyViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 250, height: 400)
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCell
        cell.data = self.data[indexPath.row]
        cell.backgroundColor = UIColor.init(red: 92, green: 219, blue: 149, alpha: 1)
        cell.layer.cornerRadius = 30.0
        return cell
    }
   
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        n = indexPath.row
        print("selected obj at \(n)")
        performSegue(withIdentifier: "challengeSegue", sender: self)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        var detailController = segue.destination as! SecondChallengeViewController
        detailController.dataValues = "\(data[n])"
        detailController.regionR = data[n].region
        detailController.titleLabelLabel =  data[n].mainLabel
        detailController.points = data[n].score
        detailController.subLabel  = data[n].subtitle
        detailController.receiverChallengeID = data[n].challengeID
    }
    
    @IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {}
}


class CustomCell: UICollectionViewCell {
    var id = Int()
    var data: CustomData? {
        didSet{
            guard  let data = data else { return }
            bg.image = data.img
            aa.text = data.mainLabel
            timetext.text = data.timeText
            scoreText.text = data.score
            region.text = data.region
            lineView.image = data.lineStaticImage
            id = data.challengeID
        }
    }
    
    fileprivate let bg: UIImageView = {
        let iv = UIImageView()
        iv.image = #imageLiteral(resourceName: "carousel3")
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = true
        iv.layer.cornerRadius = 30.0
        return iv 
    }()
    
    fileprivate let aa: UILabel = {
        let iv = UILabel()
        iv.text = "furf"
        iv.numberOfLines = 0
        iv.font = UIFont.systemFont(ofSize: 22, weight: .bold)
        iv.layer.frame = CGRect(x: 0, y: 0, width: 220, height: 100)
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.isEnabled = true
        iv.textColor = UIColor.init(red: 3/255, green: 29/255, blue: 59/255, alpha: 1)
        iv.textAlignment = .natural
        iv.sizeToFit()
        iv.layer.backgroundColor = UIColor.clear.cgColor
        return iv
    }()
    
    fileprivate let timetext: UILabel = {
        let iv = UILabel()
        iv.text = "timeText"
        iv.numberOfLines = 0
        iv.font = UIFont.systemFont(ofSize: 14, weight: .regular)
        iv.layer.frame = CGRect(x: 0, y: 0, width: 220, height: 30)
        iv.textColor = UIColor.init(red: 3/255, green: 29/255, blue: 59/255, alpha: 1)
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.textAlignment = .natural
        iv.sizeToFit()
        iv.layer.backgroundColor = UIColor.clear.cgColor
        return iv
    }()
    
    fileprivate let scoreText: UILabel = {
        let iv = UILabel()
        iv.text = "scoreText"
        iv.textColor = UIColor.init(red: 3/255, green: 29/255, blue: 59/255, alpha: 1)
        iv.numberOfLines = 0
        iv.font = UIFont.systemFont(ofSize: 20, weight: .bold)
        iv.layer.frame = CGRect(x: 0, y: 0, width: 220, height: 50)
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.textAlignment = .natural
        iv.sizeToFit()
        iv.layer.backgroundColor = UIColor.clear.cgColor
        return iv
    }()
    
    fileprivate let region: UILabel = {
        let iv = UILabel()
        iv.text = "regionText"
        iv.textColor = UIColor.init(red: 3/255, green: 29/255, blue: 59/255, alpha: 1)
        iv.numberOfLines = 0
        iv.font = UIFont.systemFont(ofSize: 15, weight: .light)
        iv.layer.frame = CGRect(x: 0, y: 0, width: 220, height: 50)
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.textAlignment = .natural
        iv.sizeToFit()
        iv.layer.backgroundColor = UIColor.clear.cgColor
        return iv
    }()
    
    fileprivate let lineView: UIImageView = {
        let iv = UIImageView()
        iv.layer.frame = CGRect(x: 0, y: 0, width: 250, height: 20)
        iv.contentMode = .scaleToFill
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.sizeToFit()
        return iv
    }()
    
    fileprivate let line2View: UIImageView = {
        let iv = UIImageView()
        iv.layer.frame = CGRect(x: 0, y: 0, width: 250, height: 20)
        iv.contentMode = .scaleToFill
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.clipsToBounds = true
        iv.sizeToFit()
        return iv
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.contentView.addSubview(bg)
        self.contentView.addSubview(aa)
        self.contentView.addSubview(timetext)
        self.contentView.addSubview(scoreText)
        self.contentView.addSubview(region)
        self.contentView.addSubview(lineView)
        self.contentView.addSubview(line2View)
        
        bg.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
        bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
        bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
        bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
        
        aa.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 40).isActive = true
        aa.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15).isActive = true
        aa.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -260).isActive = true
        aa.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15).isActive = true
        
        timetext.topAnchor.constraint(equalTo: aa.bottomAnchor, constant: 230).isActive = true
        timetext.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15).isActive = true
        timetext.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
        timetext.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15).isActive = true
        
        scoreText.topAnchor.constraint(equalTo: aa.bottomAnchor, constant: 30).isActive = true
        scoreText.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15).isActive = true
        scoreText.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15).isActive = true
        
        region.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 25).isActive = true
        region.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15).isActive = true
        region.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15).isActive = true
        
        lineView.topAnchor.constraint(equalTo: scoreText.bottomAnchor, constant: 140).isActive = true
        lineView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
        lineView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
        
        line2View.topAnchor.constraint(equalTo: scoreText.bottomAnchor, constant: 137).isActive = true
        line2View.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
        line2View.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

具有每个挑战的详细视图的 VC 在这里可以选择和提交图片:

class SecondChallengeViewController: UIViewController{
     
    var dataValues = String()
    var points = String()
    var titleLabelLabel = String()
    var regionR = String()
    var subLabel = String()
    var receiverChallengeID = Int()
    var challengeComp = Bool()
    
    @IBOutlet weak var submitButton: UIButton!
    @IBOutlet weak var submittedPicture: UIImageView!
    @IBOutlet weak var challengeTitle: UILabel!
    var selImage = UIImage()
    @IBOutlet weak var subtitleLabel: UILabel!
    @IBOutlet weak var regionLabel: UILabel!
    @IBOutlet weak var pointstogiveLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        assignValues()
        print(dataValues)
        print(points)
   
        
        navigationController?.navigationBar.prefersLargeTitles = true
              navigationItem.title = "Dashboard"
        navigationController?.navigationBar.barStyle = .default
        
        navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] 
    }
    
    func assignValues() {
        regionLabel.text = regionR
        challengeTitle.text = titleLabelLabel
        pointstogiveLabel.text = "\(points) evoPoints"
        subtitleLabel.text = subLabel
    }
    
    @IBAction func cameraTapped(_ sender: Any) {
        presentPhotoActionSheet()
    }
    
    func setSubmittedPicture() {
        submittedPicture.image = selImage
        submittedPicture.layer.cornerRadius = 20
        submitButton.layer.cornerRadius = 25.0
        submitButton.alpha = 1
    }
    
    func showToast(controller: UIViewController, message : String, seconds: Double) {
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        alert.view.backgroundColor = UIColor.black
        alert.view.alpha = 0.6
        alert.view.layer.cornerRadius = 15

        controller.present(alert, animated: true)

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
            alert.dismiss(animated: true)
        }
    }
    
    @IBAction func submitTapped(_ sender: Any) {
        if(submittedPicture != nil){
            challengeCompleted()
        }
    }
    
    func challengeCompleted() {
        showToast(controller: self, message: "You Successfully Completed a Challenge", seconds: 2)
        submitButton.alpha = 0
        submittedPicture.alpha = 0
        challengeComp = true
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        var challengePanelVC = segue.destination as! WeeklyViewController
        if(challengeComp){
            challengePanelVC.recievedCompleteChallengeID = receiverChallengeID
            challengePanelVC.recivedCompleteChallengeBool = challengeComp
        }
    }
}

extension SecondChallengeViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
   
    func presentPhotoActionSheet() {
        let actionSheet = UIAlertController(title: "Challenge Picture", message: "How would share your challenge with us", preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        actionSheet.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { [weak self] _ in
            self?.presentCamera()
        }))
        actionSheet.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { [weak self] _ in
            self?.presentPhotoPicker()
        }))
        
        present(actionSheet, animated: true)
    }

    func presentCamera() {
        let vc = UIImagePickerController()
        vc.sourceType = .camera
        vc.delegate = self
        vc.allowsEditing = true
        present(vc, animated: true)
        
    }

    func presentPhotoPicker(){
        
        let vc = UIImagePickerController()
        vc.sourceType = .photoLibrary
        vc.delegate = self
        vc.allowsEditing = true
        present(vc, animated: true)
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        
        guard let selectedImage =  info[UIImagePickerController.InfoKey.editedImage] as? UIImage else{
            return}
         selImage = selectedImage
         setSubmittedPicture()
        }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
    override func present(_ viewControllerToPresent: UIViewController,
                                   animated flag: Bool,
                                   completion: (() -> Void)? = nil) {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
        super.present(viewControllerToPresent, animated: flag, completion: completion)
    }
}

我怎样才能确定我必须删除哪张卡?

【问题讨论】:

    标签: ios swift uicollectionview uicollectionviewcell


    【解决方案1】:

    您可以创建一个带有用户默认计数器的 userDefaults 字典。每个新元素的计数器都会增加。计数器将是您在字典中的键,也是您的单元格标识符。然后,您将字典数据加载到您的单元格中,并为您删除的每个单元格删除字典键和值。当您重新加载数据时,单元格将仅是您的字典定义的单元格。

    此链接解释了字典部分。 Explanation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多