我使用UITableView来布局内容“页面”。我使用表视图的标题来布局某些图像等,我更喜欢它,如果他们没有浮动,但保持静态,因为他们做的时候,风格设置为UITableViewStyleGrouped。
除了使用UITableViewStyleGrouped,有办法做到这一点吗?我想避免使用分组,因为它增加了我所有的单元格的边缘,并要求为每个单元格禁用背景视图。我想完全控制我的布局。理想情况下,它们应该是“UITableViewStyleBareBones”,但我在文档中没有看到这个选项…
非常感谢,
实现这一点的一个可能更简单的方法:
objective - c:
CGFloat dummyViewHeight = 40;
UIView *dummyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, dummyViewHeight)];
self.tableView.tableHeaderView = dummyView;
self.tableView.contentInset = UIEdgeInsetsMake(-dummyViewHeight, 0, 0, 0);
迅速:
let dummyViewHeight = CGFloat(40)
self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
self.tableView.contentInset = UIEdgeInsets(top: -dummyViewHeight, left: 0, bottom: 0, right: 0)
分段标题现在将像任何常规单元格一样滚动。
UITableViewStyleGrouped的有趣之处在于tableView将样式添加到单元格中而不是添加到tableView中。
样式作为backgroundView添加到单元格中,作为一个名为UIGroupTableViewCellBackground的类,它根据单元格在section中的位置来处理绘制不同的背景。
所以一个非常简单的解决方案是使用UITableViewStyleGrouped,设置表格的backgroundColor为clearColor,并简单地替换cellForRow中单元格的backgroundView:
cell.backgroundView = [[[UIView alloc] initWithFrame:cell.bounds] autorelease];
这可以通过在UITableViewController的viewDidLoad方法中手动分配头视图来实现,而不是使用委托的viewForHeaderInSection和hightforheaderinsection。例如,在UITableViewController的子类中,你可以这样做:
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *headerView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 40)];
[headerView setBackgroundColor:[UIColor magentaColor]];
[headerView setTextAlignment:NSTextAlignmentCenter];
[headerView setText:@"Hello World"];
[[self tableView] setTableHeaderView:headerView];
}
当用户滚动时,头视图将消失。我不知道为什么这样工作,但它似乎达到了你想要做的。
好吧,我知道很晚了,但我必须这么做。
到目前为止,我已经花了10个小时寻找一个可行的解决方案,但没有找到一个完整的答案。我发现了一些提示,但初学者很难理解。因此,我不得不投入我的2美分,完成答案。
正如在少数的答案中所建议的,我能够实现的唯一工作解决方案是通过在表视图中插入正常的单元格,并将它们作为Section Headers处理,但更好的方法是通过在每个Section的第0行插入这些单元格。这样我们就可以很容易地处理这些自定义的非浮动标头。
步骤是。
Implement UITableView with style UITableViewStylePlain.
-(void) loadView
{
[super loadView];
UITableView *tblView =[[UITableView alloc] initWithFrame:CGRectMake(0, frame.origin.y, frame.size.width, frame.size.height-44-61-frame.origin.y) style:UITableViewStylePlain];
tblView.delegate=self;
tblView.dataSource=self;
tblView.tag=2;
tblView.backgroundColor=[UIColor clearColor];
tblView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
Implement titleForHeaderInSection as usual ( you can get this value by using your own logic, but I prefer to use standard delegates ).
- (NSString *)tableView: (UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *headerTitle = [sectionArray objectAtIndex:section];
return headerTitle;
}
Immplement numberOfSectionsInTableView as usual
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int sectionCount = [sectionArray count];
return sectionCount;
}
Implement numberOfRowsInSection as usual.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowCount = [[cellArray objectAtIndex:section] count];
return rowCount +1; //+1 for the extra row which we will fake for the Section Header
}
Return 0.0f in heightForHeaderInSection.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 0.0f;
}
DO NOT implement viewForHeaderInSection. Remove the method completely instead of returning nil.
In heightForRowAtIndexPath. Check if(indexpath.row == 0) and return the desired cell height for the section header, else return the height of the cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0)
{
return 80; //Height for the section header
}
else
{
return 70; //Height for the normal cell
}
}
Now in cellForRowAtIndexPath, check if(indexpath.row == 0) and implement the cell as you want the section header to be and set the selection style to none. ELSE implement the cell as you want the normal cell to be.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SectionCell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SectionCell"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone; //So that the section header does not appear selected
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SectionHeaderBackground"]];
}
cell.textLabel.text = [tableView.dataSource tableView:tableView titleForHeaderInSection:indexPath.section];
return cell;
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray; //So that the normal cell looks selected
cell.backgroundView =[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellBackground"]]autorelease];
cell.selectedBackgroundView=[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SelectedCellBackground"]] autorelease];
}
cell.textLabel.text = [[cellArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row -1]; //row -1 to compensate for the extra header row
return cell;
}
}
Now implement willSelectRowAtIndexPath and return nil if indexpath.row == 0. This will care that didSelectRowAtIndexPath never gets fired for the Section header row.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
return nil;
}
return indexPath;
}
And finally in didSelectRowAtIndexPath, check if(indexpath.row != 0) and proceed.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != 0)
{
int row = indexPath.row -1; //Now use 'row' in place of indexPath.row
//Do what ever you want the selection to perform
}
}
这样你就完成了。现在,您拥有了一个完美的滚动的、非浮动的节头。
While thinking how to approach this problem, I remembered a very important detail about UITableViewStyleGrouped.
The way UITableView implements the grouped style (the rounded borders around the cells) is by adding a custom backgroundView to the UITableViewCells, and not to the UITableView. Each cell is added a backgroundView according to its position in the section (upper rows get the upper part of the section border, middle ones get the side border and the bottom one gets – well, the bottom part).
So, if we just want a plain style, and we don’t have a custom backgroundView for our cells (which is the case in 90% of the times), then all we need to do is use UITableViewStyleGrouped, and remove the custom background. This can be done by following those two steps:
将我们的tableView样式改为UITableViewStyleGrouped
在cellForRow返回单元格之前,添加以下一行:
细胞。开源视图=[[UIView alloc]这是一个细胞:跳跃]autorelease];
就是这样。tableView样式将变得完全像UITableViewStylePlain,除了浮动头。
希望这能有所帮助!
还有另一种棘手的方法。主要思想是将节数加倍,第一个只显示headerView,而第二个显示真正的单元格。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionCount * 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section%2 == 0) {
return 0;
}
return _rowCount;
}
接下来需要做的是实现headerInSection委托:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section%2 == 0) {
//return headerview;
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section%2 == 0) {
//return headerheight;
}
return 0;
}
这种方法对你的数据源也没有什么影响:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int real_section = (int)indexPath.section / 2;
//your code
}
与其他方法相比,这种方法是安全的,同时不改变tableview的框架或contentInsets。
希望这能有所帮助。
也许你可以在tableView上使用scrollViewDidScroll
并根据当前可见头更改contentInset。
它似乎适用于我的用例!
extension ViewController : UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let tableView = scrollView as? UITableView,
let visible = tableView.indexPathsForVisibleRows,
let first = visible.first else {
return
}
let headerHeight = tableView.rectForHeader(inSection: first.section).size.height
let offset = max(min(0, -tableView.contentOffset.y), -headerHeight)
self.tableView.contentInset = UIEdgeInsetsMake(offset, 0, -offset, 0)
}
}
根据@samvermette的回答,我已经在Swift中实现了上面的代码,以便于编码员使用Swift。
let dummyViewHeight = CGFloat(40)
self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
self.tableView.contentInset = UIEdgeInsetsMake(-dummyViewHeight, 0, 0, 0)
@samvermette的解决方案的变体:
/// Allows for disabling scrolling headers in plain-styled tableviews
extension UITableView {
static let shouldScrollSectionHeadersDummyViewHeight = CGFloat(40)
var shouldScrollSectionHeaders: Bool {
set {
if newValue {
tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: bounds.size.width, height: UITableView.shouldScrollSectionHeadersDummyViewHeight))
contentInset = UIEdgeInsets(top: -UITableView.shouldScrollSectionHeadersDummyViewHeight, left: 0, bottom: 0, right: 0)
} else {
tableHeaderView = nil
contentInset = .zero
}
}
get {
return tableHeaderView != nil && contentInset.top == UITableView.shouldScrollSectionHeadersDummyViewHeight
}
}
}
代码片段仅为第一部分显示粘头。其他的节头将与单元格一起浮动。
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
if section == 1 {
tableView.contentInset = .zero
}
}
func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) {
if section == 0 {
tableView.contentInset = .init(top: -tableView.sectionHeaderHeight, left: 0, bottom: 0, right: 0)
}
}
**Swift 5.3 |编程**
private func buildTableView() -> UITableView {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.rowHeight = UITableView.automaticDimension
tableView.showsVerticalScrollIndicator = false
tableView.separatorStyle = .none
let dummyViewHeight: CGFloat = 80
tableView.tableFooterView = UIView(
frame: CGRect(x: .zero,
y: .zero,
width: tableView.bounds.size.width,
height: dummyViewHeight))
tableView.contentInset = UIEdgeInsets(top: .zero, left: .zero, bottom: -dummyViewHeight, right: .zero)
return tableView
}
以下2种场景的最佳解决方案:
场景1:如果tableView样式不是.grouped。改成分组没问题。页脚不会浮动。
场景2:如果你只想在tableView的末尾有一个页脚。它的风格是朴素的
步骤:
最后再加一节。
确保在添加的部分有(nuberOfRowsInSection方法)零行数。
向该节添加自定义页脚。
将highightforfooterinsection设置为自定义页脚,将. 0设置为其他部分的页脚。
例子:
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
//注意:过滤你想要添加自定义section的section
let footerView = UIView()
submitOrganiser?.showFooterAtTheEnd(view: footerView) //my method to customise the footer, use your implementation
return footerView
}