How does the Eelectronic Program Guide view update while scrolling?

400 views Asked by At

I mean initially there is dummy data then data gets loaded.

I am using collection view for the EPG. I want to load the data dynamically and at the same time I want to set the collection view cell width dynamically.

For example please see the JIOTV app. I am trying to do same thing in my application.

Below is my code of the custom layout.

import UIKit

class CustomCollectionViewLayout: UICollectionViewLayout {

var numberOfColumns = 8
var shouldPinFirstColumn = true
var shouldPinFirstRow = true
var sectionNumber = 0

var itemAttributes = [[UICollectionViewLayoutAttributes]]()
var itemsSize = [CGSize]()
var contentSize: CGSize = .zero
var arr = [String]()
var generalArr = [[String]]()
var durationArr = [String]()

override func prepare() {
    guard let collectionView = collectionView else {
        return
    }
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    numberOfColumns = appDelegate.timeArr.count//appDelegate.eventNameArr.count //appDelegate.multipleColumns
   // print(numberOfColumns)
    if appDelegate.generalArr.count > 0 {
    durationArr = appDelegate.generalArr[0]
    generalArr = appDelegate.generalArr
    if collectionView.numberOfSections == 0 {
        return
    }

    if itemAttributes.count != collectionView.numberOfSections {
        generateItemAttributes(collectionView: collectionView)
        return
    }
    for section in 0..<collectionView.numberOfSections {
        for item in 0..<collectionView.numberOfItems(inSection: section) {
            if section != 0 && item != 0 {
                continue
            }
            let attributes = layoutAttributesForItem(at: IndexPath(item: item, section: section))!
            if section == 0 {
                var frame = attributes.frame
                frame.origin.y = collectionView.contentOffset.y
                attributes.frame = frame
            }
            if item == 0 {
                var frame = attributes.frame
                frame.origin.x = collectionView.contentOffset.x
                attributes.frame = frame
            }
        }
    }
  }
}

override var collectionViewContentSize: CGSize 
{
    return contentSize
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return itemAttributes[indexPath.section][indexPath.row]
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes = [UICollectionViewLayoutAttributes]()
    for section in itemAttributes {
        let filteredArray = section.filter { obj -> Bool in
            return rect.intersects(obj.frame)
        }

        attributes.append(contentsOf: filteredArray)
    }

    return attributes
}

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return true
}

func convertHourtoMin(strTime : String) -> Int {

    var components: Array = strTime.components(separatedBy: ":")
    let hours = Int(components[0]) ?? 0
    let minutes = Int(components[1]) ?? 0
    let seconds = Int(components[2]) ?? 0

    return ((hours * 60) + (minutes) + (seconds / 60))
}
}

