UICollectionViewCell 내부의 UICollectionView -- 동적 높이?
애플리케이션 화면 중 하나에서 다음과 같은 작업을 수행해야 합니다.UICollectionView
의 에.UITableViewCell
. 것이.UICollectionView
항목 수가 동적이므로 높이도 동적으로 계산해야 합니다.그러나 내장된 높이를 계산하는 중에 문제가 발생했습니다.UICollectionView
.
의 가장 중요한 것은 우리의것한요입니다.UIViewController
스토리보드에서 생성되었으며 자동 레이아웃을 사용합니다.하지만, 어떻게 하면 동적으로 높이를 높일 수 있을지 모르겠습니다.UITableViewCell
의높에근여하의 으로 하여UICollectionView
.
이것을 성취하는 방법에 대한 조언이나 조언을 해줄 수 있는 사람이 있습니까?
정답은 '예'입니다. 이렇게 할 수 있습니다.
저는 몇 주 전에 이 문제를 접했습니다.그것은 실제로 여러분이 생각하는 것보다 쉽습니다.NIB(또는 스토리보드)에 셀을 넣고 핀으로 고정하여 자동 레이아웃이 모든 작업을 수행할 수 있도록 합니다.
다음과 같은 구조가 주어질 경우:
테이블 보기
표 보기 셀
컬렉션 뷰
컬렉션 보기 셀
컬렉션 보기 셀
컬렉션 보기 셀
[...셀 수 제한 또는 셀 크기 변경]
솔루션은 자동 레이아웃을 지정하여 먼저 collectionViewCell 크기를 계산한 다음 collectionviewcontentSize를 계산하고 셀 크기로 사용하는 것입니다.다음은 "매직을 수행하는" UIView 방법입니다.
-(void)systemLayoutSizeFittingSize:(CGSize)targetSize
withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority
verticalFittingPriority:(UILayoutPriority)verticalFittingPriority
여기서 TableViewCell의 크기를 설정해야 하며, 이 경우 CollectionView의 contentSize가 됩니다.
컬렉션 보기 셀
CollectionViewCell에서는 모델을 변경할 때마다 셀에 레이아웃을 지정해야 합니다(예: 텍스트로 UI 레이블을 설정한 다음 셀을 다시 레이아웃해야 함).
- (void)bindWithModel:(id)model {
// Do whatever you may need to bind with your data and
// tell the collection view cell's contentView to resize
[self.contentView setNeedsLayout];
}
// Other stuff here...
표 보기 셀
TableView Cell이 마법을 부립니다.CollectionView에 대한 배출구가 있으며, UICollectionViewFlowLayout의 추정 ItemSize를 사용하여 CollectionView 셀에 대한 자동 레이아웃을 활성화합니다.
그런 다음 시스템 레이아웃 크기 적합 크기에서 테이블 보기 셀의 크기를 설정합니다.방법.(참고: iOS8 이상)
참고: 표의 대리 셀 높이 방법을 사용하려고 했습니다. 보기-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
.그러나 자동 레이아웃 시스템이 CollectionView contentSize를 계산하기에는 너무 늦었고 때때로 잘못된 크기의 셀을 찾을 수 있습니다.
@implementation TableCell
- (void)awakeFromNib {
[super awakeFromNib];
UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
// Configure the collectionView
flow.minimumInteritemSpacing = ...;
// This enables the magic of auto layout.
// Setting estimatedItemSize different to CGSizeZero
// on flow Layout enables auto layout for collectionView cells.
// https://developer.apple.com/videos/play/wwdc2014-226/
flow.estimatedItemSize = CGSizeMake(1, 1);
// Disable the scroll on your collection view
// to avoid running into multiple scroll issues.
[self.collectionView setScrollEnabled:NO];
}
- (void)bindWithModel:(id)model {
// Do your stuff here to configure the tableViewCell
// Tell the cell to redraw its contentView
[self.contentView layoutIfNeeded];
}
// THIS IS THE MOST IMPORTANT METHOD
//
// This method tells the auto layout
// You cannot calculate the collectionView content size in any other place,
// because you run into race condition issues.
// NOTE: Works for iOS 8 or later
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {
// With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width)
self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT);
[self.collectionView layoutIfNeeded];
// If the cell's size has to be exactly the content
// Size of the collection View, just return the
// collectionViewLayout's collectionViewContentSize.
return [self.collectionView.collectionViewLayout collectionViewContentSize];
}
// Other stuff here...
@end
테이블 뷰 컨트롤러
TableViewController에서 테이블View 셀에 대해 자동 레이아웃 시스템을 활성화해야 합니다.
- (void)viewDidLoad {
[super viewDidLoad];
// Enable automatic row auto layout calculations
self.tableView.rowHeight = UITableViewAutomaticDimension;
// Set the estimatedRowHeight to a non-0 value to enable auto layout.
self.tableView.estimatedRowHeight = 10;
}
크레딧: @rbarbera는 이것을 해결하는 데 도움을 주었습니다.
제 솔루션은 @PabloRomeu가 제안한 솔루션보다 훨씬 단순하다고 생각합니다.
1.1⁄3에서 . 콘센트 만들기UICollectionView
UITableViewCell subclass
서, 디에어UICollectionView
let let, let, 이름은그것.collectionView
에 2⁄4 합니다. 다음을 위해 IB 추가UICollectionView
높이 제약 조건 및 배출구 생성UITableViewCell subclass
, 이름은 . Let, 그것의 이름은.collectionViewHeight
.
. 인tableView:cellForRowAtIndexPath:
코드 추가:
// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;
테블뷰컬뷰모입니다.UIScrollView
하위 클래스는 콘텐츠 크기 계산, 셀 재사용 등을 시도할 때 다른 스크롤 보기에 포함되는 것을 좋아하지 않습니다.
모든 목적을 위해 컬렉션 보기만 사용하는 것이 좋습니다.
섹션으로 분할하고 일부 섹션의 레이아웃을 표 보기로 "처리"하고 다른 섹션은 집합 보기로 "처리"할 수 있습니다.결국 표 보기로 얻을 수 있는 컬렉션 보기로는 얻을 수 없는 것이 없습니다.
집합 뷰 "부품"에 대한 기본 그리드 레이아웃이 있는 경우 일반 테이블 셀을 사용하여 부품을 처리할 수도 있습니다.그래도 iOS 5 지원이 필요하지 않다면 컬렉션 뷰를 사용하는 것이 좋습니다.
위의 파블로 로마누의 답변(https://stackoverflow.com/a/33364092/2704206) 은 제 문제에 큰 도움이 되었습니다.하지만 이 문제를 해결하기 위해서는 몇 가지 방법을 다르게 해야 했습니다.먼저, 전화할 필요가 없었습니다.layoutIfNeeded()
몇 번이나나는 단지 그것을 전화하기만 하면 되었습니다.collectionView
에 시대에systemLayoutSizeFitting
기능.
두 번째로, 테이블 뷰 셀의 컬렉션 뷰에 패딩을 주기 위해 자동 레이아웃 제약이 있었습니다.그래서 저는 다음에서 선행 및 후행 마진을 빼야 했습니다.targetSize.width
를 할 때collectionView.frame
의 폭또한 수익률에 상단 및 하단 마진을 추가해야 했습니다.CGSize
높이.
이러한 제약 상수를 얻기 위해, 저는 제약에 대한 배출구를 만들거나, 상수를 하드 코딩하거나, 식별자로 검색할 수 있는 선택권이 있었습니다.사용자 정의 테이블 보기 셀 클래스를 쉽게 재사용할 수 있도록 하기 위해 세 번째 옵션을 선택했습니다.결국, 이것이 제가 그것을 작동시키는 데 필요한 전부였습니다.
class CollectionTableViewCell: UITableViewCell {
// MARK: -
// MARK: Properties
@IBOutlet weak var collectionView: UICollectionView! {
didSet {
collectionViewLayout?.estimatedItemSize = CGSize(width: 1, height: 1)
selectionStyle = .none
}
}
var collectionViewLayout: UICollectionViewFlowLayout? {
return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
}
// MARK: -
// MARK: UIView functions
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
collectionView.layoutIfNeeded()
let topConstraintConstant = contentView.constraint(byIdentifier: "topAnchor")?.constant ?? 0
let bottomConstraintConstant = contentView.constraint(byIdentifier: "bottomAnchor")?.constant ?? 0
let trailingConstraintConstant = contentView.constraint(byIdentifier: "trailingAnchor")?.constant ?? 0
let leadingConstraintConstant = contentView.constraint(byIdentifier: "leadingAnchor")?.constant ?? 0
collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width - trailingConstraintConstant - leadingConstraintConstant, height: 1)
let size = collectionView.collectionViewLayout.collectionViewContentSize
let newSize = CGSize(width: size.width, height: size.height + topConstraintConstant + bottomConstraintConstant)
return newSize
}
}
식별자로 제약 조건을 검색하는 도우미 기능으로 다음 확장자를 추가합니다.
extension UIView {
func constraint(byIdentifier identifier: String) -> NSLayoutConstraint? {
return constraints.first(where: { $0.identifier == identifier })
}
}
참고: 스토리보드의 이러한 제약 조건 또는 제약 조건이 생성되는 위치에 식별자를 설정해야 합니다.상수가 0인 경우를 제외하고는 상관 없습니다.또한 파블로의 답변과 마찬가지로, 당신은 다음과 같은 것을 사용해야 합니다.UICollectionViewFlowLayout
컬렉션 보기의 레이아웃으로 사용할 수 있습니다.마지막으로, 링크를 연결해야 합니다.collectionView
나는 당신의 스토리보드에 게시합니다.
위의 사용자 지정 테이블 뷰 셀을 사용하여 이제 컬렉션 뷰가 필요한 다른 테이블 뷰 셀에서 하위 클래스로 분류하고 다음을 구현하도록 할 수 있습니다.UICollectionViewDelegateFlowLayout
그리고.UICollectionViewDataSource
다른 !이것이 다른 사람에게 도움이 되기를 바랍니다!
저는 모든 답을 다 읽었습니다.이것은 모든 경우에 도움이 되는 것 같습니다.
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
collectionView.layoutIfNeeded()
collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width , height: 1)
return collectionView.collectionViewLayout.collectionViewContentSize
}
저는 최근에 같은 문제에 직면했고 거의 모든 해결책을 답에서 시도했습니다.그들 중 일부는 작동했고 다른 일부는 @PabloRomeu 접근법에 대해 제가 주로 우려하지 않았던 것들은 (수집 보기 이외의) 셀에 다른 콘텐츠가 있으면 자동 레이아웃을 올바르게 하기 위해 그들의 높이와 제약 조건의 높이를 계산하고 결과를 반환해야 한다는 것입니다. 그리고 저는 제 코드에서 수동으로 계산하는 것을 좋아하지 않습니다.여기 제 코드에서 수동으로 계산하지 않고도 잘 작동한 솔루션이 있습니다.
에 시대에cellForRow:atIndexPath
합니다: 테블보기다작수업행합다니을음서에.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//do dequeue stuff
//initialize the the collection view data source with the data
cell.frame = CGRect.zero
cell.layoutIfNeeded()
return cell
}
여기서 발생하는 일은 수집 보기 높이가 계산된 후 테이블 보기 셀의 높이를 강제로 조정하는 것입니다.(데이터 소스에 collectionView 날짜를 제공한 후)
Pablo Romeu 솔루션의 대안은 테이블 뷰 셀에서 작업하는 대신 UICollectionView 자체를 사용자 지정하는 것입니다.
기본적인 문제는 기본적으로 집합 뷰에 내재된 크기가 없으므로 사용할 차원의 자동 레이아웃을 알려줄 수 없다는 것입니다.유용한 고유 크기를 반환하는 사용자 지정 하위 클래스를 만들어 이 문제를 해결할 수 있습니다.
UICollectionView의 하위 클래스를 만들고 다음 메서드를 재정의합니다.
override func intrinsicContentSize() -> CGSize {
self.layoutIfNeeded()
var size = super.contentSize
if size.width == 0 || size.height == 0 {
// return a default size
size = CGSize(width: 600, height:44)
}
return size
}
override func reloadData() {
super.reloadData()
self.layoutIfNeeded()
self.invalidateIntrinsicContentSize()
}
(또한 관련 메서드를 재정의해야 합니다. reloadSections, reloadItemsAt데이터를 다시 로드하는 것과 유사한 방법으로 IndexPaths()
calling layoutIfNeeded는 컬렉션 보기에서 컨텐츠 크기를 다시 계산하여 새 고유 크기로 사용할 수 있도록 합니다.
또한 테이블 뷰 컨트롤러에서 보기 크기 변경(예: 장치 회전)을 명시적으로 처리해야 합니다.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
제가 생각해낸 가장 쉬운 접근법은 위의 igor에 대한 크레딧입니다.
표 보기 셀 클래스에 이것을 삽입합니다.
override func layoutSubviews() {
self.collectionViewOutlet.constant = self.postPoll.collectionViewLayout.collectionViewContentSize.height
}
그리고 물론, 셀 클래스의 콘센트로 컬렉션 뷰 아웃렛을 변경합니다.
저는 컬렉션 뷰 클래스에 정적 메서드를 추가하여 포함할 콘텐츠를 기준으로 크기를 반환합니다.▁the▁in▁method에 있는 방법을 .heightForRowAtIndexPath
올바른 크기를 반환합니다.
또한 이러한 종류의 viewController를 포함할 때 이상한 동작이 발생할 수 있습니다.한 번 해봤는데 기억력에 문제가 있었어요 한 번도 안 풀렸어요
제 변종이 유용할 수도 있습니다. 지난 두 시간 동안 이 작업을 결정했습니다.100% 맞거나 최적인 척은 하지 않지만, 아직 실력이 많이 부족해서 전문가들의 의견을 듣고 싶습니다.감사해요.한 가지 중요한 점은 정적 테이블에 대해 작동한다는 것입니다. 이는 현재 작업에서 지정한 것입니다.따라서 사용하는 것은 tableView의 viewWillLayoutSubviews뿐입니다.그리고 조금 더.
private var iconsCellHeight: CGFloat = 500
func updateTable(table: UITableView, withDuration duration: NSTimeInterval) {
UIView.animateWithDuration(duration, animations: { () -> Void in
table.beginUpdates()
table.endUpdates()
})
}
override func viewWillLayoutSubviews() {
if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell {
let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height
if collectionViewContentHeight + 17 != iconsCellHeight {
iconsCellHeight = collectionViewContentHeight + 17
updateTable(tableView, withDuration: 0.2)
}
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch (indexPath.section, indexPath.row) {
case ...
case (1,0):
return iconsCellHeight
default:
return tableView.rowHeight
}
}
- CollectionView가 두 번째 섹션의 첫 번째 행에 있다는 것을 알고 있습니다.
- 줄의 높이가 내용물 높이보다 17% 더 커지도록 하라;
- 아이콘셀 높이는 프로그램이 시작될 때 임의의 숫자입니다(세로 그림 형식에서는 정확히 392여야 하지만 중요하지 않습니다).collectionView + 17의 내용이 이 숫자와 같지 않으면 값을 변경합니다.다음 번에는 이 상황에서 조건이 FALSE를 제공합니다.
- 결국 tableView를 업데이트합니다.내 경우에는 확장 행의 적절한 업데이트를 위해 두 개의 작업을 조합합니다.
- 그리고 물론, 높이에서 ForRowAt.IndexPath가 코드에 행 하나를 추가합니다.
저는 @Igor 포스트에서 아이디어를 얻고 제 프로젝트에 신속하게 시간을 투자합니다.
이것을 지나 당신의 몸에서.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//do dequeue stuff
cell.frame = tableView.bounds
cell.layoutIfNeeded()
cell.collectionView.reloadData()
cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height)
cell.layoutIfNeeded()
return cell
}
추가:셀을 로드할 때 UICollectionView가 잘린 경우
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//do dequeue stuff
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
return cell
}
Pablo의 솔루션은 저에게 잘 작동하지 않았습니다. 저는 이상한 시각적 효과(수집 보기가 올바르게 조정되지 않음)가 있었습니다.
것은 효있것은의던었서과높로가 (NSLayoutConstraint로) 를 collectionViewContentSize로입니다.layoutSubviews()
이것은 셀에 자동 레이아웃이 적용될 때 호출되는 방법입니다.
// Constraint on the collectionView height in the storyboard. Priority set to 999.
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
// Method called by autolayout to layout the subviews (including the collectionView).
// This is triggered with 'layoutIfNeeded()', or by the viewController
// (happens between 'viewWillLayoutSubviews()' and 'viewDidLayoutSubviews()'.
override func layoutSubviews() {
collectionViewHeightConstraint.constant = collectionView.contentSize.height
super.layoutSubviews()
}
// Call `layoutIfNeeded()` when you update your UI from the model to trigger 'layoutSubviews()'
private func updateUI() {
layoutIfNeeded()
}
func configure(data: [Strings]) {
names = data
contentView.layoutIfNeeded()
collectionviewNames.reloadData()
}
짧고 달콤합니다.class.tableViewCell은 위의 방법을 합니다.당신은 아마 그것을 에서 부를 것입니다.func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
당신의 감방을 해독한 후에.컬렉션 보기에서 reloadData를 호출하기 전에 tableCell에서 레이아웃 업데이트가 보류 중인 경우 컬렉션 보기에 하위 뷰를 레이아웃하도록 지시해야 합니다.
UITableView 딜러:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return ceil(itemCount/4.0f)*collectionViewCellHeight;
}
항목 개수 및 컬렉션 보기셀 높이를 실제 값으로 대체합니다.배열이 있는 경우 itemCount는 다음과 같습니다.
self.items[indexPath.row].count
아니면 뭐든.
셀을 .1. 더미 셀을 만듭니다.
2.데이터를 합니다.2. UICollectionView UICollectionViewLayout 컬렉션ViewContentSize 를 참조하십시오.
은 다과같속기성반컬로높수계있산다습니이할렉를의션으음과 같은 을 기준으로 할 수 .itemSize
,sectionInset
,minimumLineSpacing
,minimumInteritemSpacing
만약 당신이collectionViewCell
규칙 테두리가 있습니다.
언급URL : https://stackoverflow.com/questions/24126708/uicollectionview-inside-a-uitableviewcell-dynamic-height
'programing' 카테고리의 다른 글
Microsoft Excel 매크로에 포함된 연결 문자열 수정 (0) | 2023.06.10 |
---|---|
문자열 배열에 값이 포함되어 있는지 확인하고 포함되어 있으면 위치 가져오기 (0) | 2023.06.10 |
PL/SQL에서 CASE 문을 실행하는 동안 ORA-06592: CASE를 찾을 수 없는 이유는 무엇입니까? (0) | 2023.06.10 |
텍스트 파일의 URL이 주어지면 텍스트 파일의 내용을 읽는 가장 간단한 방법은 무엇입니까? (0) | 2023.06.10 |
파이어베이스에서 데이터를 구성하는 가장 좋은 방법은 무엇입니까? (0) | 2023.06.10 |