如何动态排列图像

时间:2018-06-04 06:28:47

标签: ios swift3

我从阵列中获得了包含正方形和矩形图像的图像。然后我确定排列的图像大小。来自阵列的图像是随机的矩形或正方形。我当前的结果是低于一个

enter image description here

我无法像这样安排两个方形图像我希望下面的实际结果

enter image description here

func retreiveImgFromMemory() {
    //get from memory
    let imgArr = UserDefaults.standard.array(forKey: "adsImgArr")

    //Rec Image
    let imageWidth:CGFloat = 414
    let imageHeight:CGFloat = 235
    var yPosition:CGFloat = 0
    var scrollViewContentSize:CGFloat = 0

    //Sqr Image
    let sqrImgWidth:CGFloat = 203
    let sqrImgHeight:CGFloat = 235.33

    for img in imgArr! {
        let imgURL = URL(string: img as! String)
        let data = try? Data(contentsOf: imgURL!)
        let image: UIImage = UIImage(data: data!)!
        let imageSize = Int(image.size.width)

        //1242
        if imageSize > 600 {
            let imageView:UIImageView = UIImageView()
            imageView.image = image
            imageView.contentMode = UIViewContentMode.scaleAspectFit

            imageView.frame.size.width = imageWidth
            imageView.frame.size.height = imageHeight
            imageView.frame.origin.x = 0
            imageView.center = self.view.center
            imageView.frame.origin.y = yPosition

            scrollView.addSubview(imageView)

            let spacer:CGFloat = 0

            yPosition+=200 + spacer
        }
        //600
        else{
            imageView.contentMode = UIViewContentMode.scaleAspectFit

            imageView.frame.size.width = sqrImgWidth
            imageView.frame.size.height = sqrImgHeight
            imageView.frame.origin.x = 0
            imageView.frame.origin.y = yPosition

            scrollView.addSubview(imageView)

            let spacer:CGFloat = 10

            yPosition+=200 + spacer
            scrollViewContentSize+=imageHeight + spacer
        }
    }
    scrollView.contentSize = CGSize(width: 0, height: scrollViewContentSize)
    stopLoadingSpinner()
}

1 个答案:

答案 0 :(得分:0)

要实现此目的,您必须先异步下载图像。下载图像后,您必须计算它们的大小。并使用waterfalllayout

在UICollectionView中填充图像

要异步下载图像,请使用此library。并在代码下面使用图像数据

KingfisherManager.shared.retrieveImage(with: url, options: nil, progressBlock: nil, completionHandler: { image, error, cacheType, imageURL in
    print(image)
})

并在UICollectionView中实现瀑布布局。 使用扩展名

import Foundation
import UIKit
fileprivate func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs, rhs) {
    case let (l?, r?):
        return l < r
    case (nil, _?):
        return true
    default:
        return false
    }
}

fileprivate func > <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs, rhs) {
    case let (l?, r?):
        return l > r
    default:
        return rhs < lhs
    }
}


@objc public protocol CHTCollectionViewDelegateWaterfallLayout: UICollectionViewDelegate {

    func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                         sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize

    @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                                        heightForHeaderInSection section: Int) -> CGFloat

    @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                                        heightForFooterInSection section: Int) -> CGFloat

    @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                                        insetForSectionAtIndex section: Int) -> UIEdgeInsets

    @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                                        minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat

    @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
                                        columnCountForSection section: Int) -> Int
}

public enum CHTCollectionViewWaterfallLayoutItemRenderDirection: Int {
    case chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst
    case chtCollectionViewWaterfallLayoutItemRenderDirectionLeftToRight
    case chtCollectionViewWaterfallLayoutItemRenderDirectionRightToLeft
}

public  let CHTCollectionElementKindSectionHeader = "CHTCollectionElementKindSectionHeader"
public  let CHTCollectionElementKindSectionFooter = "CHTCollectionElementKindSectionFooter"
public class CHTCollectionViewWaterfallLayout: UICollectionViewLayout {
    public var columnCount: Int {
        didSet {
            invalidateLayout()
        }}

