简体   繁体   English

关于汽车布局

[英]About auto layouts

As I have given auto layout for the collection view but in portrait it was fine: 因为我已经为集合视图提供了自动布局,但是在肖像中它很好:

as I have given auto layout for the collection view but in portrait it was fine

The problem is that where as coming to landscape the gap between the cells are increasing. 问题在于,随着景观的出现,细胞之间的差距正在扩大。 How to avoid this? 怎么避免这个?

问题是,如果进入景观,细胞之间的差距正在增加,如何避免这种情况?


import UIKit

class ViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
    @IBOutlet weak var collectionView: UICollectionView!
    var images = ["apple","banana","cherry","grapes","kiwifruit","mangoes","orange","papaya","passionfruit","peaches","pineapple","strawberry","sugarapple","watermelon"]

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged(notification:)), name: Notification.Name.UIDeviceOrientationDidChange, object: nil)
        collectionView.dataSource = self
        collectionView.delegate = self

    }
    func orientationChanged(notification: Notification) {
        collectionView.collectionViewLayout.invalidateLayout()
    }
        func numberOfSections(in collectionView: UICollectionView) -> Int {
            return 1
        }

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

        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "stridentifier",for:indexPath) as! FruitsCollectionViewCell


            cell.image.image = UIImage(named: images[indexPath.row])
            cell.nameLabel.text = images[indexPath.row]

            return cell
        }
    class SampleCollectionViewFlowLayout: UICollectionViewFlowLayout {
        override init() {
            super.init()
            setUpLayout()
        }

        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setUpLayout()
        }

        override var itemSize: CGSize {
            set {}
            get {
                let itemWidth = ((self.collectionView?.bounds.width)! / 3.0) - self.minimumLineSpacing - minimumInteritemSpacing
                return CGSize(width: itemWidth, height: itemWidth)
            }
        }

        func setUpLayout() {
            minimumInteritemSpacing = 0
            minimumLineSpacing = 1.0
            scrollDirection = .vertical
        }

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

If you have subclassed UICollectionViewFlowLayout you need to override itemSize and setup minimumInteritemSpacing , minimumLineSpacing once you have done that when the orientation changes you need to tell the collection view to reset the layout using collectionView.collectionViewLayout.invalidateLayout() If you haven't subclassed it you need to override 如果您已经子类化了UICollectionViewFlowLayout,则需要覆盖itemSize并设置minimumInteritemSpacingminimumLineSpacing一旦您完成了方向更改,您需要告诉集合视图使用collectionView.collectionViewLayout.invalidateLayout()重置布局如果您还没有子类化它你需要覆盖

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

Whenever the device rotates call the collectionView.collectionViewLayout.invalidateLayout() You will have to add notification for device rotation. 每当设备旋转时调用collectionView.collectionViewLayout.invalidateLayout()您将不得不为设备旋转添加通知。

Here is a sample UICollectionViewFlowLayout for 3 columns 以下是3列的示例UICollectionViewFlowLayout

class SampleCollectionViewFlowLayout: UICollectionViewFlowLayout {
    override init() {
        super.init()
        setUpLayout()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUpLayout()
    }

    override var itemSize: CGSize {
        set {}
        get {
             // 2 columns in portrait and 3 in landscape
          if UIApplication.shared.statusBarOrientation.isPortrait {
           let itemWidth = ((self.collectionView?.bounds.width)! / 2.0) - self.minimumLineSpacing - minimumInteritemSpacing
           return CGSize(width: itemWidth, height: itemWidth)
         }
          let itemWidth = ((self.collectionView?.bounds.width)! / 3.0) - self.minimumLineSpacing - minimumInteritemSpacing
            return CGSize(width: itemWidth, height: itemWidth)
        }
    }

    func setUpLayout() {
        minimumInteritemSpacing = 0
        minimumLineSpacing = 1.0
        scrollDirection = .vertical
    }

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

Add this line in viewDidLoad viewDidLoad添加此行

NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged(notification:)), name: Notification.Name.UIDeviceOrientationDidChange, object: nil)

and add the function 并添加功能

func orientationChanged(notification: Notification) {
  collectionView.collectionViewLayout.invalidateLayout()
}

Also if you are using customLayout you need to go to the xib->select the collectionView->attributes inspector(4th option)-> Tap Layout and select Custom and put the name of the subclassed UICollectionViewLayout class(SampleCollectionViewFlowLayout) in our case. 此外,如果您使用customLayout,则需要转到xib->选择collectionView-> attributes检查器(第四个选项) - >点击布局并选择自定义并在我们的示例中放置子类UICollectionViewLayout类的名称(SampleCollectionViewFlowLayout)。

