【问题标题】:How to mask UITableViewCells underneath a UITableView Transparent Header如何在 UITableView 透明标题下屏蔽 UITableViewCells
【发布时间】:2012-08-26 02:13:39
【问题描述】:

我希望标题遮盖单元格,而不是背景。

我有一个带有透明标题和单元格的 UITableView,类似于 Apple 的通知中心(当您在 iPhone 上的状态栏上向下滑动时)。我不知道如何掩盖单元格,以便它们在滚动时不会显示在标题下方。

我试过改变tableview的contentInsets,也试过把header View的frame改成负原点。

【问题讨论】:

  • 你说的是表头还是节头?
  • @RonLugge 他在谈论章节标题。按照他的描述打开通知中心,你可以清楚地看到他的意思。
  • 我想知道这是一个透明标题(在通知中心),还是只是一个与屏幕其余部分具有相同背景的标题?你能通过这样做来解决你的问题,还是你的背景很复杂才能起作用?
  • @rdelmar 通知中心的标题在移动时是透明的,我猜它不会根据位置而改变。我的 TableView 样式与 Apple 通知中心非常相似,它具有复杂的背景和多个依赖阴影和高光来增加深度的部分。将图形降级为不透明的标题将是我最后的手段。

标签: iphone objective-c ios


【解决方案1】:

尝试创建UITableviewCell的子类并添加这些方法

- (void)maskCellFromTop:(CGFloat)margin {
    self.layer.mask = [self visibilityMaskWithLocation:margin/self.frame.size.height];
    self.layer.masksToBounds = YES;
}

- (CAGradientLayer *)visibilityMaskWithLocation:(CGFloat)location {
    CAGradientLayer *mask = [CAGradientLayer layer];
    mask.frame = self.bounds;
    mask.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:1 alpha:0] CGColor], (id)[[UIColor colorWithWhite:1 alpha:1] CGColor], nil];
    mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location], [NSNumber numberWithFloat:location], nil];
    return mask;
}

并在UITableView中添加这个委托方法

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    for (iNotifyTableViewCell *cell in self.visibleCells) {
        CGFloat hiddenFrameHeight = scrollView.contentOffset.y + [iNotifyHeaderView height] - cell.frame.origin.y;
        if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) {
            [cell maskCellFromTop:hiddenFrameHeight];
        }
    }
}

*注意[iNotifyHeaderView height]HeaderView 的高度。并将#import &lt;QuartzCore/QuartzCore.h&gt; 用于自定义单元格。

【讨论】:

  • 谢谢!像魅力一样工作!我整天都在为此苦苦挣扎。我不敢相信我必须为此链接 QuartzCore.framework。但是我也想复制你的页脚代码,但我不知道掩码是如何工作的,你能解释一下吗?
  • 在 iOS 掩码中有点不同,白色部分显示部分,透明部分不显示。因此,此代码使顶部透明的蒙版与标题高度相同,但其余部分为白色,因此单元格部分可见,但标题后面的部分是隐藏的。 :)
  • 这是正确的答案。效果很好!
  • @AlexMarkman 谢谢,完美运行。我会将 tableView 的 contentInset 属性的顶部添加到您正在计算的 hiddenFrameHeight 以考虑 iOS 7 添加到滚动视图的自动插入,以及刷新控件等添加的任何空间:CGFloat hiddenFrameHeight = scrollView.contentOffset.y + [iNotifyHeaderView height] - cell.frame.origin.y + scrollView.contentInset.top;
  • 我还将此代码添加到 UITableViewCell 的 maskCellFromTop: 方法以提高性能(如果边距不适合当前单元格,则删除掩码)if (margin &gt; 0) { self.layer.mask = [self visibilityMaskWithLocation:margin/self.frame.size.height]; self.layer.masksToBounds = YES; } else { self.layer.mask = nil; }
【解决方案2】:

对 Alex Markman 的回答稍作修改,您可以跳过为 UITableViewCell 创建子类的步骤。这种方法的好处是您可以将它用于多个不同的 UITableViewCell。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    for (UITableViewCell *cell in self.tableView.visibleCells) {
        CGFloat hiddenFrameHeight = scrollView.contentOffset.y + self.navigationController.navigationBar.frame.size.height - cell.frame.origin.y;
        if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) {
            [self maskCell:cell fromTopWithMargin:hiddenFrameHeight];
        }
    }
}

- (void)maskCell:(UITableViewCell *)cell fromTopWithMargin:(CGFloat)margin
{
    cell.layer.mask = [self visibilityMaskForCell:cell withLocation:margin/cell.frame.size.height];
    cell.layer.masksToBounds = YES;
}

