Dima
Dima

Reputation: 111

Choose intermediate cells automatically in CollectionView

I want to select intermediate cells automatically. If I select start time and end time, like as a screenshot, here I select 01:00 as start time and 06:00 as end time. And I want to select automatically select time 02:00, 03:00, 04:00, 05:00, it's is as example...

Maybe my client want to select 01:00 as start time and 21:00 as end time accordingly, automatically should be selected all the time.

I have three time range, it's need for me to display different time for working and for each range time i have three prices. For example:

First time and price made for morning.

Second time and price made for day.

Third time and price made for evening.

enter image description here

Can I to do and how to do it? Maybe there are frameworks which will help me to do this quickly?

My code is here:

class BookingViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    var bookingHall: Halls?

    var timeIntervalArray: [String] = []
    var timeIntervalArrayTwo: [String] = []
    var timeIntervalArrayThree: [String] = []
    var selectedTimeIntervalArray: [String] = []

    var bookingAmountOfHallArray: [Int] = []
    var sumOfBookingAmount: Int = 0

    var allArrayTimesAndPrices: [(time: String, price: Int)] = [] // ARRAY FOR COLLECT ALL TIMES AND ALL PRICES

    lazy var timeFormatter: DateFormatter = {

        let formatter = DateFormatter()
        formatter.dateFormat = "HH:mm"
        return formatter

    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        configureSelectedDateAndTime()

        collectionView.allowsMultipleSelection = true 
        // MORNING TIME RANGE
        if let timeRange = generateTimeRange() {

            self.timeIntervalArray = timeRange
            self.collectionView.reloadData()

        } else {
            // Handle error
        }
        // DAY TIME RANGE
        if let timeRangeTwo = generateTimeRangeTwo() {

            self.timeIntervalArrayTwo = timeRangeTwo
            self.collectionView.reloadData()

        } else {
            // Handle error
        }
        // EVENING TIME RANGE
        if let timeRangeThree = generateTimeRangeThree() {

            self.timeIntervalArrayThree = timeRangeThree
            self.collectionView.reloadData()

        } else {
            // Handle error
        }

        if let hall = bookingHall {

            allArrayTimesAndPrices =
                timeIntervalArray.map({ (time: $0, price: hall.price) }) +
            timeIntervalArrayTwo.map({ (time: $0, price: hall.priceSecond) }) +
            timeIntervalArrayThree.map({ (time: $0, price: hall.priceThird) })

        }

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return allArrayTimesAndPrices.count

    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "timeCell", for: indexPath) as! BookingTimeCell

        cell.timeLabel.text = allArrayTimesAndPrices[indexPath.item].time
        cell.priceLabel.text = "\(allArrayTimesAndPrices[indexPath.item].price) руб."

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let selectedCell = collectionView.cellForItem(at: indexPath)

        selectedIndexesAndBackgroundColor(cell: selectedCell!, indexPath: inde xPath)

    }

    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {

        let deselectedCell = collectionView.cellForItem(at: indexPath)

        deselectedIndexesAndBackgroundColor(cell: deselectedCell!, indexPath: indexPath)

    }
    // the selected time
    func selectedIndexesAndBackgroundColor(cell: UICollectionViewCell, indexPath: IndexPath) {

        let timeToAdd = allArrayTimesAndPrices[indexPath.item].time
        selectedTimeIntervalArray.append(timeToAdd)

    }
    // cancelled time
    func deselectedIndexesAndBackgroundColor(cell: UICollectionViewCell, indexPath: IndexPath) {

        let timeToRemove = allArrayTimesAndPrices[indexPath.item].time
        let indexTime = selectedTimeIntervalArray.index(of: timeToRemove)
        selectedTimeIntervalArray.remove(at: indexTime!)

    }
    // MORNING
    func generateTimeRange() -> [String]? {

        var result = [String]()

        if let hall = bookingHall {

            guard var startTime = timeFormatter.date(from: hall.firstStartTimeToIncreasePrice) else { return nil }
            guard let endTime = timeFormatter.date(from: hall.firstEndTimeToIncreasePrice) else { return nil }

            while startTime <= endTime {

                result.append(timeFormatter.string(from: startTime))

                startTime = Calendar.current.date(byAdding: .hour, value: 1, to: startTime)!

            }

        }

        return result
    }
    // DAY
    func generateTimeRangeTwo() -> [String]? {

        var result = [String]()

        if let hall = bookingHall {

            guard var startTime = timeFormatter.date(from: hall.secondStartTimeToIncreasePrice) else { return nil }
            guard let endTime = timeFormatter.date(from: hall.secondEndTimeToIncreasePrice) else { return nil }

            while startTime <= endTime {

                result.append(timeFormatter.string(from: startTime))

                startTime = Calendar.current.date(byAdding: .hour, value: 1, to: startTime)!

            }

        }

        return result
    }
    // EVENING
    func generateTimeRangeThree() -> [String]? {

        var result = [String]()

        if let hall = bookingHall {

            guard var startTime = timeFormatter.date(from: hall.thirdStartTimeToIncreasePrice) else { return nil }
            guard let endTime = timeFormatter.date(from: hall.thirdEndTimeToIncreasePrice) else { return nil }

            while startTime <= endTime {

                result.append(timeFormatter.string(from: startTime))

                startTime = Calendar.current.date(byAdding: .hour, value: 1, to: startTime)!

            }

        }

        return result
    } 
}

