Проблем с автоматичното преоразмеряване на рамката на UICollectionViewCell contentView в прототипна клетка на Storyboard (Xcode 6, iOS 8 SDK) се случва, когато работи само на iOS 7

Използвам Xcode 6 Beta 3, iOS 8 SDK. Изградете Target iOS 7.0 с помощта на Swift. Моля, обърнете се към моя проблем стъпка по стъпка с екранни снимки по-долу.

Имам UICollectionView в Storyboard. 1 прототип UICollectionViewCell, който съдържа 1 етикет в центъра (без правило за автоматично преоразмеряване). Пурпурният фон трябваше да маркира contentView, който се генерира по време на изпълнение от клетката, предполагам. Този изглед ще бъде преоразмерен правилно въз основа на моя UICollectionViewLayoutDelegate евентуално, но не и на iOS 7. Забележете, че използвам Xcode 6 и проблемът се случва само на iOS 7.

Когато създам приложението на iOS 8. Всичко е наред.

Забележка: Лилаво е contentView, синьо е моят UIButton със заоблен ъгъл.

http://i.stack.imgur.com/uDNDY.png

В iOS 7 обаче всички подизгледи в клетката внезапно се свиват до рамката от (0,0,50,50) и вече никога не отговарят на моето правило за автоматично преоразмеряване.

http://i.stack.imgur.com/lOZH9.png

Предполагам, че това е грешка в iOS 8 SDK или Swift или може би Xcode?


Актуализация 1: Този проблем все още съществува в официалния Xcode 6.0.1! Най-добрата работа е като това, което KoCMoHaBTa предложи по-долу, като зададете рамката в cellForItem на клетката (Все пак трябва да подкласирате вашата клетка). Оказа се, че това е несъвместимост между iOS 8 SDK и iOS 7 (проверете отговора на ecotax по-долу, цитиран от Apple).

Актуализация 2: Поставете този код в началото на вашия cellForItem и нещата трябва да са наред:

/** Xcode 6 on iOS 7 hot fix **/
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
/** End of Xcode 6 on iOS 7 hot fix **/

