วิธีจัดกึ่งกลางเซลล์ UICollectionView ในแนวนอน


124

ฉันได้ทำการค้นคว้า แต่ไม่พบตัวอย่างโค้ดใด ๆ เกี่ยวกับวิธีจัดกึ่งกลางเซลล์ใน UICollectionView ในแนวนอน

แทนการใช้มือถือเป็นครั้งแรกเช่นนี้x00ผมอยากให้มันเป็นเช่นนี้0x0 มีวิธีใดบ้างที่จะทำให้สำเร็จ

แก้ไข:

เพื่อให้เห็นภาพสิ่งที่ฉันต้องการ:

ใส่คำอธิบายภาพที่นี่

ฉันต้องการให้ดูเหมือนเวอร์ชัน B เมื่อมีเพียงองค์ประกอบเดียวใน CollectionView เมื่อฉันมีองค์ประกอบมากกว่าหนึ่งองค์ประกอบก็ควรจะเป็นเวอร์ชัน A แต่มีองค์ประกอบมากกว่า

ตอนนี้ดูเหมือนเวอร์ชัน A เมื่อฉันมีเพียง 1 องค์ประกอบและฉันสงสัยว่าฉันจะทำให้มันดูเหมือน B ได้อย่างไร

ขอบคุณสำหรับความช่วยเหลือ!


การปล่อยให้เซลล์พอดีกับความกว้างของมุมมองคอลเลคชันแล้วจัดกึ่งกลางของมุมมองคอลเลคชันภายในพาเรนต์ไม่ใช่เรื่องง่ายกว่าหรือ?
Arthur Gevorkyan

ใช่มีอย่างน้อยสองวิธีในการดำเนินการขั้นแรก (เร็ว) คือทำให้ความกว้างของเซลล์ของหน้าจอทั้งหมดและจัดให้อยู่ตรงกลางมุมมองรอง วินาที (ขวา) ใช้เลย์เอาต์มุมมองคอลเลกชันที่กำหนดเอง
sage444

ในที่สุดจะมีเซลล์เพิ่มขึ้นมาจากแบ็กเอนด์การเติมความกว้างทั้งหมดคงไม่ใช่ความคิดที่ดี
RaptoX

เพิ่มความกว้างก็เพียงพอที่จะตั้งไว้ที่กึ่งกลาง
Kishore Kumar

อาจซ้ำกันได้ของHow to center align the cells of a UICollectionView?
kelin

คำตอบ:


229

ไม่ใช่ความคิดที่ดีที่จะใช้ห้องสมุดหากจุดประสงค์ของคุณมีเพียงแค่นี้เพื่อจัดกึ่งกลาง

ดีกว่าคุณสามารถคำนวณง่ายๆนี้ในฟังก์ชัน collectionViewLayout ของคุณ

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    let totalCellWidth = CellWidth * CellCount
    let totalSpacingWidth = CellSpacing * (CellCount - 1)

    let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

2
@ DarshanPatel ขอบคุณมากสำหรับคำตอบที่ฉันใช้สิ่งนี้และแถวก็อยู่ตรงกลางตามที่ควร แต่ตอนนี้ปัญหาคือฉันไม่สามารถเลื่อนไปที่รายการแรกได้ เมื่อฉันพยายามเลื่อนไปที่รายการแรกมันจะนำฉันกลับไปที่ UIEdgeInsets ที่แก้ไขแล้ว คุณสามารถดูแอปสาธิตของฉันgithub.com/anirudha-music/CollectionViewCenter
Anirudha Mahale

5
ในสวิฟท์ 3, collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int)ลายเซ็นวิธีใหม่คือ
Kamchatka

1
คุณสามารถคว้า cellWidth ได้อย่างไรโดยใช้วิธี cellForItemAt ฉันลองแล้วมันกลับไม่มี .. ความกว้างของเซลล์สำหรับฉันเปลี่ยนไปตามขนาดหน้าจอ .. @DarshanPatel
คริส

10
@DarshanPatel บางครั้งคำตอบของคุณอาจให้ผลลบกับอุปกรณ์ขนาดเล็ก พิจารณาใช้การตรวจสอบleftInsetมูลค่าสูงสุดของคุณดังนี้let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen

3
หากคุณไม่ได้คลาสย่อย UICollectionViewController ตรวจสอบให้แน่ใจว่าชั้นเรียนของคุณสอดคล้องกับ UICollectionViewDelegateFlowLayout มิฉะนั้นจะไม่ทำงาน
Saeed Ir

