Khoảng cách các ô trong UICollectionView


197

Làm cách nào để đặt khoảng cách ô trong một phần của UICollectionView? Tôi biết có một thuộc tính minimumInteritemSpacingtôi đã đặt thành 5.0 nhưng khoảng cách không xuất hiện 5.0. Tôi đã thực hiện phương pháp đại biểu dòng chảy.

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

    return 5.0;
}

Tôi vẫn không nhận được kết quả mong muốn. Tôi nghĩ rằng khoảng cách tối thiểu của nó. Không có cách nào để tôi có thể đặt khoảng cách tối đa?

giả lập sc


bạn có kiểm tra xem nó có đang vào phương thức ủy nhiệm hay không ..? bằng cách đặt điểm dừng ..
Prashant Nikam

vâng, nó đang vào đại biểu, trong IB tôi cũng đã đặt khoảng cách ô tối thiểu là 5. Nhưng tôi không nghĩ không gian tối thiểu là thuộc tính sẽ giúp tôi vì nó sẽ đảm bảo rằng không gian tối thiểu giữa các ô phải là 5, nhưng nếu chế độ xem bộ sưu tập có thêm không gian, thì nó sẽ sử dụng thêm không gian đó. Cần có một cái gì đó như khoảng cách tế bào tối đa
Vishal Singh

Tôi có cùng một vấn đề. 5px dường như không hoạt động. Một cách ngẫu nhiên tôi có thể làm điều này với UITableView, nhưng không phải với UICollectionView ...
jerik

Tôi đã sửa nó bằng một số tính toán..tôi sẽ đăng nó vào ngày mai. :)
Vishal Singh

LƯU Ý CHO NĂM 2016 thật dễ dàng: stackoverflow.com/a/28327193/294884
Fattie

Câu trả lời:


145

Tôi biết rằng chủ đề này đã cũ, nhưng trong trường hợp bất cứ ai vẫn cần câu trả lời chính xác ở đây những gì bạn cần:

  1. Ghi đè bố cục luồng tiêu chuẩn.
  2. Thêm thực hiện như thế:

    - (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;
    }

trong đó MaximumSpaces có thể được đặt thành bất kỳ giá trị nào bạn thích. Thủ thuật này đảm bảo rằng không gian giữa các ô sẽ chính xác bằng maxSpaces !!


Vì vậy, chúng ta đặt cái này ở đâu?
Jonny

1
Xin chào Jonny, kế thừa từ Bố cục luồng tiêu chuẩn và chỉ cần sao chép và dán phương thức này vào lớp của bạn.
iago849

1
Lưu ý rằng bạn không cần phải thực hiện mutableCopy: bạn không làm biến đổi nội dung của mảng, mà là làm biến đổi các đối tượng bên trong nó.
Brock Boland

5
có thể tôi đã làm gì đó sai hoặc ý tưởng này không hoạt động 100%, vì khi tôi cuộn đến cuối tôi thấy rằng một số ô được chồng lên nhau :(
pash3r

2
Bài đăng tuyệt vời. Tôi đã gặp phải một lỗi với nó làm đảo lộn định dạng của dòng cuối cùng của bố cục trong một số trường hợp. Để giải quyết, tôi đã thay đổi ifthành VÀ một điều kiện bổ sung: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota

190

Hỗ trợ câu hỏi ban đầu. Tôi đã cố gắng để khoảng cách đến 5px trên UICollectionViewnhưng điều này không hoạt động, cũng như với mộtUIEdgeInsetsMake(0,0,0,0) ...

Trên UITableView, tôi có thể thực hiện việc này bằng cách chỉ định trực tiếp tọa độ x, y trong một hàng ...

nhập mô tả hình ảnh ở đây

Đây là mã UICollectionView của tôi:

#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;
}

Cập nhật: Đã giải quyết vấn đề của tôi, với đoạn mã sau.

nhập mô tả hình ảnh ở đây

ViewControll.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

Đây là một câu trả lời tốt hơn nhiều. Hãy xem các cuộc gọi lại mà bạn có thể điều chỉnh trong UICollectionViewDelegateFlowLayout và bạn có thể thấy điều này có thể được điều chỉnh như thế nào.
cynistersix

