Home > Software engineering >  Break last view to new line in multiple views line
Break last view to new line in multiple views line

Time:06-06

I have three custom views side by side in one line. If the content of the last view does not fit (as can be seen in the picture), move that view to a new line. How?

These is constraints:

firstCustomView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
secondCustomView.leadingAnchor.constraint(equalTo: firstCustomView.trailingAnchor, constant: 15),
thirdsCustomView.leadingAnchor.constraint(equalTo: secondCustomView.trailingAnchor, constant: 15),
thirdsCustomView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor, constant: -15),

enter image description here

CodePudding user response:

I did it in this way, first create custom collection view class:

class DynamicHeightCollectionView: UICollectionView {
   override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
       }
   }

   override var intrinsicContentSize: CGSize {
       return contentSize
   }
}

Second, create custom layout:

open class UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {
   open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
      return super.layoutAttributesForElements(in: rect)?.map { $0.representedElementKind == nil ? layoutAttributesForItem(at: $0.indexPath)! : $0 }
   }

   open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
      guard let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes,
         collectionView != nil else {
         return nil
      }
      if scrollDirection == .vertical {
         if indexPath.item != 0,
             let previousFrame = layoutAttributesForItem(at: IndexPath(item: indexPath.item - 1, section: indexPath.section))?.frame,
             currentItemAttributes.frame.intersects(CGRect(x: -.infinity, y: previousFrame.origin.y, width: .infinity, height: previousFrame.size.height)) {
             currentItemAttributes.frame.origin.x = previousFrame.origin.x   previousFrame.size.width   evaluatedMinimumInteritemSpacingForSection(at: indexPath.section)
         } else {
             currentItemAttributes.frame.origin.x = evaluatedSectionInsetForSection(at: indexPath.section).left
         }
      } else {
         if indexPath.item != 0,
            let previousFrame = layoutAttributesForItem(at: IndexPath(item: indexPath.item - 1, section: indexPath.section))?.frame,
            currentItemAttributes.frame.intersects(CGRect(x: previousFrame.origin.x, y: -.infinity, width: previousFrame.size.width, height: .infinity)) {
            currentItemAttributes.frame.origin.y = previousFrame.origin.y   previousFrame.size.height   evaluatedMinimumInteritemSpacingForSection(at: indexPath.section)
         } else {
            currentItemAttributes.frame.origin.y = evaluatedSectionInsetForSection(at: indexPath.section).top
         }
      }
      return currentItemAttributes
   }

   func evaluatedMinimumInteritemSpacingForSection(at section: NSInteger) -> CGFloat {
      return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingForSectionAt: section) ?? minimumInteritemSpacing
   }

   func evaluatedSectionInsetForSection(at index: NSInteger) -> UIEdgeInsets {
      return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, insetForSectionAt: index) ?? sectionInset
   }
}

And at initialization:

@IBOutlet weak var collectionView: UICollectionView! {
    didSet {
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.isScrollEnabled = false
        collectionView.register(UINib(nibName: "BubbleCell", bundle: nil), forCellWithReuseIdentifier: "BubbleCell")
        if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        }
    }
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let size = data[indexPath.row].name.size(withAttributes:[.font: UIFont(name: "Lato-Regular", size: 16)!])
        let width = min(size.width   52, collectionView.frame.width - collectionView.contentInset.left - collectionView.contentInset.right)
        return CGSize(width: width, height: 34)
}

enter image description here

  • Related