person thkeen    schedule 15.07.2014    source източник
comment
Разбрах, че този проблем все още съществува в Xcode 6 Beta 5. Някой имал ли е това?   -  person thkeen    schedule 13.08.2014
comment
В момента се боря с това в моя проект. iOS 7 и iOS 8, създадени с помощта на Xcode 5, изглеждат добре. iOS 8, създаден с помощта на Xcode 6 beta 6, изглежда добре. iOS 7, създаден с помощта на Xcode 6 beta 6, има проблема, който описвате. С помощта на Reveal мога да видя, че моята UICollectionViewCell е правилно оразмерена. Но contentView на клетката не беше преоразмерен, въпреки че е родител, UICollectionViewCell има включени Autoresize Subviews. Размерът на contentView е зададен на това, което има сценария. Не използвам автоматично оформление в този проект. Моят проект е напълно обективен-c.   -  person Del Brown    schedule 28.08.2014
comment
Просто исках да добавя, че този проблем все още съществува от Xcode 6 / iOS 8 GM seed. Отговорът на @DanielPlamann да принуди contentView да преоразмери с клетката работи добре, за да заобиколи проблема. Предполагам, че в iOS 8 Apple е променила нещо относно начина, по който се обработват изгледите на съдържанието на клетките, когато са създадени в Interface Builder (което все още е малко черна кутия). Но фактът, че променя поведението си при насочване към iOS 7, със сигурност е грешка.   -  person Stuart    schedule 10.09.2014
comment
Същото тук с Xcode 6 GM, автоматично оформление и клетка, базирана на писалка. Поправям го, като закача contentView ръбовете към ръбовете на клетката.   -  person sergiou87    schedule 10.09.2014
comment
Да, това не е добре. Изобщо не искам да поставям това решение в производствено приложение. Някой от вас подавал ли е вече това като доклад за грешка? Страхувам се, че не приемат това достатъчно сериозно.   -  person thkeen    schedule 10.09.2014
comment
@sergiou87 как успя да закачиш contentView към ръбовете чрез перото, когато UICollectionViewCells не показват contentView в перото?   -  person Acey    schedule 10.09.2014
comment
@Acey, за съжаление това трябва да се направи в код :-\ Ние използваме персонализиран подклас на UICollectionViewCell като основен клас за нашите персонализирани клетки.   -  person sergiou87    schedule 12.09.2014
comment
Е, всъщност не е жалко, защото като го правим по този начин, избягваме да го правим за всяка клетка :D   -  person sergiou87    schedule 12.09.2014
comment
@Acey Току-що актуализирах най-доброто решение, независимо дали използвате nib или не. Поставянето на блока от код в cellForItem е най-безопасният начин.   -  person thkeen    schedule 23.09.2014
comment
Случва се както на Xcode 6.0 (от AppStore), така и на Xcode 6.1 Beta за Yosemite. „Актуализация 2“ работи като чар. Прекарах половин ден на това...   -  person Aviel Gross    schedule 23.09.2014
comment
Apple изглежда е коригирала този проблем във версия 8.1 на iOS SDK в Xcode 6.1 GM (компилация 6A1042b). Премахнах хака и моите клетки за преглед на колекцията бяха оразмерени правилно. Може ли някой друг да потвърди това?   -  person phatmann    schedule 07.10.2014
comment
Тествахте ли на iOS 7?   -  person thkeen    schedule 08.10.2014
comment
Изтеглих xcode 6.1, но все още виждам същия проблем в симулатора.   -  person Haitao Li    schedule 23.10.2014
comment
Никога не съм имал този проблем преди актуализацията на iOS 8.1, след това започна да се случва (в код, компилиран с 6.0.1, а също и когато прекомпилирах в 6.1). Трябваше да добавя заобиколното решение, за да се отърва от него.   -  person meelawsh    schedule 24.10.2014
comment
Нито едно от решенията все още не работи за мен!! Някаква помощ?   -  person thatzprem    schedule 03.12.2014
comment
stackoverflow.com/questions/27265576/ Имам друг проблем със статичната клетка   -  person thkeen    schedule 03.12.2014
comment
Момчета, тъжната новина е, че Apple все още оставя този бъг до най-новия iOS SDK.   -  person thkeen    schedule 15.01.2015
comment
За всеки, който се сблъсква с подобен проблем и работи с модерни инструменти на iOS, т.е. Swift, нека погледне тази публикация mydaytodo.com/build-a-no-storyboard-ios-ap   -  person cptdanko    schedule 05.01.2021


Отговори (12)


contentView е повреден. Може да се коригира и в awakeFromNib

ObjC:

- (void)awakeFromNib {

    [super awakeFromNib];

    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

Swift3:

override func awakeFromNib() {
    super.awakeFromNib()

    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
person Igor Palaguta    schedule 10.09.2014
comment
Направи трика без self.contentView.frame = self.bounds; Мислиш, че имам нужда от него? Благодаря все пак! - person Michal Shatz; 21.09.2014
comment
Здравей Михал, съгласен съм с теб. Но за 100% да съм сигурен, как ще работи в следващите iOS, по-добре да го добавите мисля. - person Igor Palaguta; 21.09.2014
comment
Харесвам този отговор, но трябва да се обадите на [super awakeFromNib]; Също така, обмислям да добавя проверка за iOS 7.1 и по-малко, защото не съм сигурен как добавянето на тези маски за преоразмеряване влияе на поведението по подразбиране на iOS8. - person GingerBreadMane; 23.09.2014
comment
Ако не използвате нибове или сторибордове, това също работи, ако го поставите в applyLayoutAttributes: - person cetcet; 26.09.2014
comment
Това не работи за мен. Не използвам Autolayout!! Някаква помощ? - person thatzprem; 03.12.2014
comment
Как създавате клетка? От перото? - person Igor Palaguta; 03.12.2014
comment
Виждахме проблем с ios 8.x, че клетката за изглед на колекция понякога не показваше всички свои подизгледи. Това реши нашите проблеми, но е малко по-различно от основния въпрос. - person ort11; 08.12.2014
comment
Добавих същия код в swift. Но все пак приложението се срива и показва грешка при лошо изпълнение на layout2.estimatedItemSize = CGSize(width: 300, height: 50). Добавих код в подклас на клетка self.contentView.frame = self.bounds; self.contentView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight. Ейми, човек знае как да коригира бързо - person sudheer; 30.12.2014
comment
Добавянето на подизгледи с автоматично преоразмеряване в Nib е истинският трик. Ти не правиш нищо друго. - person Deepak G M; 20.01.2015
comment
Ами ако таблицата с разкадровка има статични клетки? - person Mohammad Sadiq Shaikh; 19.03.2015
comment
Как може contentView да бъде счупен, все пак? - person Alper; 20.09.2018

Срещнах същия проблем и помолих Apple DTS за помощ. Техният отговор беше:

В iOS 7 изгледите на съдържанието на клетките се оразмеряват сами чрез маски за автоматично преоразмеряване. В iOS 8 това беше променено, клетките спряха да използват маските за автоматично преоразмеряване и започнаха да оразмеряват изгледа на съдържанието в layoutSubviews. Ако едно перо е кодирано в iOS 8 и след това го декодирате в iOS 7, ще имате изглед на съдържание без маска за автоматично преоразмеряване и никакви други средства, чрез които да се оразмерява. Така че, ако някога промените рамката на клетката, изгледът на съдържанието няма да последва.

Приложенията, които се внедряват обратно към iOS 7, ще трябва да заобиколят това чрез оразмеряване на самия изглед на съдържанието, добавяне на маски за автоматично преоразмеряване или добавяне на ограничения.

Предполагам, че това означава, че не е грешка в XCode 6, а несъвместимост между iOS 8 SDK и iOS 7 SDK, което ще ви удари, ако надстроите до Xcode 6, защото автоматично ще започне да използва iOS 8 SDK.

Както коментирах преди, заобиколното решение, описано от Daniel Plamann, работи за мен. Описаните от Игор Палагута и KoCMoHaBTa обаче изглеждат по-прости и изглежда има смисъл да се даде отговор на Apple DTS, така че ще ги пробвам по-късно.

person ecotax    schedule 17.09.2014
comment
Това е интересно, но все пак се надявам да го оправят. Това поведение беше въведено само в Xcode 6 GM, който добави поддръжка за iPhone 6. Работеше добре в по-ранните бета версии. Дори върнах проект към по-ранна бета версия, след като го забелязах и той работи според очакванията. Надявам се, че всички подават грешки на Apple по този въпрос. - person arton; 30.09.2014
comment
@arton Подадох сигнал за грешка същия ден, когато помолих DTS за помощ. Беше затворен като дубликат на 18312246. Не знам доколко това помага. - person ecotax; 01.10.2014
comment
Използвах заобикалянето чрез оразмеряване на ContentView и работи за мен. - (CGSize)collectionViewContentSize { return CGSizeMake(self.collectionView.bounds.size.width, self.collectionView.bounds.size.height); } - person Jesús Hurtado; 30.04.2015

Срещнах същия проблем и се надявам, че Apple ще поправи това със следващата версия на Xcode. Междувременно използвам заобиколно решение. В моя подклас UICollectionViewCell току-що замених layoutSubviews и преоразмерих contentView ръчно, в случай че размерът се различава от размера collectionViewCell.

- (void)layoutSubviews
{
  [super layoutSubviews];

  BOOL contentViewIsAutoresized = CGSizeEqualToSize(self.frame.size, self.contentView.frame.size);

  if( !contentViewIsAutoresized) {
    CGRect contentViewFrame = self.contentView.frame;
    contentViewFrame.size = self.frame.size;
    self.contentView.frame = contentViewFrame;
  }
}
person Daniel Plamann    schedule 02.09.2014
comment
Да, използвах подобна работа, но го направих в cellForItem / cellForRow, което също работи. - person thkeen; 04.09.2014
comment
Това е най-доброто решение. Добавянето на това в cellForItem/cellForRow ще доведе до странни артефакти, ако въртите устройството и размерът на клетката се промени. - person spybart; 12.09.2014
comment
здрасти Имам проблем с този код. За първи път булевият contentViewIsAutoresized ще бъде верен, ако е зареден от сценарий или прототипна клетка. Само когато направите reloadData, второто ще бъде правилно. Така че всъщност не е нужно да проверявате размера. Вместо това просто направете: self.contentView.frame = self.bounds; - person thkeen; 18.09.2014
comment
Потвърдено: трябва да го направим в cellForItem или cellForRow, защото layoutSubviews се извиква само след връщане на клетката. Всичко, което правите преди това, като например чертане, ще бъде грешно изчислено. - person thkeen; 18.09.2014
comment
Хм, може би е по-добре да поставите [cell layoutIfNeeded]; в cellForItem или cellForRow? - person wtorsi; 22.09.2014

Друго решение е да зададете размера на contentView и маските за автоматично преоразмеряване в -collectionView:cellForItemAtIndexPath: като следното:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

     static NSString *cellID = @"CellID";

     UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

     // Set contentView's frame and autoresizingMask
     cell.contentView.frame = cell.bounds;
     cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;

     // Your custom code goes here

     return cell;
}

Това работи и с Auto Layout, тъй като маските за автоматично преоразмеряване се преобразуват в ограничения.

person KoCMoHaBTa    schedule 10.09.2014
comment
Това е превъзходно решение, тъй като работи с всеки тип клетка без подкласиране и не изисква промени на множество места, когато използвате повече от един тип клетка в изгледа на вашата колекция. - person nacross; 14.10.2014

В Xcode 6.0.1 contentView за UICollectionViewCell е повреден за iOS7 устройства. Може също да бъде коригирано чрез добавяне на подходящи ограничения към UICollectionViewCell и неговия contentView в методите awakeFromNib или init.

        UIView *cellContentView = self.contentView;
        cellContentView.translatesAutoresizingMaskIntoConstraints = NO;

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];
person SerJ_G    schedule 15.10.2014
comment
Само това работи сега, трябва да го направите само за IOS 8 и трябва да го извиквам след всяко изваждане от опашката! Но това също не е идеалното решение, защото многократният избор не работи както би трябвало визуално... - person Renetik; 02.01.2015
comment
Най-добре е наистина да използвате автоматично оформление, с този бъг спестявате иронично време, като използвате събитие за автоматично оформление в прост случай. - person Renetik; 02.01.2015
comment
Маската не ми действа; въпреки това задаването на ограниченията работи! - person entropid; 18.03.2015