59

สวิฟต์ 5.1

func centerItemsInCollectionView(cellWidth: Double, numberOfItems: Double, spaceBetweenCell: Double, collectionView: UICollectionView) -> UIEdgeInsets {
    let totalWidth = cellWidth * numberOfItems
    let totalSpacingWidth = spaceBetweenCell * (numberOfItems - 1)
    let leftInset = (collectionView.frame.width - CGFloat(totalWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset
    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

Swift 4.2

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
    let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

    let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)

}

สวิฟต์ 3

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

        let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
        let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

        let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
        let rightInset = leftInset

        return UIEdgeInsetsMake(0, leftInset, 0, rightInset)

    }

อย่าลืมเพิ่มโปรโตคอล

UICollectionViewDelegateFlowLayout

ข้อ จำกัด อาจ @ashForIos
อาเหม็ด Safadi

คำตอบของคุณทำงานได้ดีเมื่อมีเซลล์ที่พอดีกับ collectionView เมื่อจำนวนเซลล์เพิ่มขึ้นเซลล์จะอยู่กึ่งกลางและคุณไม่สามารถเลื่อนไปที่เซลล์แรกหรือเซลล์สุดท้ายได้
NickCoder

2
@Vitalii 80 หมายถึงความกว้างของเซลล์และ 10 ช่องว่างระหว่างเซลล์ถ้าคุณอ่านชื่อตัวแปรคุณจะเข้าใจความหมาย: P
Ahmed Safadi

โซลูชัน Swift 4.2 นั้นง่ายกว่าขอบคุณ! อย่าลืมตั้งค่า "80" เป็นค่าความกว้างของเซลล์ - วัตถุจริงของคุณ
John Pitts

25

ลองใช้ Swift 4

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = 165.0

        let numberOfCells = floor(self.view.frame.size.width / cellWidth)
        let edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
    }

เพิ่ม cellWidth แทน 165.0


1
นี่คือคำตอบที่ดีที่สุด ด้วยคณิตศาสตร์ที่ง่ายที่สุดเข้าไป ทำงานร่วมกับแถวและคอลัมน์จำนวน
เท่าใดก็ได้

20

ฉันใช้KTCenterFlowLayoutสำหรับสิ่งนี้และใช้งานได้ดี เป็นคลาสย่อยที่กำหนดเองของUICollectionViewFlowLayoutที่จัดกึ่งกลางเซลล์ตามที่คุณต้องการ (หมายเหตุ: นี่ไม่ใช่เรื่องเล็กน้อยที่จะแก้ปัญหาด้วยการโพสต์โค้ดซึ่งเป็นสาเหตุที่ฉันเชื่อมโยงกับโครงการ GitHub!)


ไม่สามารถใช้งานจาก IB ได้ ห้องสมุดแห่งนี้เป็นเสน่ห์สำหรับฉัน เพิ่งติดตั้งพ็อดและเปลี่ยนคลาสของเลย์เอาต์ใน IB!
tagirkaZ

15

คำตอบของDarshan Patelรุ่นObject -C :

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    CGFloat totalCellWidth = kItemWidth * self.dataArray.count;
    CGFloat totalSpacingWidth = kSpacing * (((float)self.dataArray.count - 1) < 0 ? 0 :self.dataArray.count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}

ขอบคุณ ทำงานได้ดีกับแถวเดียว แต่สร้างปัญหาในหลายแถว ฉันไม่สามารถเพิ่ม url ที่นี่เพื่อแสดงภาพหน้าจอของคุณได้ . แต่คุณสามารถเพิ่ม "yynoalzg" ใน URL เล็ก ๆ คุณจะได้รับความคิด ส่วนทองมี 4 บันทึก อันดับ 4 ควรอยู่ในบรรทัดใหม่ . แต่หลังจากวิธีนี้มันแสดงเช่นนั้น ... แจ้งให้เราทราบหากมีความคิดเห็น
Hitarth

6

แก้ไขคำตอบของ @Safad Funy เล็กน้อยนี่คือสิ่งที่ใช้ได้ผลสำหรับฉันใน Swift & iOS เวอร์ชันล่าสุด ในกรณีนี้ฉันต้องการให้ความกว้างของเซลล์เป็นหนึ่งในสามของขนาดของมุมมองคอลเลคชัน

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

  let totalCellWidth = Int(collectionView.layer.frame.size.width) / 3 * collectionView.numberOfItems(inSection: 0)
  let totalSpacingWidth = (collectionView.numberOfItems(inSection: 0) - 1)

  let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
  let rightInset = leftInset

  return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}

