ระยะห่างระหว่างเซลล์ใน UICollectionView


198

ฉันจะตั้งค่าระยะห่างของเซลล์ในส่วนของได้UICollectionViewอย่างไร ฉันรู้ว่ามีสถานที่ให้บริการminimumInteritemSpacingฉันได้ตั้งไว้ที่ 5.0 ยังคงเป็นระยะห่างไม่ปรากฏ 5.0 ฉันใช้วิธีการมอบหมาย flowout

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{

    return 5.0;
}

ยังฉันไม่ได้รับผลลัพธ์ที่ต้องการ ฉันคิดว่ามันเป็นระยะห่างขั้นต่ำ ไม่มีวิธีใดที่ฉันสามารถกำหนดระยะห่างสูงสุดได้หรือไม่

จำลอง SC


คุณตรวจสอบว่ามันเข้าสู่วิธีการมอบสิทธิ์หรือไม่ .. โดยการใส่เบรกพอยต์ ..
Prashant Nikam

ใช่มันกำลังเข้าสู่ตัวแทนใน IB และฉันได้กำหนดระยะห่างเซลล์ขั้นต่ำเป็น 5 แต่ฉันไม่คิดว่าพื้นที่ขั้นต่ำคือคุณสมบัติที่จะช่วยฉันเพราะมันจะทำให้แน่ใจว่าช่องว่างขั้นต่ำระหว่างเซลล์ควรเป็น 5 แต่ หากมุมมองคอลเลกชันมีพื้นที่พิเศษมากกว่าที่จะใช้พื้นที่พิเศษนั้น ควรมีบางสิ่งเช่นระยะห่างระหว่างเซลล์สูงสุด
Vishal Singh

ผมมีปัญหาเดียวกัน. 5px ดูเหมือนว่าจะไม่ทำงาน อย่างขยันขันแข็งฉันสามารถทำสิ่งนี้ด้วย UITableView แต่ไม่ใช่กับ UICollectionView ...
jerik

ฉันได้แก้ไขแล้วทำการคำนวณบางอย่าง .. ฉันจะโพสต์วันพรุ่งนี้ :)
Vishal Singh

หมายเหตุสำหรับปี 2559เป็นเรื่องง่าย: stackoverflow.com/a/28327193/294884
Fattie

คำตอบ:


144

ฉันรู้ว่าหัวข้อเก่า แต่ในกรณีที่ทุกคนยังต้องการคำตอบที่ถูกต้องสิ่งที่คุณต้องการ:

  1. แทนที่โครงร่างโฟลว์มาตรฐาน
  2. เพิ่มการใช้งานเช่นนั้น:

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *answer = [super layoutAttributesForElementsInRect:rect];
    
        for(int i = 1; i < [answer count]; ++i) {
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = 4;
            NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
    
            if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.origin.x = origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }
        }
        return answer;
    }

โดยที่ maximumSpacing สามารถตั้งค่าเป็นค่าใดก็ได้ที่คุณต้องการ เคล็ดลับนี้รับประกันได้ว่าช่องว่างระหว่างเซลล์จะเท่ากับ EXTRACTIVE สูงสุด!


ดังนั้นเราจะนำสิ่งนี้ไปที่ไหน
จอนนี่

1
เฮ้จอนนี่สืบทอดมาจาก Flow Layout มาตรฐานและเพียงแค่คัดลอกและวางวิธีนี้ในชั้นเรียนของคุณ
iago849

1
โปรดทราบว่าคุณไม่จำเป็นต้องทำ a mutableCopy: คุณไม่ได้กลายพันธุ์เนื้อหาของอาร์เรย์ แต่การกลายพันธุ์วัตถุภายในนั้น
เบอร์ทรัมออบรีย์โบแลนด์