// MARK: - Helpers
extension CustomCollectionViewLayout {

func generateItemAttributes(collectionView: UICollectionView) {
    if itemsSize.count != numberOfColumns {
             calculateItemSizes()
       }
    var column = 0
    var xOffset: CGFloat = 0
    var yOffset: CGFloat = 0
    var contentWidth: CGFloat = 0

    itemAttributes = []
    for section in 0..<collectionView.numberOfSections {
        var sectionAttributes: [UICollectionViewLayoutAttributes] = []
            arr = generalArr[section]
           // print("General Array : \(arr)")
           // print("General Array count : \(arr.count)")
            numberOfColumns = arr.count
            durationArr = arr
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
        for index in 0..<numberOfColumns {
            var itemSize = itemsSize[index]
            if numberOfColumns == appDelegate.timeArr.count {
                 itemSize = itemsSize[index]
            }
            else {
                calculateItemSizes()
                 itemSize = itemsSize[index]
            }
 let indexPath = IndexPath(item: index, section: section)
 let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            attributes.frame = CGRect(x: xOffset, y: yOffset, width: itemSize.width, height: itemSize.height).integral

            if section == 0 && index == 0 {
                // First cell should be on top
                attributes.zIndex = 1024
            } else if section == 0 || index == 0 {
                // First row/column should be above other cells
                attributes.zIndex = 1023
            }
            // Below code with section == 0 and index till end
         /*   if section == 0 && 0 < numberOfColumns {
                attributes.frame = CGRect(x: xOffset, y: yOffset, width: 100, height: 54).integral
            }
        */
            if section == 0 {
                var frame = attributes.frame
                frame.origin.y = collectionView.contentOffset.y
                attributes.frame = frame
            }
            if index == 0 {
                var frame = attributes.frame
                frame.origin.x = collectionView.contentOffset.x
                attributes.frame = frame
            }

            sectionAttributes.append(attributes)

            xOffset += itemSize.width
            column += 1

            if column == numberOfColumns {
                if xOffset > contentWidth {
                    contentWidth = xOffset
                }

                column = 0
                xOffset = 0
                yOffset += itemSize.height
            }
        }

        itemAttributes.append(sectionAttributes)
    }

    if let attributes = itemAttributes.last?.last {
        contentSize = CGSize(width: contentWidth, height: attributes.frame.maxY)
    }
}

func calculateItemSizes() {
    itemsSize = []
  let appDelegate = UIApplication.shared.delegate as! AppDelegate
if numberOfColumns == appDelegate.timeArr.count{
    for index  in 0..<numberOfColumns {
        itemsSize.append(sizeForItemWithColumnIndexA(index))
     }
}
else {
    for index  in 0..<numberOfColumns {
        itemsSize.append(sizeForItemWithColumnIndex(index))
    }
}
 }

    func sizeForItemWithColumnIndex(_ columnIndex: Int) -> CGSize {
    var text: NSString

    switch columnIndex {

    case 0: return CGSize(width: 80, height: 40) //54
        // case 0: return CGSize(width: 106, height: 54)

        //  case 1:
    //     text = "MMM-99"
    default:
        text = "Content"
        //return CGSize(width: 100, height: 54)
        // for Stringresult in durationArr[columnIndex]
        // Below is code to make the cell dynamic
        var width:Float = Float(convertHourtoMin(strTime: durationArr[columnIndex]))
        var actualWidth:Float = Float((width / 60) * 200) // * 100
        actualWidth = actualWidth + actualWidth
       // print("Actual Width : \(actualWidth)")
        return CGSize(width: Int(actualWidth), height: 40) // 54

        //}
    }

    // let size: CGSize = text.size(withAttributes: [kCTFontAttributeName as NSAttributedStringKey: UIFont.systemFont(ofSize: 14.0)])
    // let width: CGFloat = size.width + 16
    return CGSize(width: 100, height: 54)
}
// Below method is for time row in EPG VIEW
func sizeForItemWithColumnIndexA(_ columnIndex: Int) -> CGSize {
    var text: NSString

    switch columnIndex {

    case 0: return CGSize(width: 80, height: 25)
   // case 0: return CGSize(width: 106, height: 54)

  //  case 1:
   //     text = "MMM-99"
    default:
        text = "Content"
        return CGSize(width: 200, height: 25) // originally width : 100
       // for Stringresult in durationArr[columnIndex]
        // Below is code to make the cell dynamic
            var width:Float = Float(convertHourtoMin(strTime: durationArr[columnIndex]))
            var actualWidth:Float = Float((width / 60) * 100)
            actualWidth = actualWidth + actualWidth
           // print("Actual Width : \(actualWidth)")
            return CGSize(width: Int(actualWidth), height: 54)

        //}
    }

   // let size: CGSize = text.size(withAttributes: [kCTFontAttributeName as NSAttributedStringKey: UIFont.systemFont(ofSize: 14.0)])
   // let width: CGFloat = size.width + 16
    return CGSize(width: 100, height: 35)
}
}
1

There are 1 answers

6
Durdu On

Check this out

For an EPG you will basically need to calculate the size of the cell and also it's position for each program for each channel.