Това няма да работи правилно без някое от другите споменати решения поради грешка в Xcode 6 GM с това как Xcode компилира xib файлове във формат nib. Въпреки че не мога да кажа със 100% сигурност, че е свързано с Xcode и не е свързано с времето за изпълнение, аз съм много уверен - ето как мога да го покажа:

  1. Създайте+изпълнете приложението в Xcode 5.1.
  2. Отидете в директорията на приложението за симулатор и копирайте компилирания .nib файл за xib, с който имате проблеми.
  3. Създайте+изпълнете приложението в Xcode 6 GM.
  4. Спрете приложението.
  5. Заменете файла .nib в папката на симулатора на новоизграденото приложение с файла .nib, създаден с помощта на Xcode 5.1
  6. Рестартирайте приложението от симулатора, НЕ от Xcode.
  7. Вашата клетка, заредена от този .nib, трябва да работи според очакванията.

Надявам се, че всеки, който прочете този въпрос, ще подаде радар в Apple. Това е ОГРОМЕН проблем и трябва да бъде решен преди окончателното издание на Xcode.

Редактиране: В светлината на публикацията на ecotax, просто исках да актуализирам това, за да кажа, че вече са потвърдени разлики в поведението между изграждането в iOS 8 срещу iOS 7, но не е грешка. Моят хак коригира проблема, тъй като изграждането на iOS 7 добави маската за автоматично преоразмеряване към изгледа на съдържанието, необходима, за да може това да работи, която Apple вече не добавя.

person Acey    schedule 10.09.2014
comment
Не съм сигурен дали законно могат да пуснат xCode, различен от версията на GM - person Mabedan; 16.09.2014
comment
Хаха ще влязат ли в затвора? =P Но съвсем сериозно, със сигурност могат. Имаха множество GM версии за Mavericks, ако не си спомняте. Не е твърде често, но може да се случи. - person Acey; 16.09.2014

Отговорите в тази публикация работят, това, което така и не разбрах, е защо работи.

Първо, има две "правила":

  1. За изгледи, създадени програмно (Напр. [UIView new]), свойството translatesAutoresizingMaskIntoConstraints е зададено на YES
  2. Изгледите, създадени в конструктора на интерфейси, с активиран AutoLayout, ще имат свойството translatesAutoresizingMaskIntoConstraints, зададено на NO