5
บางทีฉันอาจทำสิ่งผิดปกติหรือความคิดนี้ไม่ทำงาน 100% เพราะเมื่อฉันเลื่อนไปยังจุดสิ้นสุดฉันเห็นว่าเซลล์บางเซลล์ซ้อนทับกัน :(
pash3r

2
โพสต์ยอดเยี่ยม ฉันพบข้อผิดพลาดเนื่องจากทำให้การจัดรูปแบบของบรรทัดสุดท้ายของเค้าโครงในบางกรณี ในการแก้ไขปัญหาฉันได้เปลี่ยนเงื่อนไขifเป็นและเพิ่มเติม: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota

190

สนับสนุนคำถามเริ่มต้น ฉันพยายามที่จะเพิ่มระยะห่างเป็น 5px UICollectionViewแต่มันใช้งานไม่ได้เช่นกันกับUIEdgeInsetsMake(0,0,0,0)...

ใน UITableView ฉันสามารถทำได้โดยระบุพิกัด x, y ในหนึ่งแถว ...

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือรหัส UICollectionView ของฉัน:

#pragma mark collection view cell layout / size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return [self getCellSize:indexPath];  // will be w120xh100 or w190x100
    // if the width is higher, only one image will be shown in a line
}

#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {

    return 5.0;
}

อัปเดต: แก้ไขปัญหาของฉันด้วยรหัสต่อไปนี้

ป้อนคำอธิบายรูปภาพที่นี่

ViewController.m

#import "ViewController.h"
#import "MagazineCell.h" // created just the default class. 

static NSString * const cellID = @"cellID";

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Collection view
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 30;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

    mCell.backgroundColor = [UIColor lightGrayColor];

    return mCell;
}

#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
    CGSize mElementSize = CGSizeMake(104, 104);
    return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
   // return UIEdgeInsetsMake(0,8,0,8);  // top, left, bottom, right
    return UIEdgeInsetsMake(0,0,0,0);  // top, left, bottom, right
}

@end

นี่เป็นคำตอบที่ดีกว่ามาก ดูการเรียกกลับที่คุณสามารถปรับได้ใน UICollectionViewDelegateFlowLayout และคุณสามารถดูว่ามันจะถูก tweaked อย่างไร
cynistersix

1
ฉันบางสิ่งนี้สามารถทำงานได้เมื่อความกว้างของรายการ + การเว้นวรรคเท่ากับความกว้างของ uicollectionview
xi.lin

@JayprakashDubey ในขณะนี้ฉันไม่พอดีกับความรวดเร็ว คุณต้องลอง ขอให้โชคดี
jerik

คุณระบุความกว้างระหว่างเซลล์ของ 5px ที่ไหน
UKDataGeek

1
คำตอบที่ดีกว่าคำตอบที่ได้รับการยอมรับส่วนใหญ่เป็นเพราะคลาสย่อย UICollectionViewLayout เพียงเพื่อแทนที่วิธีการหนึ่งดูเหมือนว่า overkill และไม่มีเรื่องเล็กน้อยที่ให้วิธีการอื่น ๆ ทั้งหมดที่จำเป็นต้องมีการแทนที่
Cindeselia

80

เมื่อใช้เลย์เอาต์การไหลในแนวนอนฉันก็ได้รับระยะห่าง 10 จุดระหว่างเซลล์ด้วย ในการลบระยะห่างฉันจำเป็นต้องตั้งค่าminimumLineSpacingเช่นเดียวminimumInterItemSpacingกับศูนย์

UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;

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


34
น่าแปลกใจที่ MinimumLineSpacing มีผลต่อพื้นที่แนวนอนระหว่างเซลล์
Matt H

4
ฉันด้วยฉันต้องการเลื่อนแนวนอนและเว้นระยะห่างระหว่างเซลล์เป็นศูนย์และ MinimumLineSpacing = 0 คือกุญแจ
Wingzero

3
ผมสามารถที่จะได้รับผลกระทบนี้ได้โดยไม่ต้องminimumInteritemSpacingใช้ เพียงแค่ตั้งค่าminimumLineSpacing = 0ในเค้าโครงแนวนอนของฉันลบระยะห่างแนวนอนระหว่างรายการ
Ziewvater

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

