Reputation: 5332
OK. There's a number of questions that touch on this, but none that actually address what I need.
What I need, quite simply, is to get the value that I set in IB for the "custom row height" of a DYNAMIC (not static) table cell prototype.
If the table sets up static prototypes, then this is automatically honored. However, when using dynamic prototypes, this value is ignored in favor of the table's main rowHeight value.
I'd like to be able to access this value, so I can return it in the tableView(_:heightForRowAt:)
method. I can do this manually, by having an internal table of heights, and matching to the prototype, but that's messy and awkward, and requires that the prototype always appear in a certain row.
When tableView(_:heightForRowAt:)
is called, I can synthesize the reuseID, but I'd like to avoid having to load the viewcell until the proper time (tableView(_:cellForRowAt:)
).
Is there a good way to access this? I don't see any literature in the Apple docs about accessing prototypes.
Upvotes: 1
Views: 77
Reputation: 36
Edit: Ok, I see what is your problem. In iOS development, we deal with tasks like this with different subclasses of UITableCell. Like this:
+ (CGFloat)layoutHeightWithEntity:(id)entity {
CGFloat layoutHeight = 0;
// use data to calculate layout height dynamically if needed
// id data = [entity data];
// layoutHeight = layoutHeight + [data ...];
// or use a static layout height if the height of this kind of cells do not change
layoutHeight = 100;
return layoutHeight;
}
And in your view controller, you need to prepare data source for your table view like this:
NSMutableArray *dataList = [NSMutableArray new];
NSMutableArray *firstSection = [NSMutableArray new];
[firstSection addObject:[XXXTableEntity entityWithReuseCellID:@"nameCell" data:someData cellClass:[XXXNameCell class]];
[dataList addObject:firstSection];
NSMutableArray *secondSection = [NSMutableArray new];
[firstSection addObject:[XXXTableEntity entityWithReuseCellID:@"pickerCell" data:someData cellClass:[XXXPickerCell class]];
[dataList addObject:secondSection];
[self setDataList:dataList];
your CustomTableEntity
may look like this:
+ (instancetype)entityWithEntityID:(NSString *)entityID
cellReUseID:(NSString *)cellReUseID
cellClass:(Class<XXXBaseTableCellLayout>)cellClass
dataEntity:(id)dataEntity
precalculateHeight:(BOOL)precalculateHeight {
XXXBaseTableCellEntity *entity = [self new];
[entity setEntityID:entityID];
[entity setReuseCellID:cellReUseID];
[entity setDataEntity:dataEntity];
[entity setCellClass:cellClass];
if (precalculateHeight) {
[entity setLayoutHeight:[cellClass layoutHeightWithEntity:dataEntity]];
}
return entity;
}
- (CGFloat)layoutHeight {
if (_layoutHeight > 0) {
return _layoutHeight;
}
_layoutHeight = [[self cellClass] layoutHeightWithEntity:[self dataEntity]];
return _layoutHeight;
}
then in your UITableViewDataSource methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.dataList.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.dataList[section] count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[[[self dataList] objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]] layoutHeight];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
XXXTableEntity *entity = [[[self dataList] objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
XXXBaseTableCell *cell = [tableView dequeueReusableCellWithIdentifier:[entity reuseCellID] forIndexPath:indexPath];
[cell configureWithEntity:entity];
return cell;
}
the code above are basically from a framework I write for my company, but you should get the idea. The framework has 3 classes related to table view: XXXBaseTableCell
, XXXBaseTableViewController
, XXXBaseTableCellEntity
. All view controllers contains a table view subclass XXXBaseTableViewController
, all table cells subclass XXXBaseTableCell
, all table entities subclass XXXBaseTableCellEntity
.
May I ask you why you want to do this? I think you are having some problems with table view. If you can explain why you want to do it, maybe I can help you so that you don't need to do it at all.
You cannot access the height of prototype cells in the standard approach. But actually you can access any data in a storyboard file if you really want to do it. Below is how:
Storyboard is a XML file. Everything you do when you are editing a storyboard file in IB are encoded in a XML file. You can access any information you need by parsing XML file yourself. You can read the XML data in a storyboard file and feed it to a XML parser to get the DOM data. Then you can query the DOM to get data. Here is the XML view of a test storyboard which contains a table view controller:
<!--Table View Controller-->
<scene sceneID="hbL-mT-mfb">
<objects>
<tableViewController id="XNl-aA-YKn" customClass="TableViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="lX1-Ry-xNl">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="100" id="4rn-ee-JoI">
<rect key="frame" x="0.0" y="28" width="375" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4rn-ee-JoI" id="bdN-kI-rps">
<rect key="frame" x="0.0" y="0.0" width="375" height="99"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="XNl-aA-YKn" id="GlZ-SO-7gG"/>
<outlet property="delegate" destination="XNl-aA-YKn" id="gqq-QI-tZD"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="RCX-w1-742" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="118" y="798"/>
</scene>
Please don't do it this way...
Upvotes: 2