    public var minimumColumnSpacing: CGFloat {
        didSet {
            invalidateLayout()
        }}

    public var minimumInteritemSpacing: CGFloat {
        didSet {
            invalidateLayout()
        }}

    public var headerHeight: CGFloat {
        didSet {
            invalidateLayout()
        }}

    public var footerHeight: CGFloat {
        didSet {
            invalidateLayout()
        }}

    public var sectionInset: UIEdgeInsets {
        didSet {
            invalidateLayout()
        }}


    public var itemRenderDirection: CHTCollectionViewWaterfallLayoutItemRenderDirection {
        didSet {
            invalidateLayout()
        }
    }


    //    private property and method above.
    public weak var delegate: CHTCollectionViewDelegateWaterfallLayout? {
        get {
            return self.collectionView!.delegate as? CHTCollectionViewDelegateWaterfallLayout
        }
    }
    public var columnHeights: [[CGFloat]]
    public var sectionItemAttributes: [[UICollectionViewLayoutAttributes]]
    public var allItemAttributes: [UICollectionViewLayoutAttributes]
    public var headersAttributes: [Int: UICollectionViewLayoutAttributes]
    public var footersAttributes: [Int: UICollectionViewLayoutAttributes]
    public var unionRects: [NSValue]
    public let unionSize = 20

    override public init() {
        self.headerHeight = 0.0
        self.footerHeight = 0.0
        self.columnCount = 2
        self.minimumInteritemSpacing = 10
        self.minimumColumnSpacing = 10
        self.sectionInset = UIEdgeInsets.zero
        self.itemRenderDirection =
            CHTCollectionViewWaterfallLayoutItemRenderDirection.chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst

        headersAttributes = [:]
        footersAttributes = [:]
        unionRects = []
        columnHeights = []
        allItemAttributes = []
        sectionItemAttributes = []

        super.init()
    }

    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public func columnCountForSection (_ section: Int) -> Int {
        if let columnCount = self.delegate?.collectionView?(self.collectionView!, layout: self, columnCountForSection: section) {
            return columnCount
        } else {
            return self.columnCount
        }
    }

    public func itemWidthInSectionAtIndex (_ section: Int) -> CGFloat {
        var insets: UIEdgeInsets
        if let sectionInsets = self.delegate?.collectionView?(self.collectionView!, layout: self, insetForSectionAtIndex: section) {
            insets = sectionInsets
        } else {
            insets = self.sectionInset
        }
        let width: CGFloat = self.collectionView!.bounds.size.width - insets.left - insets.right
        let columnCount = self.columnCountForSection(section)
        let spaceColumCount: CGFloat = CGFloat(columnCount - 1)
        return floor((width - (spaceColumCount * self.minimumColumnSpacing)) / CGFloat(columnCount))
    }