Второто правило изглежда не се прилага за изгледи от най-високо ниво, за които не дефинирате ограничения. (Напр. изглед на съдържание)

Когато разглеждате клетка на Storyboard, забележете, че клетката не показва своето contentView. Ние не „контролираме“ contentView, Apple го прави.

Гмурнете се задълбочено в изходния код на сценария и вижте как се дефинира contentView клетка:

<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">

Сега подизгледите на клетката (забележете translatesAutoresizingMaskIntoConstraints="NO"):

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NaT-qJ-npL" userLabel="myCustomLabel">

contentView не е translatesAutoresizingMaskIntoConstraints настроен на NO. Освен това му липсва дефиниция на оформлението, може би поради това, което @ecotax каза.

Ако разгледаме contentView, той наистина има маска за автоматично преоразмеряване, но няма дефиниция за нея: <autoresizingMask key="autoresizingMask"/>

Така че изводите са два:

  1. contentView translatesAutoresizingMaskIntoConstraints е зададено на YES.
  2. contentView липсва определение за оформление.

Това ни води до две решения, за които се говори.

Можете да зададете маските за автоматично преоразмеряване ръчно в awakeFromNib:

self.contentView.frame = cell.bounds;
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Или можете да зададете contentView translatesAutoresizingMaskIntoConstraints на NO в awakeFromNib и да дефинирате ограничения в - (void)updateConstraints.

person kgaidis    schedule 19.06.2015

Това е Swift версията на отговора на @Igor, който е приет и благодаря за хубавия отговор, колега.

Първо Отидете до вашия UICollectionViewCell подклас и поставете следния код, както е вътре в класа.

override func awakeFromNib() {
    super.awakeFromNib()
    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
}

Между другото, използвам Xcode 7.3.1 и Swift 2.3. Решението е тествано на iOS 9.3, който работи безупречно.

Благодаря, надявам се, че това помогна.

person onCompletion    schedule 15.06.2016
comment
съжалявам за лошия ми английски, имах предвид, че работи като чар :) - person Aznix; 23.08.2016
comment
@Aznix Няма проблем.. :) - person onCompletion; 23.08.2016

В swift поставете следния код в подкласа на клетката за изглед на колекция:

override var bounds: CGRect {
  didSet {
    // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1
    self.contentView.frame = bounds
  }
}
person Ian    schedule 28.11.2014
comment
Това беше отговорът, който търсех. Преди заменях setBounds в Objective-C, за да коригирам този проблем (не бях сигурен как да го напиша в Swift). Благодаря ти :) - person Matthew Cawley; 19.10.2016

Открих, че също има проблеми с contentView оразмеряването в iOS 8. Има тенденция да се излага много късно в цикъла, което може да причини временни конфликти на ограничения. За да разреша това, добавих следния метод в категория UICollectionViewCell:

- (void)fixupContentView
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 80100
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
        self.contentView.frame = self.bounds;
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    } else {
        [self layoutIfNeeded];
    }
#endif
#endif
}

Този метод трябва да се извика след изваждане на клетката от опашката.

person phatmann    schedule 03.10.2014
comment
Би било идеално, ако този метод се извиква автоматично. Не ми харесва, но това може да стане чрез въртене на dequeueReusableCellWithReuseIdentifier:forIndexPath:. - person phatmann; 04.10.2014
comment
Apple изглежда е коригирала този проблем във версия 8.1 на iOS SDK в Xcode 6.1 GM (компилация 6A1042b). Затова актуализирах кода по-горе, за да не се изпълнява при използване на 8.1 SDK. След като целият ви екип премине към Xcode 6.1, можете напълно да премахнете този хак. - person phatmann; 07.10.2014

Поправих това:

override func layoutSubviews() {
   contentView.superview?.frame = bounds
   super.layoutSubviews()
}

вижте: тук

person Serluca    schedule 03.06.2016

Просто се уверете, че сте поставили отметка в квадратчето „Автоматично преоразмеряване на подизгледи“ в перото за тази клетка за изглед на колекция. Ще работи добре както на iOS 8, така и на iOS 7.

person Deepak G M    schedule 20.01.2015
comment
Не, не става. Това е вграден прототип на клетка. - person thkeen; 21.01.2015