问题
I'm trying to make a detail screen for a to-do list kind of app. Here's what the detail screen currently looks like:
This is a UICollectionViewController
, with a header. The header contains 2 UILabel
objects, and a UITextView
object. The layout of these objects is managed by a vertical UIStackView
. A UIView
is used to set a white background.
I'm having some difficulties in defining the height of this UICollectionReusableView
at runtime. Any advice is appreciated.
回答1:
This is a bit of a hack, but seems to work.
// showhere to keep a reference
UICollectionReusableView * _cachedHeaderView;
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath{
if(!_cachedHeaderView){
// dequeue the cell from storyboard
_cachedHeaderView =
[collectionView dequeueReusableCellWithReuseIdentifier:@"header_cell"
forIndexPath:indexPath];
// set captions/images on the header etc...
// tell the collectionview to redraw this section
[self.collectionView reloadSections:[NSIndexSet
indexSetWithIndex:indexPath.section]];
}
return _cachedHeaderView;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
referenceSizeForHeaderInSection:(NSInteger)section{
// once there is a reference ot the view, use it to figure out the height
if(_cachedHeaderView){
CGSize size =
[_cachedHeaderView systemLayoutSizeFittingSize:collectionView.bounds.size
withHorizontalFittingPriority:UILayoutPriorityRequired
verticalFittingPriority:UILayoutPriorityDefaultLow];
return size;
}
// a placeholder value just to get the dequeueReusableCellWithReuseIdentifier to work
return CGSizeMake(collectionView.bounds.size.width, 100);
}
回答2:
Here is how you can handle custom UICollectionViewReusableView with auto layout without the XIB file.
- Implement the
referenceSizeForHeaderInSection
delegate method. - In it, instantiate the view that you use as a header view.
- Set its visibility to hidden, to avoid flashing.
- Add the view to the collectionview's superview.
- Set it's layout using auto layout, to match the expected visual outcome of the header.
- Invoke
setNeedsLayout
andlayoutIfNeeded
- Remove the view from the superview
CAUTION: I am not a big fan of this solution, as it adds the custom view to the collectionview's superview each time, to perform calculations. I didn't notice any performance issues though.
CAUTION #2: I'd treat it as a temporary solution, and migrate to self sizing supplementary views once they get published.
I am using PureLayout for autolayout purposes.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
let header = CustomHeaderView()
header.isHidden = true;
self.view.addSubview(header)
header.autoPinEdge(toSuperviewEdge: .leading)
header.autoPinEdge(toSuperviewEdge: .trailing)
header.autoPin(toTopLayoutGuideOf: self, withInset: 0)
header.setupHeader(withData: self.data)
header.setNeedsLayout()
header.layoutIfNeeded()
header.removeFromSuperview()
return header.frame.size
}
来源:https://stackoverflow.com/questions/39201748/auto-sizing-uicollectionview-headers