62

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

หากเป็นแนวตั้งคุณจำเป็นต้องตั้งค่าช่องว่างของเซลล์หรือช่องว่างระหว่างรายการสำหรับช่องว่างแนวนอนระหว่างเซลล์และช่องว่างระหว่างบรรทัดสำหรับช่องว่างแนวตั้งระหว่างเซลล์

รุ่น Objective-C

- (CGFloat)collectionView:(UICollectionView *)collectionView
                       layout:(UICollectionViewLayout*)collectionViewLayout
    minimumLineSpacingForSectionAtIndex:(NSInteger)section
    {
        return 20;
    }

รุ่น Swift:

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

ตอนนี้ช่องว่างด้านล่างหายไปเมื่อฉันกลับ 0 วิธีการลบพื้นที่ด้านขวา
บังกาลอร์

เฮ้ฉันไม่เข้าใจคำถามของคุณเป็นอย่างดี แต่ฉันคิดว่าinsetForSectionAtIndexเป็นสิ่งที่คุณกำลังมองหา - (UIEdgeInsets) collectionView: (UICollectionView *) layoutView layout: (UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex: (NSInteger) ส่วน (return UIEdgeInsetsMake (5, 10, 5, 10); }
Vincent Joy

เป็นระยะห่างบรรทัดขั้นต่ำสำหรับทั้งแนวนอนและแนวตั้ง
Swati

คุณบันทึกวันของฉัน (Y)
Umair_UAS

โอ้คำพูดของฉัน! ฉันไม่อยากเชื่อสิ่งนี้ ขอบคุณ
Magoo

36

ลองใช้รหัสนี้เพื่อให้แน่ใจว่าคุณมีระยะห่าง 5px ระหว่างแต่ละรายการ:

- (UIEdgeInsets)collectionView:(UICollectionView *) collectionView 
                        layout:(UICollectionViewLayout *) collectionViewLayout 
        insetForSectionAtIndex:(NSInteger) section {

    return UIEdgeInsetsMake(0, 0, 0, 5); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *) collectionView
                   layout:(UICollectionViewLayout *) collectionViewLayout
  minimumInteritemSpacingForSectionAtIndex:(NSInteger) section {    
    return 5.0;
}

โปรดจัดรูปแบบรหัสของคุณเป็นบล็อครหัสดังนั้นมันจะแสดงผลได้ดีบน SO
รางน้ำ

33

สวิฟท์รุ่นของคำตอบที่ได้รับความนิยมมากที่สุด cellSpacingช่องว่างระหว่างเซลล์จะเท่ากับ

class CustomViewFlowLayout : UICollectionViewFlowLayout {

    let cellSpacing:CGFloat = 4

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        if let attributes = super.layoutAttributesForElementsInRect(rect) {
        for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
        }
        return nil
    }
}

super.layoutAttributesForElements (ใน: rect) กำลังส่งคืนความคิดใด ๆ
Ashok R

เช่นเดียวกับวิธีอื่น ๆ ทั้งหมดที่ใช้สิ่งนี้มันไม่ทำงานอย่างถูกต้องสำหรับหลายแถว ช่องว่างสไตล์การปัดเศษข้อผิดพลาดเป็นระยะจะยังคงอยู่ระหว่างแถวแม้จะมีวิธีการมอบหมายที่เหมาะสมและคุณสมบัติที่ตั้งค่าให้ใช้ 0 อาจเป็นปัญหาการแสดงผล UICollectionView
Womble

30

ฉันพบวิธีที่ง่ายมากในการกำหนดค่าระยะห่างระหว่างเซลล์หรือแถวโดยใช้ IB

เพียงแค่เลือก UICollectionView จากสตอรีบอร์ด / ไฟล์ Xib และคลิกในตัวตรวจสอบขนาดตามที่ระบุในภาพด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับการกำหนดค่าพื้นที่ใช้คุณสมบัติต่อไปนี้โดยทางโปรแกรม

1) สำหรับการตั้งช่องว่างระหว่างแถว