You need to set UICollectionViewFlowLayout class here after selecting the UICollectionView in you Storyboard/xib file 在Storyboard / xib文件中选择UICollectionView后,需要在此处设置UICollectionViewFlowLayout类

在此输入图像描述

Though i am bit late in this thread.But my solution will work in every devices according to your specification. 虽然我在这个帖子中有点迟了。但我的解决方案将根据您的规范在每个设备中工作。 2 cells in portrait and 3 cells in landscape.But you can increase cell number according to your choice just modify NUMBER_OF_CELLS_IN_PORTRAIT and NUMBER_OF_CELLS_IN_LANDSCAPE 2个单元格为纵向,3个单元格为横向。但您可以根据您的选择增加单元格数量,只需修改NUMBER_OF_CELLS_IN_PORTRAITNUMBER_OF_CELLS_IN_LANDSCAPE

I have made comment in every function.So it may be understandable. 我已经在每个功能上发表评论。所以这可能是可以理解的。

At first i made some default value . 起初我做了一些默认值。

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height

let BASE_SCREEN_HEIGHT:CGFloat = 736.0
let SCREEN_MAX_LENGTH = max(SCREEN_WIDTH, SCREEN_HEIGHT)
let ASPECT_RATIO_RESPECT_OF_7P = SCREEN_MAX_LENGTH / BASE_SCREEN_HEIGHT

let MINIMUM_INTERITEM_SPACING:CGFloat = 14.0 //My Default Inter Cell Spacing for iphone 7plus as i have designed in it.
var ITEM_WIDTH:CGFloat  = 200 //for iPhone 7 plus.initial value
var ITEM_HEIGHT:CGFloat = 200 //for iphone 7 plus.initial value
let NUMBER_OF_CELLS_IN_PORTRAIT:CGFloat = 2
let NUMBER_OF_CELLS_IN_LANDSCAPE:CGFloat = 3 

Then in viewDidLoad i initialize the collection view with the following function 然后在viewDidLoad中使用以下函数初始化集合视图

func initialCollectionData() {
    let orientation = UIApplication.shared.statusBarOrientation
    if orientation == .portrait {
        self.calculateCellSize(screenWidth:SCREEN_WIDTH ,cellItem: NUMBER_OF_CELLS_IN_PORTRAIT)
    }
    else {
        self.calculateCellSize(screenWidth:SCREEN_WIDTH ,cellItem: NUMBER_OF_CELLS_IN_LANDSCAPE)
    }
}

And there are some helper function. 并且有一些辅助功能。 Like this. 像这样。

//This method calculate cellsize according to cell number.
func  calculateCellSize(screenWidth:CGFloat , cellItem:CGFloat) {
    ITEM_WIDTH = (screenWidth - MINIMUM_INTERITEM_SPACING * ASPECT_RATIO_RESPECT_OF_7P  * (cellItem-1)) / cellItem  - 1// This 1 has been subtracted from ITEM_WIDTH to remove mantissa
    ITEM_HEIGHT = ITEM_WIDTH
}

//This method calculate cell number according to orientation.
func findCellItem(screenWidth:CGFloat)  {
    let orientation = UIDevice.current.orientation
    if orientation == .portrait {
        self.calculateCellSize(screenWidth:screenWidth ,cellItem: NUMBER_OF_CELLS_IN_PORTRAIT) //You have chosen 2 cells to show in portrait
    }
    else {
        self.calculateCellSize(screenWidth:screenWidth ,cellItem: NUMBER_OF_CELLS_IN_LANDSCAPE) ////You have chosen 3 cells to show in portrait
    }
}

//During orientation change this method is called everytime.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { context in

        context.viewController(forKey: UITransitionContextViewControllerKey.from)
        //Below two methods do the trick
        self.findCellItem(screenWidth: size.width)
        self.collectionView.collectionViewLayout.invalidateLayout()
    }, completion: {
        _ in
    })

}

//Collection View delegate methods //集合查看委托方法

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

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

    collectionCell.fruitImage.image = UIImage.init(named: imageArray[indexPath.row])
    return collectionCell


}


 public func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}


public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize.init(width: ITEM_WIDTH , height: ITEM_HEIGHT )
}

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
   return MINIMUM_INTERITEM_SPACING * ASPECT_RATIO_RESPECT_OF_7P
}

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return MINIMUM_INTERITEM_SPACING * ASPECT_RATIO_RESPECT_OF_7P
}

Just add the following lines in your ViewController : 只需在ViewController中添加以下行:

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    self.yourCollectionView.collectionViewLayout.invalidateLayout()
}

And set proper size in this delegate method : 并在此委托方法中设置适当的大小:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM