У меня есть UICollectionView, который загружает ячейки из многоразовой ячейки, содержащей метку. Массив предоставляет контент для этой метки. Я могу легко изменить размер метки в зависимости от ширины содержимого с помощью sizeToFit. Но я не могу подогнать ячейку под этикетку.
Вот код
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrayOfStats = @[@"time:",@"2",@"items:",@"10",@"difficulty:",@"hard",@"category:",@"main"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section{
return [arrayOfStats count];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(??????????);
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
Cell *cell = (Cell *) [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath];
cell.myLabel.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]];
// make label width depend on text width
[cell.myLabel sizeToFit];
//get the width and height of the label (CGSize contains two parameters: width and height)
CGSize labelSize = cell.myLbale.frame.size;
NSLog(@"\n width = %f height = %f", labelSize.width,labelSize.height);
return cell;
}
Ответы:
В
sizeForItemAtIndexPath
вернуть размер текста- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ return [(NSString*)[arrayOfStats objectAtIndex:indexPath.row] sizeWithAttributes:NULL]; }
источник
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath]; cell.myLbale.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]]; CGSize textSize; textSize = [[arrayOfStats objectAtIndex:indexPath.item] sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]}]; [cell.myLbale sizeThatFits:textSize]; //[cell.myLbale sizeToFit]; return cell; }
Swift 4.2+
Принцип такой:
Убедитесь, что делегирование настроено (например
collectionView.delegate = self
)Реализовать
UICollectionViewDelegateFlowLayout
(содержит необходимую сигнатуру метода).collectionView...sizeForItemAt
Метод вызова .Нет необходимости использовать мост
String
дляNSString
вызоваsize(withAttributes:
метода. У SwiftString
он есть прямо из коробки.Атрибуты те же, что и вы
(NS)AttributedString
, например, семейство шрифтов, размер, вес и т.д. Необязательный параметр.Пример решения:
extension ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return "String".size(withAttributes: nil) } }
Но вы, скорее всего, захотите указать конкретные строковые атрибуты, соответствующие вашей ячейке, поэтому окончательный результат будет выглядеть так:
extension ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // dataArary is the managing array for your UICollectionView. let item = dataArray[indexPath.row] let itemSize = item.size(withAttributes: [ NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14) ]) return itemSize } }
Почему НЕ СЛЕДУЕТ использовать UILabel для расчета размера? Вот предлагаемое решение:
let label = UILabel(frame: CGRect.zero) label.text = textArray[indexPath.item] label.sizeToFit()
Да, результат такой же. Это выглядит упрощенно и может показаться подходящим решением. Но это неправильно, потому что: 1) это дорого, 2) накладные расходы и 3) грязно.
Это дорого, потому что UILabel - это сложный объект пользовательского интерфейса, который создается на каждой итерации, когда ваша ячейка собирается показывать, даже если она вам здесь не нужна. Это накладное решение, потому что вам нужно получить только размер текста, но вы можете создать целый объект пользовательского интерфейса. И по этой причине он грязный.
источник
collectionView.delegate == self // or whatever-object-which-do-it
CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Я нашел небольшую хитрость для swift 4.2
Для динамической ширины и фиксированной высоты:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let label = UILabel(frame: CGRect.zero) label.text = textArray[indexPath.item] label.sizeToFit() return CGSize(width: label.frame.width, height: 32) }
Для динамической высоты и фиксированной ширины:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let label = UILabel(frame: CGRect.zero) label.text = textArray[indexPath.item] label.sizeToFit() return CGSize(width: 120, height: label.frame.height) }
источник
sizeWithAttributes
, так что, возможно, это предпочтительный ответ.При оформлении заказа ниже кода вы можете указать очень короткий размер CGSize.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ NSString *testString = @"SOME TEXT"; return [testString sizeWithAttributes:NULL]; }
источник
В Swift 3
let size = (arrayOfStats[indexPath.row] as NSString).size(attributes: nil)
источник
Swift 4
let size = (arrayOfStats[indexPath.row] as NSString).size(withAttributes: nil)
источник
// добавляем в просмотр didload
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal]; layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); self.breadScrumbCollectionView.collectionViewLayout = layout;
источник