2
สิ่งนี้ได้ผลสำหรับฉันโดยเฉพาะเมื่อมีเซลล์เพียงเซลล์เดียว
Dasoga

6

คุณสามารถใช้ส่วนขยายนี้ (Swift 4)

สามารถจัดกึ่งกลางเซลล์ด้วยถ้าคุณcollectionViewมีlayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSizeมี

ทำงานได้กับเซลล์ทุกขนาดและทำงานได้อย่างสมบูรณ์เมื่อ scrollDirection = .horizontal

public extension UICollectionView {
    func centerContentHorizontalyByInsetIfNeeded(minimumInset: UIEdgeInsets) {
        guard let layout = collectionViewLayout as? UICollectionViewFlowLayout,
            layout.scrollDirection == .horizontal else {
                assertionFailure("\(#function): layout.scrollDirection != .horizontal")
                return
        }

        if layout.collectionViewContentSize.width > frame.size.width {
            contentInset = minimumInset
        } else {
            contentInset = UIEdgeInsets(top: minimumInset.top,
                                        left: (frame.size.width - layout.collectionViewContentSize.width) / 2,
                                        bottom: minimumInset.bottom,
                                        right: 0)
        }
    }
}


final class Foo: UIViewController {
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.centerContentHorizontalyByInsetIfNeeded(minimumInset: yourDefaultInset)
    }
}

หวังว่าจะช่วยคุณได้!


1
รับข้อผิดพลาด: เธรด 1: EXC_BAD_ACCESS (รหัส = 2 ที่อยู่ = 0x118ffde58)
atulkhatri

4

Swift 4.2 (แนวนอนและแนวตั้ง) เป็นการอัพเกรดรหัส Pink Panther เล็กน้อยและขอบคุณเขามาก!


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellHieght: CGFloat = flowLayout.itemSize.height
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var collectionHeight = collectionView.frame.size.height
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
        collectionHeight -= collectionView.safeAreaInsets.top + collectionView.safeAreaInsets.bottom
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    let totalHieght = cellHieght * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInsetWidth = (collectionWidth - totalWidth) / 2

        print(edgeInsetWidth, edgeInsetWidth)
        return UIEdgeInsets(top: 5, left: edgeInsetWidth, bottom: flowLayout.sectionInset.top, right: edgeInsetWidth)
    } else {
        let edgeInsetHieght = (collectionHeight - totalHieght) / 2
        print(edgeInsetHieght, edgeInsetHieght)
        return UIEdgeInsets(top: edgeInsetHieght, left: flowLayout.sectionInset.top, bottom: edgeInsetHieght, right: flowLayout.sectionInset.top)

    }
}

ตรวจสอบให้แน่ใจว่าชั้นเรียนของคุณสอดคล้องกับโปรโตคอลUICollectionViewDelegateFlowLayout


รหัสของคุณใช้งานได้ดีสำหรับฉันจริงๆขอบคุณเพื่อน; )
steveSarsawa

4

นี่คือเวอร์ชันใหม่สำหรับSwift 5ซึ่งทำงานได้ดีเมื่อเซลล์มีมากกว่าหนึ่งแถว:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    var cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var totalWidth: CGFloat
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    repeat {
        totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
        cellCount -= 1
    } while totalWidth >= collectionWidth

    if (totalWidth > 0) {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsets.init(top: flowLayout.sectionInset.top, left: edgeInset, bottom: flowLayout.sectionInset.bottom, right: edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

โปรดตรวจสอบว่าชั้นเรียนของคุณสอดเพื่อUICollectionViewDelegateFlowLayoutโปรโตคอล


3

สวิฟต์ 4

extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

        let cellWidth: CGFloat = 170.0 // Your cell width

        let numberOfCells = floor(view.frame.size.width / cellWidth)
        let edgeInsets = (view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets)
    }

 }

2

สำหรับผู้ที่ต้องการเพิ่มช่องว่างภายใน ( ด้านบนซ้ายล่างขวา ):

เพิ่มโปรโตคอล UICollectionViewDelegateFlowLayout

