iOS Ӥ self-sizing cell ጱ螂牏 匍牏膏๚㬵 ฏਡ(Jeff Lin)
iOS self-sizing cell
(Jeff Lin)
• Yahoo AppDevKit - - (Anistar)
• https://github.com/yahoo/AppDevKit
• – iOS BDD - (qcl)
• https://github.com/qcl/zizhi
About me• YAHOO App Engineer
• iOS App
• AppDevKit
Agenda
• Self-sizing
• Self-sizing
• Xcode 8
Self-sizing
/
/
Expandable cell
• iOS dynamic type
• UIFont.preferredFontForTextStyle:
•
• UIImageView, UILabel, UITextView…
• Container
• UITableView, UICollectionView
•
• storyboard, xib, constraint
Layout
Self-sizing ?
!• auto self-sizing
• NSString
• sizeWithAttributes
• boundingRectWithSize:options:attributes:context:
• UILabel
• sizeToFit:
• UIScrollView/UITextView
• contentSize
• size ceil()
• sizeToFit: frameconstraint
UITextView contentSize
• sizeForItemAtIndexPath:
• textView.ContentSize
iOS ?
UITableview self sizing
• UILabel numberOfLines = 0
• AutoLayout
self.tableView?.rowHeight = UITableViewAutomaticDimension self.tableView?.estimatedRowHeight = 100
That’s all!
UITableview self sizing
•
• layout
UICollectionView
• Grid view,
• /layout
•
UICollectionView self-sizing
AppDevKit• UICollectionViewCell
• subclass ADKTableViewDynamicSizeCell/ADKCollectionViewDynamicSizeCell
• constraint
• collectionView:layout:sizeForItemAtIndexPath:
• ADKNibCacheManager cell
• cell
AppDevKit Solution
AppDevKit Solution
collectionView:layout:sizeForItemAtIndexPath:
1. cell
let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String? let cell = ADKSWNibCacheManager.sharedInstance().instance( className: appName?.appending(".\(SSSmallCardCollectionViewCell.self)")) as! SSSmallCardCollectionViewCell
AppDevKit Solution
2.
let preferSize = CGSize.init(width: collectionView.frame.size.width / 2.0 - 10, height: 100.0) cell.frame = CGRect.init(origin: .zero, size: preferSize)
3. layoutIfNeeded constraint
cell.contentView.layoutIfNeeded()
AppDevKit Solution
4.
func setup(cell: SSSmallCardCollectionViewCell, indexPath: IndexPath) { let productInfo = self.products[indexPath.row] cell.contentView.layoutIfNeeded() cell.titleLabel?.text = productInfo.productTitle ... }
AppDevKit Solution
5.
let size = ADKCellDynamicSizeCalculator.sharedInstance().size(forDynamicHeightCellInstance: cell, preferredSize: preferSize)
return size
Sample Code@objc(collectionView:layout:sizeForItemAtIndexPath:) func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 1. cell let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String? let cell = ADKSWNibCacheManager.sharedInstance().instance(className: appName?.appending(".\(SSSmallCardCollectionViewCell.self)")) as! SSSmallCardCollectionViewCell
// 2. let preferSize = CGSize.init(width: collectionView.frame.size.width / 2.0 - 10, height: 100.0) cell.frame = CGRect.init(origin: .zero, size: preferSize)
// 3. layoutIfNeeded constraint cell.contentView.layoutIfNeeded()
// 4. setup(cell: cell, indexPath: indexPath)
// 5. let size = ADKCellDynamicSizeCalculator.sharedInstance().size(forDynamicHeightCellInstance: cell, preferredSize: CGSize.init(width: collectionView.frame.size.width / 2.0 - 10, height: 0.0)) return size }
Recap1. cell
2.
3. layoutIfNeededconstraint
4.
5.
ImageView
Title
Description
Price
Recap1. cell
2.
3. layoutIfNeededconstraint
4.
5.
ImageView
Title
Description
Price
Recap1. cell
2.
3. layoutIfNeededconstraint
4.
5.
ImageView
Title
Description
Price
Recap1. cell
2.
3. layoutIfNeededconstraint
4.
5.
ImageView
Title
Description
Price
ImageView
SO NICE
$ 790
ImageView
SO NICE
790
Recap1. cell
2.
3. layoutIfNeededconstraint
4.
5.
ImageView
SO NICE
$ 790
SO NICE
,
,
$ 790
AppDevKit Solution
ADKCellDynamicSizeCalculator.sharedInstance().size(forDynamicHeightCellInstance: cell, preferredSize: CGSize.init(width: collectionView.frame.size.width / 2.0 - 10, height: 0.0))
10px
How AppDevKit works?•CGSize resultSize = [contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; resultSize.width = preferredSize.width; resultSize.height = MAX(resultSize.height, preferredSize.height);
systemLayoutSizeFittingSize
• UILayoutFittingCompressedSize
• view constraints size
• UILayoutFittingExpandedSize
• view constraints size
layoutIfNeeds
• layoutIfNeeds
• reloadData contentSize
• Animate autoLayout
contentSize
// contentSize: {0, 0}collectionView.dataSource = self.delegator// contentSize: {0, 0}collectionView.reloadData()// contentSize: {0, 0}collectionView.layoutIfNeeded// contentSize: {375, 2557.5}
layoutIfNeeds-Animation
viewForAnimate.someConstraint.constanst = 0.0 UIView.animate(withDuration: 0.3) {
viewForAnimate.layoutIfNeeded() }
UIView.animate(withDuration: 0.3) { viewForAnimate.frame = CGRect.init(origin: .zero, size: CGSize.init(width: 100, height: 100))
}
Frame base layout
Constraint Autolayout
iOS ?
cell
• collectionView:layout:sizeForItemAtIndexPath:
• Customized UICollectionViewLayout
estimatedItemSize
estimatedItemSize• iOS 8 above
• UICollectionViewFlowLayout
• estimatedItemSize
• UICollectionViewCell
• preferredLayoutAttributesFittingAttributes
estimatedItemSize
• UITableView estimatedRowHeight
• UICollectionViewFlowLayoutflowLayout.estimatedItemSize = CGSize.init(width: UIScreen.main.bounds.size.width / 2 - 20, height: 100)
Sample Codefunc preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { self.contentView.layoutIfNeeded() layoutAttributes.frame.size.height = systemLayoutSizeFitting(UILayoutFittingCompressedSize).height layoutAttributes.frame.size.width = self.bounds.size.width
return layoutAttributes }
• class reference super.preferredLayoutAttributesFitting(layoutAttributes)
• newLayoutAttributes size 1000x1000
• iOS 10self.contentView.layoutIfNeeded()
• estimatedItemSize cellpreferredLayoutAttributesFitting
• estimatedItemSize sizeForItemAtIndexPath
preferredLayoutAttributesFittingAttributes
preferredLayoutAttributesFittingAttributes
•
•
• + ...
•constraint
• willDisplayCell
• ADKSetConstraintConstant:forAttribute: can help!
• cellestimatedItemSize
flowLayout
•collectionView:layout:sizeForItemAtIndexPath:
Expandable cell
•
• estimatedItemSize+invalidLayout+UIViewAnimation
• sizeForCellAtIndexPath+performBatchUpdate:
• TableView
• estimatedRowHeight
• CollectionView
• cell estimatedItemSize
• sizeForItemAtIndexPath
• Custom flowLayout
• AppDevKit might help for nib!
Xcode 8 & iOS 10
self-sizing in iOS 10
• WWDC 216 What's New in UICollectionView in iOS 10
•
flowLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
xib in Xcode 8
xib in Xcode 8
• xib constraint frame
• init frame
• Update:Xcode 8.1
Frame size1000!
xib in Xcode 8
NSLayoutConstraint(item: star, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0.0, constant: self.frame.height).isActive = true;
” ”
1000x1000 star!
Solution
• or 0NSLayoutConstraint(item: star, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1.0, constant: 0.0).isActive = true;
xibXcode 7
Xcode 8
constraint...
• auto layout constraint
• contentView
layoutIfNeeded
• preferredMaxLayoutWidth
• xib
• size constraint
• constraint self.frame.size
constraint ...
Self-sizing checklist
• estimatedItemSize
• cellpreferredLayoutAttributesFittingAttributes
• self-sizing constraint
Self-sizing checklist• sizeForItemAtIndexPath:
• cache cell
• constraint frame
• self-sizing constraint
• ADKNibSizeCalculator & ADKCellDynamicSizeCalculator can help!
…
• self-sizing constraint
• ( )
• preferredMaxLayoutWidth
Thank you!