[self.collectionView setMinimumLineSpacing:5];

2) สำหรับการตั้งค่าช่องว่างระหว่างรายการ / เซลล์

[self.collectionView setMinimumInteritemSpacing:5];

1
นั่นคือพื้นที่ขั้นต่ำซึ่งจะมากกว่าค่าที่ระบุและไม่ได้เป็นค่าที่ระบุเสมอไป
Vishal Singh

21

โปรดทราบชื่อคุณสมบัติminimumInterItemSpacing นี่จะเป็นระยะห่างต่ำสุดระหว่างรายการที่ไม่ใช่ระยะห่างที่แน่นอน ถ้าคุณตั้งค่าน้อยที่สุดInterItemSpacingให้เป็นค่าบางอย่างคุณสามารถมั่นใจได้ว่าระยะห่างจะไม่เป็นค่าที่น้อย แต่มีโอกาสได้รับมูลค่าที่สูงกว่า

จริงๆแล้วระยะห่างระหว่างรายการขึ้นอยู่กับปัจจัยหลายประการitemSizeและsectionInset มุมมองคอลเล็กชันวางเนื้อหาตามค่าเหล่านี้แบบไดนามิก ดังนั้นคุณไม่สามารถรับรองระยะห่างที่แน่นอนได้ คุณควรจะทดลองและข้อผิดพลาดกับsectionInsetและminimumInterItemSpacing


1
@ มีแมลงขอบหรือไม่ : D
NightFury

10
อาจมีข้อบกพร่องในส่วนของคุณ
Nestor

24
แมลง == ข้อผิดพลาด & & แมลง! = สิ่งที่ใส่เข้าไป :)
เนสเตอร์

16

คำตอบสำหรับ Swift 3.0, Xcode 8

1. ตรวจสอบให้แน่ใจว่าคุณตั้งผู้แทนมุมมองการรวบรวม

class DashboardViewController: UIViewController {
    @IBOutlet weak var dashboardCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardCollectionView.delegate = self
    }
}

2. ฉันใช้UICollectionViewDelegateFlowLayoutโปรโตคอลไม่ใช่ UICollectionViewDelegate

extension DashboardViewController: UICollectionViewDelegateFlowLayout {
    fileprivate var sectionInsets: UIEdgeInsets {
        return .zero
    }

    fileprivate var itemsPerRow: CGFloat {
        return 2
    }