    override public func prepare() {
        super.prepare()

        let numberOfSections = self.collectionView!.numberOfSections
        if numberOfSections == 0 {
            return
        }

        self.headersAttributes = [:]
        self.footersAttributes = [:]
        self.unionRects = []
        self.columnHeights = []
        self.allItemAttributes = []
        self.sectionItemAttributes = []

        for section in 0 ..< numberOfSections {
            let columnCount = self.columnCountForSection(section)
            var sectionColumnHeights: [CGFloat] = []
            for idx in 0 ..< columnCount {
                sectionColumnHeights.append(CGFloat(idx))
            }
            self.columnHeights.append(sectionColumnHeights)
        }

        var top: CGFloat = 0.0
        var attributes = UICollectionViewLayoutAttributes()

        for section in 0 ..< numberOfSections {
            /*
             * 1. Get section-specific metrics (minimumInteritemSpacing, sectionInset)
             */
            var minimumInteritemSpacing: CGFloat
            if let miniumSpaceing = self.delegate?.collectionView?(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAtIndex: section) {
                minimumInteritemSpacing = miniumSpaceing
            } else {
                minimumInteritemSpacing = self.minimumColumnSpacing
            }

            var sectionInsets: UIEdgeInsets
            if let insets = self.delegate?.collectionView?(self.collectionView!, layout: self, insetForSectionAtIndex: section) {
                sectionInsets = insets
            } else {
                sectionInsets = self.sectionInset
            }

            let width = self.collectionView!.bounds.size.width - sectionInsets.left - sectionInsets.right
            let columnCount = self.columnCountForSection(section)
            let spaceColumCount = CGFloat(columnCount - 1)
            let itemWidth = floor((width - (spaceColumCount * self.minimumColumnSpacing)) / CGFloat(columnCount))

            /*
             * 2. Section header
             */
            var heightHeader: CGFloat
            if let height = self.delegate?.collectionView?(self.collectionView!, layout: self, heightForHeaderInSection: section) {
                heightHeader = height
            } else {
                heightHeader = self.headerHeight
            }

            if heightHeader > 0 {
                attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: CHTCollectionElementKindSectionHeader, with: IndexPath(row: 0, section: section))
                attributes.frame = CGRect(x: 0, y: top, width: self.collectionView!.bounds.size.width, height: heightHeader)
                self.headersAttributes[section] = attributes
                self.allItemAttributes.append(attributes)

                top = attributes.frame.maxY
            }
            top += sectionInsets.top
            for idx in 0 ..< columnCount {
                self.columnHeights[section][idx]=top
            }

            /*
             * 3. Section items
             */
            let itemCount = self.collectionView!.numberOfItems(inSection: section)
            var itemAttributes: [UICollectionViewLayoutAttributes] = []

            // Item will be put into shortest column.
            for idx in 0 ..< itemCount {
                let indexPath = IndexPath(item: idx, section: section)

                let columnIndex = self.nextColumnIndexForItem(idx, section: section)
                let xOffset = sectionInsets.left + (itemWidth + self.minimumColumnSpacing) * CGFloat(columnIndex)

                let yOffset = ((self.columnHeights[section] as AnyObject).object (at: columnIndex) as AnyObject).doubleValue
                let itemSize = self.delegate?.collectionView(self.collectionView!, layout: self, sizeForItemAtIndexPath: indexPath)
                var itemHeight: CGFloat = 0.0
                if itemSize?.height > 0 && itemSize?.width > 0 {
                    itemHeight = floor(itemSize!.height * itemWidth / itemSize!.width)
                }

                attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
                attributes.frame = CGRect(x: xOffset, y: CGFloat(yOffset!), width: itemWidth, height: itemHeight)
                itemAttributes.append(attributes)
                self.allItemAttributes.append(attributes)

                self.columnHeights[section][columnIndex] = attributes.frame.maxY + minimumInteritemSpacing

            }
            self.sectionItemAttributes.append(itemAttributes)

            /*
             * 4. Section footer
             */
            var footerHeight: CGFloat = 0.0
            let columnIndex  = self.longestColumnIndexInSection(section)
            top = self.columnHeights[section][columnIndex] - minimumInteritemSpacing + sectionInsets.bottom

            if let height = self.delegate?.collectionView?(self.collectionView!, layout: self, heightForFooterInSection: section) {
                footerHeight = height
            } else {
                footerHeight = self.footerHeight
            }

            if footerHeight > 0 {
                attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: CHTCollectionElementKindSectionFooter, with: IndexPath(item: 0, section: section))
                attributes.frame = CGRect(x: 0, y: top, width: self.collectionView!.bounds.size.width, height: footerHeight)
                self.footersAttributes[section] = attributes
                self.allItemAttributes.append(attributes)
                top = attributes.frame.maxY
            }