1
Tôi chỉ có thể làm việc khi chiều rộng của vật phẩm + khoảng cách bằng với chiều rộng của uicollectionview.
xi.lin

@JayprakashDubey hiện tại tôi không phù hợp với swift. Bạn phải thử nó. Chúc may mắn
jerik

Bạn đang chỉ định chiều rộng giữa các ô 5px ở đâu?
UKDataGeek

1
Câu trả lời tốt hơn nhiều so với câu trả lời được chấp nhận, chủ yếu là vì phân lớp UICollectionViewLayout chỉ để ghi đè một phương thức có vẻ như quá mức, và không phải là vấn đề tầm thường đối với tất cả các phương thức khác cần được ghi đè.
Cindeselia

80

Sử dụng bố cục luồng ngang, tôi cũng nhận được khoảng cách 10 điểm giữa các ô. Để xóa khoảng cách tôi cần đặt minimumLineSpacingcũng như minimumInterItemSpacingbằng không.

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

Ngoài ra, nếu tất cả các ô của bạn có cùng kích thước, việc đặt thuộc tính trên bố trí luồng trực tiếp sẽ đơn giản và hiệu quả hơn thay vì sử dụng các phương thức ủy nhiệm.


34
Đáng ngạc nhiên, minimLineSpaces ảnh hưởng đến không gian ngang giữa các ô.
Matt H

4
Tôi cũng vậy, tôi cần một cuộn ngang và khoảng cách giữa các ô và tối thiểuLineSpaces = 0 là chìa khóa.
Wingzero 3/2/2015

3
Tôi đã có thể có được hiệu ứng này mà không cần sử dụng minimumInteritemSpacing. Chỉ cần đặt minimumLineSpacing = 0trên bố cục ngang của tôi đã loại bỏ khoảng cách ngang giữa các mục.
Ziewvater

1
Nếu bạn nghĩ về nó, khoảng cách ngang giữa các mục là khoảng cách dòng cho bố cục theo chiều ngang. Khoảng cách dòng là khoảng cách dọc giữa các mục trong một bố cục điển hình, theo chiều dọc.
lancejabr

62

Hãy nhớ rằng, đó là không gian dòng tối thiểu , không phải khoảng cách giữa các mục tối thiểu hoặc không gian ô. Bởi vì hướng cuộn của bộ sưu tập của bạn là HORIZONTAL .

Nếu nó là dọc thì bạn cần đặt không gian ô hoặc không gian mục giữa cho không gian ngang giữa các ô và khoảng cách dòng cho không gian dọc giữa các ô.

Phiên bản Objective-C

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

Phiên bản Swift:

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

bây giờ không gian dưới cùng đã biến mất khi tôi trở về 0; Làm thế nào để loại bỏ không gian bên phải?
Bangalore

Này, tôi không hiểu câu hỏi của bạn lắm. Nhưng tôi nghĩ insetForSectionAt Index là thứ bạn đang tìm kiếm. - Bộ sưu tập (UIEdgeInsets) Xem: (UICollectionView *) bộ sưu tập Xem bố cục: (UICollectionViewLayout *) bộ sưu tậpViewLayout insetForSectionAtIndex: (NSInteger) phần {return UIEdgeInsetsMake (5, 10, 10; }
Vincent Joy

Đó là khoảng cách dòng tối thiểu cho cả ngang và dọc.
Swati

Bạn đã cứu ngày của tôi (Y).
Umair_UAS

Oh từ ngữ của tôi! Tôi không thể tin điều này. Cảm ơn
Magoo

36

Hãy thử mã này để đảm bảo bạn có khoảng cách 5px giữa mỗi mục:

- (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;
}

Vui lòng định dạng mã của bạn dưới dạng một khối mã để nó sẽ hiển thị độc đáo trên SO.
Ống luồn

33

Phiên bản Swift của câu trả lời phổ biến nhất. Không gian giữa các ô sẽ bằng 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.layoutAttributForElements (in: orth) sẽ trả về cho đến khi nào?
Ashok R

Giống như tất cả các phương thức khác sử dụng phương thức này, điều này không hoạt động đúng cho nhiều hàng. Các khoảng trống kiểu lỗi không liên tục, làm tròn sẽ vẫn còn giữa các hàng, ngay cả với các phương thức và thuộc tính đại biểu phù hợp được đặt để sử dụng 0. Đây có thể là sự cố kết xuất UICollectionView.
Womble

30

Tôi đã tìm thấy cách rất dễ dàng để định cấu hình khoảng cách giữa các ô hoặc hàng bằng cách sử dụng IB.

Chỉ cần chọn UICollectionView từ tệp Storyboard / Xib và nhấp vào Size Inspector như được chỉ định trong hình ảnh bên dưới.

nhập mô tả hình ảnh ở đây

Để cấu hình không gian lập trình sử dụng các thuộc tính sau.

1) Để thiết lập không gian giữa các hàng.

