Как маскировать UITableViewCells под прозрачным заголовком UITableView
Я хочу, чтобы заголовок маскировал ячейки, но не фон.
У меня есть UITableView с прозрачными заголовками и ячейками, подобными Центру уведомлений Apple (при прокрутке строки состояния на вашем iPhone). Я не могу понять, как маскировать ячейки, чтобы они не отображались под заголовком при прокрутке.
Я пробовал изменить contentInsets таблицы, и я попытался изменить фрейм заголовка View на отрицательное начало.
Ответы
Ответ 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 <QuartzCore/QuartzCore.h>
для пользовательской ячейки.
Ответ 2
Немного отредактируйте ответ Alex Markman, где вы можете пропустить создание подкласса для UITableViewCell. Преимущество этого подхода заключается в том, что вы можете использовать его для нескольких разных UITableViewCells.
- (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;
}
Ответ 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;
}
Ответ 5
Версия Clean 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
}
}
Я просто использовал это, и он работает как шарм. Я хочу поблагодарить всех на этом посту! Все голоса вокруг!
Ответ 6
У меня есть два возможных решения, без кода - просто идея:
- не общий, должен работать с яблоком установки/дизайна, используемым в Центре уведомлений.
Сделайте заголовок секции непрозрачным, "клонируйте" фоновый рисунок таблицы в качестве фона раздела-заголовка. Поместите фоновый рисунок в зависимости от смещения заголовка раздела.
- genereic, но, вероятно, больше проблем с производительностью. Должно работать нормально с несколькими ячейками.
Добавьте альфа-маску ко всем ячейкам. Переместите альфа-маску в зависимости от положения ячейки.
(используйте метод делегата scrollViewDidScroll для поддержания фонового рисунка/смещения альфа-маски).
Ответ 7
В итоге я установил высоту заголовка раздела до минимума и переопределил UITableView layoutSubviews, чтобы поместить заголовок в представление tableView, отрегулировав начало кадра вверх по его высоте.
Ответ 8
Версия Swift 3 не работала для меня, потому что я добавил UITableViewController в качестве подзаголовка. Поэтому мне пришлось внести некоторые изменения в расширение прокрутки.
Это также должно работать с UITableViewController, который был нажат из другого ViewController (Примечание: не проверено)
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 ячейки и отвлекаю содержимое scollViewsOffsetY.
Высота моего настраиваемого раздела - 44. Поэтому я определяю значение hideAmount для маски.
Функции ячейки нетронуты:
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
Или, если вам нужно только для вашего интерфейса,
вы могли
измените вид таблицы, чтобы не иметь заголовков плавающих разделов
В двух быстрых и простых шагах (iOS 6):
-
Измените стиль UITableView на UITableViewStyleGrouped. (Вы можете сделать это из Storyboard/NIB или с помощью кода.)
-
Затем установите для вашего представления в виде таблицы вид на пустой вид, подобный этому [в любом методе, таком как viewDidAppear или даже в методе cellForRow (хотя я бы предпочел первый)].
yourTableView.backgroundView = [[UIView alloc] initWithFrame:listTableView.bounds];
Voila, теперь у вас есть вид в таблице, но без заголовков плавающего раздела. Заголовки разделов теперь прокручиваются вместе с ячейками, и ваши беспорядочные проблемы пользовательского интерфейса решаются!
Попробуйте это и дайте мне знать, как это происходит.
Счастливое кодирование:)
EDIT: для iOS 7 просто измените стиль представления таблицы на "UITableViewStyleGrouped" и измените цвет оттенка представления на "очистить цвет".