    fileprivate var interitemSpace: CGFloat {
        return 5.0
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let sectionPadding = sectionInsets.left * (itemsPerRow + 1)
        let interitemPadding = max(0.0, itemsPerRow - 1) * interitemSpace
        let availableWidth = collectionView.bounds.width - sectionPadding - interitemPadding
        let widthPerItem = availableWidth / itemsPerRow

        return CGSize(width: widthPerItem, height: widthPerItem)
    }

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

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

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

1
คิดว่าคุณสามารถลบสาธารณะที่นั่นได้ ควรทำงานได้ดีและสอดคล้องกับ func อื่น ๆ ทั้งหมด
Edward Potter

มันจะใช้งานได้กับมุมมองคอลเลกชันเลื่อนแนวตั้งหรือไม่ ฉันมีมุมมองคอลเล็กชันที่ควรแสดง 2 เซลล์ในแนวนอนบนอุปกรณ์เช่น iPhone 6s และ 6s Plus แต่ควรแสดงเพียงเซลล์เดียวสำหรับสิ่งที่ต่ำกว่าเช่น 5s, 5 และ SE รหัสปัจจุบันของฉันทำงานได้ แต่ในอุปกรณ์ 6s Plus ช่องว่างระหว่างเซลล์นั้นมากเกินไปและดูน่าเกลียดและฉันพยายามลดช่องว่างนั้นและนั่นเป็นข้อกำหนดเพียงอย่างเดียวเนื่องจากอุปกรณ์อื่น ๆ ทั้งหมดทำงานตามการออกแบบของฉัน
AnBisw

11

รหัสง่าย ๆ สำหรับการเว้นวรรค

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value

3
สำหรับการเว้นช่องว่างของเซลล์แนวนอนควรใช้: MinimumLineSpacing
Alfi

9

การโหวตคำตอบ (และยังมีรุ่นสวิฟท์ ) มีปัญหาเล็ก ๆ : จะมีระยะห่างขนาดใหญ่อยู่ทางด้านขวา

นี่เป็นเพราะรูปแบบการไหลได้รับการปรับแต่งเพื่อให้ระยะห่างระหว่างเซลล์ตรงตามลักษณะการทำงานแบบลอยซ้าย

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

ในสกรีนช็อตด้านล่างระยะห่างรายการ / บรรทัดเท่ากับ 8 พอยต์ในขณะที่ส่วนซ้ายและขวาแทรกจะใหญ่กว่า 8 พอยต์ (เพื่อจัดแนวกึ่งกลาง):

เซลล์ที่เว้นระยะเท่ากัน

รหัส Swift เช่นนี้:

private let minItemSpacing: CGFloat = 8
private let itemWidth: CGFloat      = 100
private let headerHeight: CGFloat   = 32

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Create our custom flow layout that evenly space out the items, and have them in the center
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
    layout.minimumInteritemSpacing = minItemSpacing
    layout.minimumLineSpacing = minItemSpacing
    layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)

    // Find n, where n is the number of item that can fit into the collection view
    var n: CGFloat = 1
    let containerWidth = collectionView.bounds.width
    while true {
        let nextN = n + 1
        let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
        if totalWidth > containerWidth {
            break
        } else {
            n = nextN
        }
    }

    // Calculate the section inset for left and right. 
    // Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
    let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    collectionView.collectionViewLayout = layout
}

1
ฉันได้รับ 'NSInvalidArgumentException' เหตุผล: '*** setObjectForKey: วัตถุไม่สามารถเป็นศูนย์ได้ (กุญแจ: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0})' ข้อยกเว้นที่ไม่ได้ตรวจสอบ
DaftWooly

... ถ้าฉันไม่เข้าใจผิดขณะที่ลูปของคุณนั้นเทียบเท่ากับ: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly

ไม่ได้ใช้รหัสตามที่เป็นอยู่ แต่สิ่งนี้ให้การอ้างอิงที่ดีที่สุดสำหรับฉันในการนำรูปแบบการไหลออกของฉันไปใช้สำหรับมุมมองคอลเล็กชัน ไชโย
Dima Gimburg

8

กำหนดUICollectionViewDelegateFlowLayoutโปรโตคอลในไฟล์ส่วนหัวของคุณ

ใช้วิธีการUICollectionViewDelegateFlowLayoutโปรโตคอลต่อไปนี้:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(5, 5, 5, 5);
}

คลิกที่นี่เพื่อดูUIEdgeInsetMakeวิธีการเอกสารของ Apple


4

แนวทางสตอรีบอร์ด

เลือก CollectionView ในกระดานเรื่องราวของคุณและไปที่ขนาดผู้ตรวจสอบและกำหนดระยะห่างขั้นต่ำสำหรับเซลล์และเส้นเป็น 5

Swift 5 โดยทางโปรแกรม

lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        //Provide Width and Height According to your need
        let width = UIScreen.main.bounds.width / 4
        let height = UIScreen.main.bounds.height / 10
        layout.itemSize = CGSize(width: width, height: height)

        //For Adjusting the cells spacing
        layout.minimumInteritemSpacing = 5
        layout.minimumLineSpacing = 5

        return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    }()

3

หากคุณต้องการปรับแต่งระยะห่างโดยไม่ต้องสัมผัสขนาดเซลล์จริงนี่เป็นวิธีแก้ปัญหาที่ดีที่สุดสำหรับฉัน #xcode 9 # tvOS11 # iOS11 #swift

