IT

iOS 7에서만 실행할 때 Storyboard 프로토 타입 셀 (Xcode 6, iOS 8 SDK)의 UICollectionViewCell contentView 프레임 자동 크기 조정 문제가 발생합니다.

lottoking 2020. 6. 4. 08:08
반응형

iOS 7에서만 실행할 때 Storyboard 프로토 타입 셀 (Xcode 6, iOS 8 SDK)의 UICollectionViewCell contentView 프레임 자동 크기 조정 문제가 발생합니다.


Xcode 6 Beta 3, iOS 8 SDK를 사용하고 있습니다. Swift를 사용하여 대상 iOS 7.0을 빌드하십시오. 아래 스크린 샷과 함께 내 문제를 단계별로 참조하십시오.

스토리 보드에 UICollectionView가 있습니다. 1 중앙에 1 개의 레이블이있는 프로토 타입 UICollectionViewCell (자동 크기 조정 규칙 없음). 자주색 배경은 추측하는 셀에 의해 런타임에 생성되는 contentView를 표시하는 것이 었습니다. 이 뷰의 크기는 결국 UICollectionViewLayoutDelegate에 따라 적절하게 조정되지만 iOS 7에서는 그렇지 않습니다. Xcode 6을 사용하고 있으며 문제는 iOS 7에서만 발생합니다.

iOS 8에서 앱을 빌드하면 모든 것이 정상입니다.

참고 : 자주색은 contentView 이며 파란색은 모서리가 둥근 내 UIButton입니다.

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

그러나 iOS 7에서는 Cell 내부의 모든 subView가 갑자기 (0,0,50,50) 프레임으로 축소되어 더 이상 내 자동 크기 조정 규칙을 준수하지 않습니다.

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

iOS 8 SDK 또는 Swift 또는 Xcode의 버그라고 생각합니까?


업데이트 1 : 이 문제는 여전히 공식 Xcode 6.0.1에 존재합니다! 가장 좋은 해결 방법은 셀의 cellForItem에 프레임을 설정하여 KoCMoHaBTa가 아래에 제안한 것과 같습니다 (셀을 서브 클래스 화해야 함). 이것은 iOS 8 SDK와 iOS 7 사이에 호환되지 않는 것으로 판명되었습니다 (아래 Apple에서 인용 한 ecotax의 답변을 확인하십시오).

업데이트 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 **/

contentView가 손상되었습니다. awakeFromNib에서 수정 될 수도 있습니다.

ObjC :

- (void)awakeFromNib {

    [super awakeFromNib];

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

스위프트 3 :

override func awakeFromNib() {
    super.awakeFromNib()

    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

같은 문제가 발생하여 Apple DTS에 도움을 요청했습니다. 그들의 대답은 다음과 같습니다.

In iOS 7, cells’ content views sized themselves via autoresizing masks. In iOS 8, this was changed, cells stopped using the autoresizing masks and started sizing the content view in layoutSubviews. If a nib is encoded in iOS 8 and then decode it on iOS 7, you’ll have a content view without an autoresizing mask and no other means by which to size itself. So if you ever change the frame of the cell, the content view won’t follow.

Apps being deploying back to iOS 7 will have to work around this by sizing the content view itself, adding autoresizing masks, or adding constraints.

I guess this means that it's not a bug in XCode 6, but an incompatibility between the iOS 8 SDK and iOS 7 SDK, which will hit you if you upgrade to Xcode 6, because it will automatically start using the iOS 8 SDK.

As I commented before, the workaround Daniel Plamann described works for me. The ones described by Igor Palaguta and KoCMoHaBTa look simpler though, and appear to make sense giving Apple DTS' answer, so I'll try those later.


I encountered the same issue and hope that Apple will fix this with the next Xcode version. Meanwhile I use a workaround. In my UICollectionViewCell subclass I've just overridden layoutSubviews and resize the contentView manually in case the size differs from collectionViewCell size.

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

Another solution is to set the contentView's size and autoresizing masks in -collectionView:cellForItemAtIndexPath: like the following:

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

This works with Auto Layout too, since auto resizing masks are translated to constraints.


In Xcode 6.0.1 contentView for UICollectionViewCell is broken for iOS7 devices. It can be also fixed by adding proper constraints to UICollectionViewCell and its contentView in awakeFromNib or init methods.

        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)]];