[self.collectionView setMinimumLineSpacing:5];

2) Để thiết lập không gian giữa các mục / ô.

[self.collectionView setMinimumInteritemSpacing:5];

1
Đó là không gian tối thiểu, sẽ lớn hơn giá trị được chỉ định và không phải luôn luôn là giá trị được chỉ định.
Vishal Singh

21

Vui lòng lưu ý tên thuộc tính minimInterItemSpaces . Đây sẽ là khoảng cách tối thiểu giữa các mục không chính xác khoảng cách . Nếu bạn đặt minimInterItemSpaces thành một số giá trị, bạn có thể đảm bảo rằng khoảng cách sẽ không phải là một giá trị nhỏ hơn giá trị đó. Nhưng có một cơ hội có được một giá trị cao hơn.

Trên thực tế, khoảng cách giữa các mục phụ thuộc vào một số yếu tố itemSizepartInset . Chế độ xem bộ sưu tập tự động đặt nội dung dựa trên các giá trị này. Vì vậy, bạn không thể đảm bảo khoảng cách chính xác. Bạn nên thực hiện một số thử nghiệm và lỗi với partInsetminimInterItemSpaces .


1
@ Anil cạnh côn trùng? : D
NightFury

10
Có thể có lỗi trong phần của bạn.
Nestor

24
côn trùng == bug && côn trùng! = inet :)
Nestor

16

Trả lời cho Swift 3.0, Xcode 8

1. Hãy chắc chắn rằng bạn đặt đại biểu cho bộ sưu tập

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

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

2. Thực hiện giao thức UICollectionViewDelegateFlowLayout , không phải 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
Hãy nghĩ rằng bạn có thể loại bỏ công chúng ở đó. Nên hoạt động tốt và phù hợp với tất cả các chức năng khác.
Edward Potter

Điều này sẽ làm việc cho xem bộ sưu tập cuộn dọc? Tôi có chế độ xem bộ sưu tập, nơi nó sẽ hiển thị 2 ô theo chiều ngang trên các thiết bị như iPhone 6s và 6s Plus, nhưng sẽ chỉ hiển thị một ô cho bất cứ thứ gì thấp hơn đó là 5s, 5 và SE. Mã hiện tại của tôi đang hoạt động nhưng trong thiết bị 6s Plus, khoảng cách giữa các ô là quá nhiều và trông xấu và tôi đang cố gắng giảm khoảng cách đó và đó là yêu cầu duy nhất vì tất cả các thiết bị khác đều hoạt động theo thiết kế của tôi.
AnBisw

11

Mã đơn giản cho khoảng cách

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

3
Đối với khoảng cách ô ngang nên sử dụng: minimLineSpaces
Alfi

9

Các bình chọn câu trả lời (và cũng là phiên bản nhanh chóng ) có một vấn đề nhỏ: sẽ có một khoảng cách lớn ở bên phải.

Điều này là do cách bố trí luồng được tùy chỉnh để làm cho khoảng cách giữa các ô chính xác, với hành vi thả nổi bên trái .

Giải pháp của tôi là thao tác với phần chèn, sao cho phần đó được căn giữa, nhưng khoảng cách chính xác như được chỉ định.