ดังนั้นในUICollectionViewDelegateFlowLayoutให้เปลี่ยนใช้วิธีการต่อไปเคล็ดลับคือคุณต้องใช้ทั้งคู่และเอกสารไม่ได้ชี้ให้ฉันคิดในทิศทางนั้นจริงๆ : D

open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return cellSpacing
}

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

2

ฉันใช้ monotouch ดังนั้นชื่อและรหัสจะแตกต่างกันเล็กน้อย แต่คุณสามารถทำได้โดยตรวจสอบให้แน่ใจว่าความกว้างของ collectionview เท่ากับ (x * ความกว้างของเซลล์) + (x-1) * MinimumSpacing กับ x = จำนวน ของเซลล์ต่อแถว

เพียงทำตามขั้นตอนต่อไปนี้ตาม MinimumInteritemSpacing และความกว้างของเซลล์

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

float currentTotalWidth = CollectionView.Frame.Width - Layout.SectionInset.Left - Layout.SectionInset.Right (Layout = flowlayout)
int amountOfCellsPerRow = (currentTotalWidth + MinimumSpacing) / (cell width + MinimumSpacing)

2) ตอนนี้คุณมีข้อมูลทั้งหมดในการคำนวณความกว้างที่คาดไว้สำหรับมุมมองการรวบรวม

float totalWidth =(amountOfCellsPerRow * cell width) + (amountOfCellsPerRow-1) * MinimumSpacing

3) ดังนั้นความแตกต่างระหว่างความกว้างปัจจุบันและความกว้างที่คาดหวังคือ

float difference = currentTotalWidth - totalWidth;

4) ตอนนี้ปรับการแทรก (ในตัวอย่างนี้เราเพิ่มไปทางขวาดังนั้นตำแหน่งด้านซ้ายของมุมมองคอลเลกชันยังคงเหมือนเดิม

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;

2

ฉันมีแนวนอนUICollectionViewและคลาสย่อยUICollectionViewFlowLayoutsubclassed มุมมองคอลเล็กชันมีเซลล์ขนาดใหญ่และแสดงเพียงครั้งละหนึ่งแถวเท่านั้นและมุมมองคอลเลกชันนั้นเหมาะกับความกว้างของหน้าจอ

ฉันลองคำตอบของ iago849 แล้วก็ใช้งานได้ แต่แล้วฉันก็รู้ว่าฉันไม่ต้องการคำตอบของเขา ด้วยเหตุผลบางอย่างการตั้งค่าminimumInterItemSpacingไม่ทำอะไรเลย ระยะห่างระหว่างรายการ / เซลล์ของฉันสามารถควบคุมได้ทั้งหมดminimumLineSpacingเซลล์สามารถควบคุมได้โดยสิ้นเชิง

ไม่แน่ใจว่าทำไมมันทำงานด้วยวิธีนี้ แต่มันทำงาน


1
สิ่งนี้ดูเหมือนจะเป็นจริง - ค่า "เส้น" ที่แปลกคือในความเป็นจริงตัวคั่นระหว่างรายการในกรณีของรูปแบบแนวนอน
Fattie

สวัสดี @ user3344977 - หาดี ฉันตัดสินใจที่จะแยกปัญหานี้ออกเป็นคำถามแยกต่างหากที่จัดการกับมุมมองคอลเล็กชันการเลื่อนในแนวนอนโดยตรงเพื่อให้บางคนค้นหาง่ายขึ้น ฉันอ้างอิงคำตอบของคุณที่นั่น คำถามของฉันอยู่ที่นี่: stackoverflow.com/q/61774415/826946
Andy Weinstein

1

ฉันพบปัญหาคล้ายกันกับ OP น่าเสียดายที่คำตอบที่ยอมรับไม่ได้ผลสำหรับฉันเนื่องจากเนื้อหาของcollectionViewจะไม่อยู่กึ่งกลางอย่างถูกต้อง ดังนั้นฉันจึงคิดวิธีแก้ปัญหาที่แตกต่างกันซึ่งต้องการเพียงว่ารายการทั้งหมดในนั้นcollectionViewมีความกว้างเท่ากันซึ่งน่าจะเป็นกรณีของคำถาม:

#define cellSize 90

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    float width = collectionView.frame.size.width;
    float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    int numberOfCells = (width + spacing) / (cellSize + spacing);
    int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;

    return UIEdgeInsetsMake(0, inset, 0, inset);
}