This will not work correctly without any of the other mentioned workarounds because of a bug in Xcode 6 GM with how Xcode compiles xib files into the nib format. While I cannot say for 100% certainty it is Xcode related and not having to do with runtime, I'm very confident - here's how I can show it:

  1. Build+Run the application in Xcode 5.1.
  2. Go to the simulator application's directory and copy the compiled .nib file for the xib you are having issues with.
  3. Build+Run the application in Xcode 6 GM.
  4. Stop the application.
  5. Replace the .nib file in the newly built application's simulator folder with the .nib file created using Xcode 5.1
  6. Relaunch the app from the simulator, NOT from Xcode.
  7. Your cell loaded from that .nib should work as expected.

I hope everyone who reads this question will file a Radar with Apple. This is a HUGE issue and needs addressing before the final Xcode release.

Edit: In light of ecotax's post, I just wanted to update this to say it is now confirmed behavior differences between building in iOS 8 vs iOS 7, but not a bug. My hack fixed the issue because building on iOS 7 added the autoresizing mask to the content view needed to make this work, which Apple no longer adds.


The answers in this post work, what I never understood is why it works.

First, there are two "rules":

  1. For views created programmatically (Ex. [UIView new]), the property translatesAutoresizingMaskIntoConstraints is set to YES
  2. Views created in interface builder, with AutoLayout enabled, will have the property translatesAutoresizingMaskIntoConstraints set to NO

The second rule does not seem to apply to top-level views for which you do not define constraints for. (Ex. the content view)

When looking at a Storyboard cell, notice that the cell does not have its contentView exposed. We are not "controlling" the contentView, Apple is.

Deep dive into storyboard source code and see how contentView cell is defined:

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

Now the cell's subviews (notice the translatesAutoresizingMaskIntoConstraints="NO"):

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

The contentView does not have it's translatesAutoresizingMaskIntoConstraints set to NO. Plus it lacks layout definition, maybe because of what @ecotax said.

If we look into the contentView, it does have an autoresizing mask, but no definition for it: <autoresizingMask key="autoresizingMask"/>

So there are two conclusions:

  1. contentView translatesAutoresizingMaskIntoConstraints is set to YES.
  2. contentView lacks definition of a layout.

This leads us to two solutions which have been talked about.

You can set the autoresizing masks manually in awakeFromNib:

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

Or you can set the contentView translatesAutoresizingMaskIntoConstraints to NO in awakeFromNib and define constraints in - (void)updateConstraints.


This is the Swift version of @Igor's answer which is accepted and thanks for your nice answer mate.

First Goto your UICollectionViewCell Subclass and paste the following code as it is inside the class.

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

By the way I am using Xcode 7.3.1 and Swift 2.3. Solution is tested on iOS 9.3 which is working flawlessly.

Thanks, Hope this helped.


In swift, place the following code in the collection view cell subclass:

override var bounds: CGRect {
  didSet {
    // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1
    self.contentView.frame = bounds
  }
}

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

이 메소드는 셀을 대기열에서 제거한 후에 호출해야합니다.


나는 이것을하고 고정했다 :

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

참조 : 여기


해당 콜렉션 뷰 셀의 펜촉에서 "하위 뷰 자동 크기 조정"확인란을 선택하십시오. iOS 8과 iOS 7 모두에서 잘 작동합니다.

참고 URL : https://stackoverflow.com/questions/24750158/autoresizing-issue-of-uicollectionviewcell-contentviews-frame-in-storyboard-pro

반응형