ตัวอย่างนี้แสดงช่องว่างภายในซ้ายและขวาด้วย 40

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    return UIEdgeInsetsMake(0, 40, 0, 40)
}

2

SWIFT 4.2

private lazy var contentView: UICollectionView = {
        let layoutView: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
            layoutView.scrollDirection = .horizontal
            layoutView.minimumInteritemSpacing = 0
            layoutView.minimumLineSpacing = 5

        let collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layoutView)
            collectionView.dataSource = self
            collectionView.delegate = self
            collectionView.showsHorizontalScrollIndicator = false
            collectionView.isPagingEnabled = true
            collectionView.registerCell(Cell.self)
            collectionView.backgroundColor = .clear
            collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()

//

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

        return CGSize(width: collectionView.frame.width*4/5, height: collectionView.frame.height)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = collectionView.frame.width*4/5

        let numberOfCells = floor(collectionView.frame.width / cellWidth)
        let edgeInsets = (collectionView.frame.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: edgeInsets)
    }
}

1

คุณสามารถลองวิธีแก้ปัญหาของฉันมันใช้ได้ดี

func refreshCollectionView(_ count: Int) {
    let collectionViewHeight = collectionView.bounds.height
    let collectionViewWidth = collectionView.bounds.width
    let numberOfItemsThatCanInCollectionView = Int(collectionViewWidth / collectionViewHeight)
    if numberOfItemsThatCanInCollectionView > count {
        let totalCellWidth = collectionViewHeight * CGFloat(count)
        let totalSpacingWidth: CGFloat = CGFloat(count) * (CGFloat(count) - 1)
        // leftInset, rightInset are the global variables which I am passing to the below function
        leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2;
        rightInset = -leftInset
    } else {
        leftInset = 0.0
        rightInset = -collectionViewHeight
    }
    collectionView.reloadData()
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}

1

คำตอบที่ได้รับการยอมรับเป็นคำตอบที่ถูกต้อง แต่ถ้าคุณtotalCellWidthมีค่าน้อยกว่าCollectionView's widthแต่เพียงเพื่อป้องกันการนี้คุณสามารถทำดังต่อไปนี้

if (leftInset > 0) {
     return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
  } else {
     return UIEdgeInsetsMake(0, 10, 0, 10)
}

1

รหัสนี้ควรจัดกึ่งกลางมุมมองคอลเลกชันในแนวนอนแม้ในSwift 4.0โดยไม่มีการแก้ไขใด ๆ :

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

ตรวจสอบให้แน่ใจว่าชั้นเรียนของคุณเป็นไปตามUICollectionViewDelegateFlowLayoutโปรโตคอล


0

ฉันลงเอยด้วยวิธีการที่แตกต่างอย่างสิ้นเชิงที่นี่ซึ่งฉันเชื่อว่าควรค่าแก่การกล่าวถึง

ฉันตั้งค่าข้อ จำกัด ในมุมมองคอลเลกชันของฉันให้จัดแนวนอนตรงกลาง จากนั้นฉันตั้งค่าข้อ จำกัด อื่นที่ระบุความกว้าง ฉันสร้างทางออกสำหรับข้อ จำกัด ด้านความกว้างภายใน viewController ของฉันที่เก็บมุมมองคอลเลกชัน จากนั้นเมื่อแหล่งข้อมูลของฉันเปลี่ยนไปและฉันกำลังอัปเดตมุมมองคอลเลกชันฉันจะนับจำนวนเซลล์และทำการคำนวณ (คล้ายกันมาก) เพื่อรีเซ็ตความกว้าง

let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)

จากนั้นฉันตั้งค่าข้อ จำกัด ของเต้าเสียบเป็น.constantผลการคำนวณและการจัดวางอัตโนมัติจะดำเนินการส่วนที่เหลือ

สิ่งนี้อาจขัดแย้งกับ `` UICollectionViewDelegateFlowLayout แต่สิ่งนี้ใช้ได้ผลอย่างสมบูรณ์สำหรับฉันในการสร้างมุมมองคอลเลกชันที่จัดชิดซ้าย หากไม่มีผู้รับมอบสิทธิ์ดูเหมือนว่าจะทำงานก็ต่อเมื่อเซลล์เติมเต็มมุมมองส่วนใหญ่


0