รหัสนั้นจะทำให้มั่นใจได้ว่าค่าที่ส่งคืนโดย...minimumInteritemSpacing...จะเป็นระยะห่างที่แน่นอนระหว่างทุก ๆcollectionViewCellและยิ่งกว่านั้นรับประกันว่าเซลล์ทั้งหมดเข้าด้วยกันจะอยู่ตรงกลางในcollectionView


มันค่อนข้างเท่ห์ แต่ฉันสงสัยว่าวิธีการแก้ปัญหาที่คล้ายกันสามารถนำไปใช้กับระยะห่างแนวตั้งระหว่างองค์ประกอบ
p0lAris

ระยะห่างแนวตั้งในกรณีที่คุณเลื่อนแนวนอน?
luk2302

1

การแก้ปัญหาข้างต้นโดยvojtech-vrbkaถูกต้อง แต่มันก่อให้เกิดคำเตือน:

คำเตือน: UICollectionViewFlowLayout มีการแคชเฟรมไม่ตรงกันสำหรับพา ธ ดัชนี - ค่าที่แคช: สิ่งนี้อาจเกิดขึ้นเนื่องจากโครงร่างของคลาสย่อยผังการไหลมีการปรับเปลี่ยนแอตทริบิวต์ที่ส่งกลับโดย UICollectionViewFlowLayout โดยไม่คัดลอก

รหัสต่อไปนี้ควรแก้ไข:

class CustomViewFlowLayout : UICollectionViewFlowLayout {

   let cellSpacing:CGFloat = 4

   override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
       let original = super.layoutAttributesForElementsInRect(rect)

       if let original = original {
           let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]

           for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
       }
       return nil
   }
}

2
เช่นเดียวกับคำตอบอื่น ๆ เกี่ยวกับ SO ที่ใช้วิธีการนี้วิธีนี้ใช้ได้ผลกับเซลล์ที่เหมาะสมในความกว้างของ collectionView แต่ช่องว่างความสูงของตัวแปรยังคงเป็นระยะ ๆ อยู่ระหว่างแถว นี่อาจเป็นข้อ จำกัด ของวิธีที่ CollectionView แสดงผลจริง
Womble

1

เวอร์ชั่น Swift 3

เพียงแค่สร้างคลาสย่อย UICollectionViewFlowLayout และวางวิธีนี้

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let answer = super.layoutAttributesForElements(in: rect) else { return nil }

        for i in 1..<answer.count {
            let currentAttributes = answer[i]
            let previousAttributes = answer[i - 1]

            let maximumSpacing: CGFloat = 8
            let origin = previousAttributes.frame.maxX

            if (origin + maximumSpacing + currentAttributes.frame.size.width < self.collectionViewContentSize.width && currentAttributes.frame.origin.x > previousAttributes.frame.origin.x) {
                var frame = currentAttributes.frame
                frame.origin.x = origin + maximumSpacing
                currentAttributes.frame = frame
            }
        }

        return answer
}

วิธีนี้ใช้งานได้สำหรับการปรับแนวนอน แต่ช่องว่างจะยังคงอยู่ระหว่างแถวแม้ว่าค่าขั้นต่ำ LineSpineForSectionAt จะถูกตั้งค่าเป็น 0 และเลย์เอาต์ขั้นต่ำ miniLineSpacing จะถูกตั้งค่าเป็น 0 นอกจากนี้การสัมผัสในคอลเล็กชัน ของช่วง
Womble

1

ฉันได้ลองคำตอบของ iago849 แล้วและก็ใช้งานได้

สวิฟต์ 4