- (CAGradientLayer *)visibilityMaskForCell:(UITableViewCell *)cell withLocation:(CGFloat)location
{
    CAGradientLayer *mask = [CAGradientLayer layer];
    mask.frame = cell.bounds;
    mask.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:1 alpha:0] CGColor], (id)[[UIColor colorWithWhite:1 alpha:1] CGColor], nil];
    mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location], [NSNumber numberWithFloat:location], nil];
    return mask;
}

【讨论】:

  • 喜欢这个。像魅力一样工作。我喜欢我不必继承任何东西。我只需修改 self.navigationController.navigationBar.frame.size.height 即可使用表头的高度。 -rrh
  • 这是一个很好的解决方案,但是有一个问题。如果您在加载数据时在表格视图中使用某种分页,则掩码存在问题,即当显示分页加载指示符的 tablefooterview 隐藏时,它会隐藏最后一个单元格的底部。
【解决方案3】:

@Alex Markman - 你的回答很好,对我很有用,但我发现当你在视网膜设备上滚动时,单元格滚动不顺畅。发现是渲染过程中layer的locations参数引起的:

mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location];

我稍微修改了您的代码。也许有人会觉得它有用:

- (void)maskCellFromTop:(CGFloat)margin
{
    self.layer.mask = [self visibilityMaskFromLocation:margin];
    self.layer.masksToBounds = YES;
}

- (CAGradientLayer *)visibilityMaskFromLocation:(CGFloat)location
{
    CAGradientLayer *mask = [CAGradientLayer layer];
    mask.frame = CGRectMake(
                            self.bounds.origin.x,
                            location+self.bounds.origin.y,
                            self.bounds.size.width,
                            self.bounds.size.height-location);
    mask.colors = @[
                    (id)[[UIColor colorWithWhite:1 alpha:1] CGColor],
                    (id)[[UIColor colorWithWhite:1 alpha:1] CGColor]
                    ];
    return mask;
}