Trong ảnh chụp màn hình bên dưới, khoảng cách giữa các mục / dòng chính xác là 8pt, trong khi phần bên trái và bên phải sẽ lớn hơn 8pt (để làm cho nó được căn giữa):

các ô cách đều nhau

Mã Swift như vậy:

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
Tôi nhận được 'NSInvalidArgumentException', lý do: '*** setObjectForKey: object không thể là nil (key: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0})' ngoại lệ.
DaftWooly

... nếu tôi không nhầm, vòng lặp while của bạn tương đương với: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly

Không sử dụng mã như vậy, nhưng điều này đã cho tôi tài liệu tham khảo tốt nhất để triển khai bố cục luồng ra cho chế độ xem bộ sưu tập. chúc mừng
Dima Gimburg

8

Xác định UICollectionViewDelegateFlowLayoutgiao thức trong tệp tiêu đề của bạn.

Thực hiện phương pháp UICollectionViewDelegateFlowLayoutgiao thức như sau:

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

Nhấn vào đây để xem Tài liệu của Apple về UIEdgeInsetMakephương pháp.


3

Nếu bạn muốn điều chỉnh khoảng cách mà không chạm vào kích thước ô thực tế, đây là giải pháp phù hợp nhất với tôi. #xcode 9 # tvOS11 # iOS11 #swift

Vì vậy, trong UICollectionViewDelegateFlowLayout , thay đổi thực hiện các phương thức tiếp theo, mẹo là bạn phải sử dụng cả hai và tài liệu không thực sự khiến tôi phải suy nghĩ theo hướng đó. : 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
}

3

Cách tiếp cận Storyboard

Chọn CollectionView trong bảng phân cảnh của bạn và đi đến trình kiểm tra kích thước và đặt khoảng cách tối thiểu cho các ô và dòng là 5

Swift 5 lập trình

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)
    }()

2

Tôi đang sử dụng monotouch, vì vậy tên và mã sẽ khác nhau một chút, nhưng bạn có thể làm điều này bằng cách đảm bảo rằng chiều rộng của bộ sưu tập bằng (x * chiều rộng ô) + (x-1) * Khoảng cách tối thiểu với x = lượng của các ô trên mỗi hàng.

Chỉ cần thực hiện các bước sau dựa trên MaximumInteritemSpaces và Width của ô

1) Chúng tôi tính toán số lượng mục trên mỗi hàng dựa trên kích thước ô + phần tử hiện tại + khoảng cách tối thiểu

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

2) Bây giờ bạn có tất cả thông tin để tính chiều rộng dự kiến ​​cho chế độ xem bộ sưu tập

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

3) Vì vậy, sự khác biệt giữa chiều rộng hiện tại và chiều rộng dự kiến ​​là

float difference = currentTotalWidth - totalWidth;

4) Bây giờ điều chỉnh các phần tử (trong ví dụ này, chúng tôi thêm nó vào bên phải, vì vậy vị trí bên trái của bộ sưu tập vẫn giữ nguyên

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

2

Tôi có một UICollectionViewlớp ngang và phân lớpUICollectionViewFlowLayout . Chế độ xem bộ sưu tập có các ô lớn và chỉ hiển thị một hàng trong số chúng tại một thời điểm và chế độ xem bộ sưu tập phù hợp với chiều rộng của màn hình.

Tôi đã thử câu trả lời của iago849 và nó đã hoạt động, nhưng sau đó tôi phát hiện ra tôi thậm chí không cần câu trả lời của anh ấy. Đối với một số lý do, thiết lập minimumInterItemSpacingkhông làm gì. Khoảng cách giữa các mục / ô của tôi có thể được kiểm soát hoàn toàn bởiminimumLineSpacing .

Không chắc chắn tại sao nó hoạt động theo cách này, nhưng nó hoạt động.


1
điều này có vẻ đúng - thật kỳ lạ là giá trị "đường" trên thực tế là dấu phân cách giữa các mục trong trường hợp bố trí theo chiều ngang.
Fattie

Hey @ user3344977 - tìm thấy tốt đẹp. Tôi quyết định tách vấn đề này thành một câu hỏi riêng biệt trực tiếp giải quyết các chế độ xem bộ sưu tập cuộn ngang để dễ tìm thấy hơn đối với một số người. Tôi tham khảo câu trả lời của bạn ở đó. Câu hỏi của tôi là ở đây: stackoverflow.com/q/61774415/826946
Andy Weinstein

1

Tôi vấp phải một vấn đề tương tự như OP. Thật không may, câu trả lời được chấp nhận đã không làm việc cho tôi vì nội dung của câu trả lời collectionViewsẽ không được tập trung chính xác. Vì vậy, tôi đã đưa ra một giải pháp khác nhau mà chỉ yêu cầu tất cả các mục trong collectionViewlà của cùng một chiều rộng , mà dường như là trường hợp trong câu hỏi:

#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);
}