open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let answer = super.layoutAttributesForElements(in: rect) else {
        return nil
    }
    let count = answer.count
    for i in 1..<count {
        let currentLayoutAttributes = answer[i]
        let prevLayoutAttributes = answer[i-1]
        let origin = prevLayoutAttributes.frame.maxX
        if (origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x {
            var frame = currentLayoutAttributes.frame
            frame.origin.x = origin + CGFloat(spacing)
            currentLayoutAttributes.frame = frame
        }
    }
    return answer
}

นี่คือลิงค์สำหรับโครงการ GitHub https://github.com/vishalwaka/MultiTags


0

รุ่นก่อนหน้านี้ไม่ได้จริงๆทำงานร่วมกับส่วน> 1. ดังนั้นวิธีการแก้ปัญหาของฉันได้พบได้ที่นี่https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ สำหรับคนขี้เกียจ:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
    var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
    // use a value to keep track of left margin
    var leftMargin: CGFloat = 0.0;
    for attributes in attributesForElementsInRect! {
        let refAttributes = attributes 
        // assign value if next row
        if (refAttributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left
        } else {
            // set x position of attributes to current margin
            var newLeftAlignedFrame = refAttributes.frame
            newLeftAlignedFrame.origin.x = leftMargin
            refAttributes.frame = newLeftAlignedFrame
        }
        // calculate new value for current margin
        leftMargin += refAttributes.frame.size.width + 10
        newAttributesForElementsInRect.append(refAttributes)
    }

    return newAttributesForElementsInRect
}

0

ฉันมีปัญหากับคำตอบที่ยอมรับดังนั้นฉันจึงอัปเดตนี่ใช้งานได้สำหรับฉัน:

.h

@interface MaxSpacingCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,assign) CGFloat maxCellSpacing;
@end

.m

@implementation MaxSpacingCollectionViewFlowLayout

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    if (attributes.count <= 0) return attributes;

    CGFloat firstCellOriginX = ((UICollectionViewLayoutAttributes *)attributes[0]).frame.origin.x;

    for(int i = 1; i < attributes.count; i++) {
        UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
        if (currentLayoutAttributes.frame.origin.x == firstCellOriginX) { // The first cell of a new row
            continue;
        }

        UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1];
        CGFloat prevOriginMaxX = CGRectGetMaxX(prevLayoutAttributes.frame);
        if ((currentLayoutAttributes.frame.origin.x - prevOriginMaxX) > self.maxCellSpacing) {
            CGRect frame = currentLayoutAttributes.frame;
            frame.origin.x = prevOriginMaxX + self.maxCellSpacing;
            currentLayoutAttributes.frame = frame;
        }
    }
    return attributes;
}

@end

0

โซลูชันของฉันในSwift 3การเว้นช่องว่างระหว่างบรรทัดของเซลล์เหมือนกับใน Instagram:

ป้อนคำอธิบายรูปภาพที่นี่

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.backgroundColor = UIColor.rgb(red: 227, green: 227, blue: 227)
    cv.showsVerticalScrollIndicator = false
    layout.scrollDirection = .vertical
    layout.minimumLineSpacing = 1
    layout.minimumInteritemSpacing = 1
    return cv
}()

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

    switch UIDevice.current.modelName {
    case "iPhone 4":
        return CGSize(width: 106, height: 106)
    case "iPhone 5":
        return CGSize(width: 106, height: 106)
    case "iPhone 6,7":
        return CGSize(width: 124, height: 124)
    case "iPhone Plus":
        return CGSize(width: 137, height: 137)
    default:
        return CGSize(width: frame.width / 3, height: frame.width / 3)
    }
}

วิธีตรวจหาอุปกรณ์โดยทางโปรแกรม: https://stackoverflow.com/a/26962452/6013170


0

minimumLineSpacingดีถ้าคุณกำลังสร้างคอลเลกชันมุมมองแนวนอนแล้วที่จะให้ช่องว่างระหว่างเซลล์คุณจะต้องตั้งค่าคุณสมบัติ


-1

ลองเล่นด้วยวิธีนี้:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

    UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?);

    return insets;
}

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