Upvotes: 0

Views: 176

Answers (3)

Alpesh Prajapati
Alpesh Prajapati

Reputation: 291

Create below global properties:

var selectedIndexPath:IndexPath! // store selected indexpath

var arrSelectedIndexPath = [IndexPath]() // array of selected indexpath

After then

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return timeArray.count
}

// -------------------------------------------------------------------------------------------

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: (self.view.frame.size.width - 60) / 7, height: (self.view.frame.size.width - 60) / 7)
}

// -------------------------------------------------------------------------------------------

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    // dequeue cell
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell

    // assign text to label
    cell.lblTitle.text = self.timeArray[indexPath.item]

    if self.arrSelectedIndexPath.contains(indexPath) {// if arrSelectedIndexPath contain indexpath then change backgrond color of label

        cell.lblTitle.backgroundColor = UIColor(red: 81.0/255.0, green: 182.0/255.0, blue: 186.0/255.0, alpha: 1.0)

    }else { // else set it to default color white

        cell.lblTitle.backgroundColor = UIColor.white

    }

    // return collection view cell
    return cell
}

// -------------------------------------------------------------------------------------------

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    if self.selectedIndexPath == nil { // if selected indexpath nil then assign first indexpath

        self.selectedIndexPath = indexPath
        self.arrSelectedIndexPath.removeAll() // remove all items from array
        self.collectionView.reloadData() // reload CollectionView

    }else {

        if self.arrSelectedIndexPath.count == 0 { // if arrSelectedIndexPath.count == 0 then

            if self.selectedIndexPath.item < indexPath.item { // check first selected indexpath is smaller then end indexpath

                // fill all intermediate cell
                for i in self.selectedIndexPath.item...indexPath.item {
                    self.arrSelectedIndexPath.append(NSIndexPath(item: i, section: 0) as IndexPath)
                }

                // reload collection view and update background color
                self.collectionView.reloadData()

                // reset first selected indexpath
                self.selectedIndexPath = nil

            }else { // else select first selected indexpath

                self.selectedIndexPath = indexPath

            }

        }else { // else remove all items from

            self.arrSelectedIndexPath.removeAll()
            self.collectionView.reloadData()
            self.selectedIndexPath = indexPath

        }

    }
}

// -------------------------------------------------------------------------------------------

}

Hope it works for you!

Upvotes: 1

Prashant Tukadiya
Prashant Tukadiya

Reputation: 16456

Have two global objects for indexPaths

var selectedRowOne:IndexPath? <br>
var selectedRowTwo:Indexpath?

After that in didSelectItemAt

   if selectedRowOne == nil {
        // Start of range is empty !!

        selectedRowOne = indexPath;
        // Logic for select the row
    } else if selectedRowTwo == nil {
        // End of range is empty
        selectedRowTwo = indexPath

        var indexPathToBeSelected :[IndexPath] = []

        for i in selectedRowOne!.row  ..< selectedRowTwo!.row {
            indexPathToBeSelected.append(IndexPath(item: i, section: 0))
        }

        // Select indexPathToBeSelected logic
    }

As your code is too confusing to I can't write code for one case . so Now You have to manage one case where where both selectedRowOne and selectedRowTwo is selected and user tap on any of cell.

Then you have to check if selected indexpath.row <selectedRowOne.row then selectedRowOne = indexpath

Secondly else if indexpath.row > selectedRowOne.row && indexpath.row < selectedRowTwo.row then selectedRowOne = indexpath

and at last condition

else if indexpath.row > selectedRowTwo.row Then selectedRowTwo = indexpath

And after all apply cell selection logic for range between selectedRowOne and selectedRowTwo

you need to take care of de select cell also if two cells are selected and if I Deselect first or second you need to manage selectedRowOne and selectedRowTwo properly

Hope it is helpful to you

Upvotes: 1

Sharad Paghadal
Sharad Paghadal

Reputation: 2154

create one property to store selectedIndexPath var selectedItem: IndexPath?, then assign it's value for first selected item.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    guard let selectedItem = selectedItem else{
        selectedItem = indexPath
        return
    }

    //loop for selecting items between current selected item and previous selected item.
    for i in selectedItem.row...indexPath.row {
         let selectedCell = collectionView.cellForItem(at: IndexPath(row: i, section: indexPath.section))
         selectedIndexesAndBackgroundColor(cell: selectedCell!, indexPath: inde xPath)
    }        

}

and do the same in didDeSelectItemAt for deselecting items accordingly.

Upvotes: 0

Related Questions