            for idx in 0 ..< columnCount {
                self.columnHeights[section][idx] = top
            }
        }

        var idx = 0
        let itemCounts = self.allItemAttributes.count
        while idx < itemCounts {
            let rect1 = self.allItemAttributes[idx].frame
            idx = min(idx + unionSize, itemCounts) - 1
            let rect2 = self.allItemAttributes[idx].frame
            self.unionRects.append(NSValue(cgRect:rect1.union(rect2)))
            idx += 1
        }
    }

    override public var collectionViewContentSize: CGSize {
        let numberOfSections = self.collectionView!.numberOfSections
        if numberOfSections == 0 {
            return CGSize.zero
        }

        var contentSize = self.collectionView!.bounds.size as CGSize

        if columnHeights.count > 0 {
            if let height = self.columnHeights[columnHeights.count - 1].first {
                contentSize.height = height
                return contentSize
            }
        }
        return CGSize.zero
    }

    override public func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        if (indexPath as NSIndexPath).section >= self.sectionItemAttributes.count {
            return nil
        }
        let list = self.sectionItemAttributes[indexPath.section]
        if (indexPath as NSIndexPath).item >= list.count {
            return nil
        }
        return list[indexPath.item]
    }

    override public func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes {
        var attribute: UICollectionViewLayoutAttributes?
        if elementKind == CHTCollectionElementKindSectionHeader {
            attribute = self.headersAttributes[indexPath.section]
        } else if elementKind == CHTCollectionElementKindSectionFooter {
            attribute = self.footersAttributes[indexPath.section]
        }
        guard let returnAttribute = attribute else {
            return UICollectionViewLayoutAttributes()
        }
        return returnAttribute
    }

    override public func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var begin = 0, end = self.unionRects.count
        var attrs: [UICollectionViewLayoutAttributes] = []

        for i in 0 ..< end {
            let unionRect = self.unionRects[i]
            if rect.intersects(unionRect.cgRectValue) {
                begin = i * unionSize
                break
            }
        }
        for i in (0 ..< self.unionRects.count).reversed() {
            let unionRect = self.unionRects[i]
            if rect.intersects(unionRect.cgRectValue) {
                end = min((i + 1) * unionSize, self.allItemAttributes.count)
                break
            }
        }
        for i in begin ..< end {
            let attr = self.allItemAttributes[i]
            if rect.intersects(attr.frame) {
                attrs.append(attr)
            }
        }

        return attrs
    }

    override public func shouldInvalidateLayout (forBoundsChange newBounds: CGRect) -> Bool {
        let oldBounds = self.collectionView!.bounds
        if newBounds.width != oldBounds.width {
            return true
        }
        return false
    }


    /**
     *  Find the shortest column.
     *
     *  @return index for the shortest column
     */
    public func shortestColumnIndexInSection (_ section: Int) -> Int {
        var index = 0
        var shorestHeight = CGFloat.greatestFiniteMagnitude
        for (idx, height) in self.columnHeights[section].enumerated() {
            if height < shorestHeight {
                shorestHeight = height
                index = idx
            }
        }
        return index
    }

    /**
     *  Find the longest column.
     *
     *  @return index for the longest column
     */

    public func longestColumnIndexInSection (_ section: Int) -> Int {
        var index = 0
        var longestHeight: CGFloat = 0.0

        for (idx, height) in self.columnHeights[section].enumerated() {
            if height > longestHeight {
                longestHeight = height
                index = idx
            }
        }
        return index

    }

    /**
     *  Find the index for the next column.
     *
     *  @return index for the next column
     */
    public func nextColumnIndexForItem (_ item: Int, section: Int) -> Int {
        var index = 0
        let columnCount = self.columnCountForSection(section)
        switch self.itemRenderDirection {
        case .chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst :
            index = self.shortestColumnIndexInSection(section)
        case .chtCollectionViewWaterfallLayoutItemRenderDirectionLeftToRight :
            index = (item%columnCount)
        case .chtCollectionViewWaterfallLayoutItemRenderDirectionRightToLeft:
            index = (columnCount - 1) - (item % columnCount)
        }
        return index
    }
}

希望这会对你有所帮助