วิธีแก้ปัญหาทั่วไปสำหรับโฟลว์เลย์เอาต์ที่จัดกึ่งกลางหน้าหากมีความกว้างน้อยกว่าและจัดแนวซ้ายหากมีมากกว่านั้น

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    // Centering if there are fever pages
    CGSize itemSize = [(UICollectionViewFlowLayout *)collectionViewLayout itemSize];
    CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing];

    NSInteger count = [self collectionView:self numberOfItemsInSection:section];
    CGFloat totalCellWidth = itemSize.width * count;
    CGFloat totalSpacingWidth = spacing * ((count - 1) < 0 ? 0 : count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    if (leftInset < 0) {
        UIEdgeInsets inset = [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset];
        return inset;
    }
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}

เวอร์ชัน Swift (แปลงจาก ObjC)

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // Centering if there are fever pages
    let itemSize: CGSize? = (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize
    let spacing: CGFloat? = (collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing

    let count: Int = self.collectionView(self, numberOfItemsInSection: section)
    let totalCellWidth = (itemSize?.width ?? 0.0) * CGFloat(count)
    let totalSpacingWidth = (spacing ?? 0.0) * CGFloat(((count - 1) < 0 ? 0 : count - 1))
    let leftInset: CGFloat = (bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2
    if leftInset < 0 {
        let inset: UIEdgeInsets? = (collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset
        return inset!
    }
    let rightInset: CGFloat = leftInset
    let sectionInset = UIEdgeInsets(top: 0, left: Float(leftInset), bottom: 0, right: Float(rightInset))
    return sectionInset
}

Untitled-3.png


ขอบเขตในรหัสด่วนคืออะไร? ฉันได้รับข้อผิดพลาดการใช้ตัวระบุ 'ขอบเขต' ที่ไม่ได้รับการแก้ไข
Sachin Tanpure

สวัสดีในตัวอย่างของฉันฉันใช้วิธีการภายใน UIView ซึ่งมีขอบเขตหากคุณนำไปใช้ที่อื่นให้ใช้ขอบเขตที่เหมาะสม
Peter Lapisu

0

ฉันมีสถานการณ์ที่คล้ายกันในโครงการและฉันแก้ไขโดยอ้างถึง UPCarouselFlowLayout

ฉันคิดว่ามันรองรับswift 5เวอร์ชัน

https://github.com/ink-spot/UPCarouselFlowLayout/blob/master/UPCarouselFlowLayout/UPCarouselFlowLayout.swift

ดูการติดตั้งโค้ดใน

override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint

0

วิธีที่ง่ายที่สุดคือตั้งค่าขนาดโดยประมาณของมุมมองคอลเลคชันเป็นไม่มีในสตอรีบอร์ดหรือด้วยโค้ด layout.estimatedItemSize = CGSize.zero


0

หากมีเพียงห้องเดียวสำหรับหนึ่งเซลล์ต่อกลุ่ม a leading:และtrailing:จาก.flexible(0)จะจัดกึ่งกลางเซลล์ในแนวนอน:

item.edgeSpacing = NSCollectionLayoutEdgeSpacing(
    leading: .flexible(0), top: nil,                                                     
    trailing: .flexible(0), bottom: nil
)

0

ฉันใช้รหัสนั้นในโครงการ จัดกึ่งกลางคอลเลกชันดูในแนวนอนและแนวตั้งทั้งสองทิศทาง.horizontalและ.verticalใช้ส่วนที่แทรกเข้าไป คำนึงถึงระยะห่างและสิ่งที่ใส่เข้าไปดั้งเดิมของส่วนหากตั้งค่าไว้ รหัสที่จะใช้ในผู้รับมอบสิทธิ์UICollectionViewDelegateFlowLayoutเพื่อให้เราสามารถเข้าถึงคุณสมบัติทั้งหมดที่เราต้องการเพื่อดึงข้อมูลจากUIcollectionViewหรือตั้งค่าในกระดานเรื่องราวเพื่อนำกลับมาใช้ใหม่ได้

// original function of the delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // casting the layout as a UICollectionViewFlowLayout to have access to the properties of items for reusability - you could also link the real one from the storyboard with an outlet
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    // getting all the properties we need
    let itemWidth = flowLayout.itemSize.width
    let itemHeight = flowLayout.itemSize.height
    let interSpacing = flowLayout.minimumInteritemSpacing
    let lineSpacing = flowLayout.minimumLineSpacing
    // getting the size of the collectionView
    let collectionWidth = collectionView.bounds.width
    let collectionHeight = collectionView.bounds.height
    // getting the direction to choose how to align the collection
    let direction = flowLayout.scrollDirection
    // you don't want to have an item greater than the collection
    guard (itemWidth < collectionWidth && direction == .vertical) || (itemHeight < collectionHeight && direction == .horizontal) else {
        print("Really?")
        return UIEdgeInsets(top: flowLayout.sectionInset.top, left: flowLayout.sectionInset.left, bottom: flowLayout.sectionInset.bottom, right: flowLayout.sectionInset.right)
    }
    // getting the number of item in the current section
    let totalItemCount = CGFloat(collectionView.numberOfItems(inSection: section))
    // setting number of item in a row to the max number of items that can fit in a row without spacing or to the number of items in the section if less than the max
    var itemCountInRow = totalItemCount < (collectionWidth / itemWidth).rounded(.towardZero) ? totalItemCount : (collectionWidth / itemWidth).rounded(.towardZero)
    // how many max row can we have
    var countOfRow = totalItemCount < (collectionHeight / itemHeight).rounded(.towardZero) ? totalItemCount : (collectionHeight / itemHeight).rounded(.towardZero)
    // calculating the total width of row by multiplying the number of items in the row by the width of item and adding the spacing multiplied by the number of item minus one
    var totalWidthOfRow:CGFloat {
        get{
            return (itemWidth * itemCountInRow) + (interSpacing * (itemCountInRow - 1))
        }
    }
    // calculating the total height of row by multiplying the number of row by the height of item and adding the spacing multiplied by the number of row minus one
    var totalHeightOfRow:CGFloat {
        get{
            return (itemHeight * countOfRow) + (lineSpacing * (countOfRow - 1))
        }
    }
    // first we set the inset to the default
    var edgeInsetLeft = flowLayout.sectionInset.left
    var edgeInsetTop = flowLayout.sectionInset.top

    if direction == .vertical {
        // while the width of row with original margin is greater than the width of the collection we drop one item until it fits
        while totalWidthOfRow > collectionWidth || ((collectionWidth - totalWidthOfRow) / 2) < flowLayout.sectionInset.left {
            // droping an item to fit in the row
            itemCountInRow -= 1
        }
        // calculating the number of rows in collectionView by dividing the number of items by the number of items in a row
        countOfRow = (totalItemCount / (itemCountInRow)).rounded(.up)
    } else {
        itemCountInRow = (totalItemCount / countOfRow).rounded(.up)
        // while the height of row with original marginis greater than the height of the collection we drop one row until it fits
        while totalHeightOfRow >= collectionHeight  || ((collectionHeight - totalHeightOfRow) / 2) < flowLayout.sectionInset.top  {
            // droping an item to fit in the row
            countOfRow -= 1
        }
    }
    edgeInsetLeft = max(flowLayout.sectionInset.left, (collectionWidth - totalWidthOfRow) / 2)
    edgeInsetTop = max(flowLayout.sectionInset.top, (collectionHeight - totalHeightOfRow) / 2)
    // we don't specially need insets where the items are overflowing
    let edgeInsetRight = direction == .vertical ? edgeInsetLeft : flowLayout.sectionInset.right
    let edgeInsetBottom = direction == .horizontal ? edgeInsetTop : flowLayout.sectionInset.bottom
    // returning the UIEdgeInsets
    return UIEdgeInsets(top: edgeInsetTop, left: edgeInsetLeft, bottom: edgeInsetBottom, right: edgeInsetRight)
}

หวังว่ามันจะช่วยใครสักคน - มันจะเน้นที่ส่วนนี้ไม่ใช่รายการที่อยู่ในส่วนนี้สำหรับข้อมูลเพิ่มเติมเราต้องซับคลาสUICollectionViewFlowLayoutหรือUICollectionViewLayoutเป็นตัวอย่างโมเสคจาก Apple


-4

ฉันคิดว่าคุณต้องจัดกึ่งกลางเซลล์ดังนั้นแทนที่จะใช้ collectionView ฉันเหมือน UITableView จะเป็นประโยชน์อย่างยิ่ง เพียงใช้ UIViewController และวาง UIView สองตัวไว้ด้านหน้าและด้านหลังแล้ววางUITableViewตรงกลางหวังว่านี่จะช่วยได้


ฉันเพิ่มรูปภาพเพื่อแสดงสิ่งที่ต้องการขอบคุณ!
RaptoX
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.