【讨论】:

    【解决方案4】:

    斯威夫特版本

    func scrollViewDidScroll(_ scrollView: UIScrollView) { 
        for cell in tableView.visibleCells {
            let hiddenFrameHeight = scrollView.contentOffset.y + navigationController!.navigationBar.frame.size.height - cell.frame.origin.y
            if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) {
                maskCell(cell: cell, margin: Float(hiddenFrameHeight))
            }
        }
    }
    
    func maskCell(cell: UITableViewCell, margin: Float) {
        cell.layer.mask = visibilityMaskForCell(cell: cell, location: (margin / Float(cell.frame.size.height) ))
        cell.layer.masksToBounds = true
    }
    
    func visibilityMaskForCell(cell: UITableViewCell, location: Float) -> CAGradientLayer {
        let mask = CAGradientLayer()
        mask.frame = cell.bounds
        mask.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor(white: 1, alpha: 1).cgColor]
        mask.locations = [NSNumber(value: location), NSNumber(value: location)]
        return mask;
    }
    

    【讨论】:

    • 它工作正常,但是我在同一个 ViewController 的底部有不同的 tableview,当我滚动第二个 tableview 时,第一个 tableview 的单元格也消失了!有什么问题?
    • 在 iOS 14 上,这在将设备旋转到垂直和后退时无法正常工作。它会切割侧面的所有细胞。看起来像是坐标系的东西。
    【解决方案5】:

    干净的 Swift 3 版本:

    extension YourViewController: UIScrollViewDelegate {
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            for cell in tableView.visibleCells {
                let hiddenFrameHeight = scrollView.contentOffset.y + navigationController!.navigationBar.frame.size.height - cell.frame.origin.y
                if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) {
                    if let customCell = cell as? CustomCell {
                        customCell.maskCell(fromTop: hiddenFrameHeight)
                    }
                }
            }
        }
    }
    
    class CustomCell: UITableViewCell {
        public func maskCell(fromTop margin: CGFloat) {
            layer.mask = visibilityMask(withLocation: margin / frame.size.height)
            layer.masksToBounds = true
        }
    
        private func visibilityMask(withLocation location: CGFloat) -> CAGradientLayer {
            let mask = CAGradientLayer()
            mask.frame = bounds
            mask.colors = [UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.cgColor]
            let num = location as NSNumber
            mask.locations = [num, num]
            return mask
        }
    }
    

    我刚用过它,它就像一个魅力。我要感谢帖子里的每一个人!到处投票!

    【讨论】:

    • 它工作正常,但是我在同一个 ViewController 的底部有不同的 tableview,当我滚动第二个 tableview 时,第一个 tableview 的单元格也消失了!有什么问题?
    【解决方案6】:

    我有两种可能的解决方案,没有代码 - 只是想法:

    1. 不是通用的,应该与苹果在通知中心使用的设置/设计一起使用。

    使 Section-Header 不透明,“克隆”表格的背景图案作为 section-Header 的背景。根据节头偏移定位背景图案。


    1. 通用,但可能存在更多性能问题。应该可以在少量单元格的情况下正常工作。

    为所有单元格层添加一个 Alpha 蒙版。根据单元格位置移动 Alpha 蒙版。


    (使用 scrollViewDidScroll 委托方法来维护 background-pattern / Alpha-Mask 偏移)。

    【讨论】:

      【解决方案7】:

      我最终将部分标题的高度设置为最小值,并覆盖 UITableView 的 layoutSubviews 以将标题放置在 tableView 的超级视图上,将框架的原点向上调整其高度。

      【讨论】:

      • 不是所提出问题的答案。
      • 其他答案更好。这篇文章是一个 OP 只是对正确答案的自私。
      【解决方案8】:

      Swift 3 版本对我不起作用,因为我将 UITableViewController 添加为子视图。所以我不得不对scrollview的扩展做一些改动。

      这也应该适用于从另一个 ViewController 推送的 UITableViewController(注意:未测试)

      extension NavNotitionTableViewController {
      override func scrollViewDidScroll(_ scrollView: UIScrollView) {
          for cell in tableView.visibleCells {
      
              let calculatedY = cell.frame.origin.y - scrollView.contentOffset.y;
              if let customCell = cell as? NavNotitionTableViewCell {
      
                  if(calculatedY < 44 && calculatedY > 0){
                      let hideAmount = 44 - calculatedY;
      
                      if let customCell = cell as? NavNotitionTableViewCell {
                          customCell.maskCell(fromTop: hideAmount)
                      }
                  }else if (calculatedY > 0){
                      //All other cells
                      customCell.maskCell(fromTop: 0)
                  }else if (calculatedY < 0){
                      customCell.maskCell(fromTop: cell.frame.height);
                  }
              }
          }
      }
      }
      

      在本例中,我首先获取单元格的框架 Y 原点并分散 scollViews 的 contentOffsetY。

      我的自定义部分的高度是 44。所以我定义了遮罩的 hideAmount 值。

      Cell 功能保持不变:

      public func maskCell(fromTop margin: CGFloat) {
          layer.mask = visibilityMask(withLocation: margin / frame.size.height)
          layer.masksToBounds = true
      }
      
      private func visibilityMask(withLocation location: CGFloat) -> CAGradientLayer {
          let mask = CAGradientLayer()
          mask.frame = bounds
          mask.colors = [UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.cgColor]
          let num = location as NSNumber
          mask.locations = [num, num]
          return mask
      }
      

      【讨论】:

        【解决方案9】:

        如果您想在表格视图后面显示内容,这将不起作用,但是,由于我只是尝试创建带有纯色背景的圆形标题,因此为我解决的问题是通过设置来模仿透明度标题的背景视图的背景颜色到表格视图的背景颜色(或具有不透明背景的第一个父视图)。

        【讨论】:

          【解决方案10】:

          或者,如果您只需要让您的 UI 看起来不错, 你可以

          将表格视图更改为没有浮动节标题

          只需两个快速简单的步骤(iOS 6):

          1. 将您的 UITableView 样式更改为 UITableViewStyleGrouped。 (您可以从 Storyboard/NIB 或通过代码执行此操作。)

          2. 接下来,将您的 tableview 的背景视图设置为一个空视图,如下所示 [在诸如 viewDidAppear 之类的方法中,甚至在 cellForRow 方法中(尽管我更喜欢前者)]。

          yourTableView.backgroundView = [[UIView alloc] initWithFrame:listTableView.bounds];
          

          瞧,现在您有了表格视图 - 但没有浮动部分标题。现在,您的部分标题会随着单元格滚动,您的混乱 UI 问题得到解决!

          试试这个,让我知道结果如何。 快乐编码:)

          编辑:对于 iOS 7,只需将表格视图样式更改为“UITableViewStyleGrouped”并将视图的色调颜色更改为“清除颜色”。

          【讨论】:

          • 虽然这个答案«有效»,但我认为它没有解决 OP 的要求。我认为这个想法是保持标题可见,但下面的单元格没有透明标题
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-01-08
          • 2011-10-30
          • 1970-01-01
          • 1970-01-01
          • 2020-01-25
          • 2017-01-01
          • 2013-10-05
          相关资源
          最近更新 更多