Mã đó sẽ đảm bảo rằng giá trị được trả về ...minimumInteritemSpacing...sẽ là khoảng cách chính xác giữa mọi collectionViewCellvà hơn nữa đảm bảo rằng các ô cùng nhau sẽ được căn giữa trongcollectionView


Điều đó thật tuyệt. Nhưng tôi đã tự hỏi nếu một giải pháp tương tự có thể được áp dụng cho khoảng cách dọc giữa các yếu tố
p0lAris

Khoảng cách dọc trong trường hợp bạn có cuộn ngang?
luk2302

1

Các giải pháp trên của Vojtech-Vrbka là đúng nhưng nó gây ra một cảnh báo:

cảnh báo: UICollectionViewFlowLayout có bộ đệm khung không khớp cho đường dẫn chỉ mục - giá trị được lưu trong bộ nhớ cache: Điều này có thể xảy ra do lớp con bố cục luồng Bố cục được sửa đổi các thuộc tính được trả về bởi UICollectionViewFlowLayout mà không sao chép chúng

Các mã sau đây nên sửa nó:

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
Giống như các câu trả lời khác về SO sử dụng phương pháp này, cách này hoạt động để khớp các ô trên chiều rộng của bộ sưu tập, nhưng các khoảng trống có chiều cao thay đổi không liên tục vẫn còn giữa các hàng. Đây có thể là một hạn chế của cách CollectionView thực sự biểu hiện.
Womble

1

Phiên bản Swift 3

Chỉ cần tạo một lớp con UICollectionViewFlowLayout và dán phương thức này.

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
}

Điều này hoạt động cho khớp ngang, nhưng các khoảng trống sẽ vẫn còn giữa các hàng, ngay cả khi minimLineSpacesForSectionAt được đặt về 0 và layout.minimumLineSpaces được đặt thành 0. Ngoài ra, một lần chạm trong bộ sưu tậpView sẽ bị lỗi ứng dụng, do vòng lặp đầu tiên bị tắt của phạm vi.
Womble

1

Tôi đã thử câu trả lời của iago849 và nó đã hoạt động.

Swift 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
}

Đây là liên kết cho dự án github. https://github.com/vishalwaka/MultiTags


0

Các phiên bản trước không thực sự hoạt động với các phần> 1. Vì vậy, giải pháp của tôi đã được tìm thấy ở đây https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ . Dành cho những người lười biếng:

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

Tôi có vấn đề với câu trả lời được chấp nhận, vì vậy tôi đã cập nhật nó, đây là cách làm việc với tôi:

.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

Giải pháp của tôi trong Swift 3khoảng cách dòng di động như trong Instagram:

nhập mô tả hình ảnh ở đây

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)
    }
}

Cách phát hiện thiết bị theo chương trình: https://stackoverflow.com/a/26962452/6013170


0

Chà, nếu bạn đang tạo chế độ xem bộ sưu tập theo chiều ngang để tạo khoảng trống giữa các ô, bạn cần đặt thuộc tính minimumLineSpacing.


-1

Hãy thử chơi xung quanh với phương pháp này:

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

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

    return insets;
}

2
Điều này chỉ hoạt động cho khoảng cách giữa các phần, không phải các ô
Diego A. Rincon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.