UITableView滚动时单元格超出视图边界,如何实现边缘淡出消失?
问题描述
开发应用时使用了多个UITableView,滚动时发现所有表格的单元格在消失前都会超出UITableView的上下边界,希望实现单元格在超出边界前就消失或淡出的效果。
滚动前截图:
滚动时截图:
以下是自定义ViewController中的代码(使用Cartography进行布局):
override func viewDidLoad() { super.viewDidLoad() appDelegate = UIApplication.shared.delegate as? AppDelegate model = appDelegate.model as CCModel setupTable() createTableContent() appDelegate.chordIndex = createSectionIndex() appDelegate.leftPanel!.addSubview(appDelegate.chordIndex!) appDelegate.chordIndex!.alpha = 0.0 #if targetEnvironment(macCatalyst) self.tableView.addGestureRecognizer(HoverGestureRecognizer(target: appDelegate, action: #selector(appDelegate.viewHovering(_:)), id: .selectChord)) #else self.tableView.addGestureRecognizer(LongPressGestureRecognizer(target: appDelegate, action: #selector(appDelegate.onLongTip(_:)), type: .selectChord)) #endif // Uncomment the following line to preserve selection between presentations // self.clearsSelectionOnViewWillAppear = false // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem() } func setupTable() { self.tableView.backgroundColor = UIColor.white self.tableView!.accessibilityIdentifier = "ChordTV" self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: reuseID) self.tableView.dataSource = self self.tableView.delegate = self self.tableView.separatorStyle = .none self.tableView.alpha = 0.0 // initially hidden } func createTableContent() { // create the ChordFamily Dictionary CHORDTYPE.forEach { item in let out = sChordTableItem(name: item.name, chordTones: item.chordTones, family:item.family, selected: false) if (!familyDict.keys.contains(out.family)) { familyDict[out.family] = [out] } else { familyDict[out.family]!.append(out) } if out.family == "SIMPLE" { numSimpleChords += 1 } } var sectionPointer = 0 for (index,family) in families.enumerated() { familyOffsets[index] = sectionPointer sectionPointer += familyDict[family]!.count items.append(contentsOf: familyDict[family]!) } items = items.compactMap {$0} // flatten ordered list } override func viewDidAppear(_ animated: Bool) { let device = Device.current let parentSize = self.view.superview!.frame.size var widthFraction = CGFloat(0.0) if device.isPad { widthFraction = 0.4 } else { widthFraction = 0.3 } self.tableView.rowHeight = 36 group = Cartography.constrain(self.view, appDelegate.chordIndex!, appDelegate.chordscaleLabel!, appDelegate.chordIndexLabel!, replace: group) { tv, index, label, ciLabel in label.leading == label.superview!.safeAreaLayoutGuide.leading + parentSize.width * model.scaleChordFraction label.height == 32 label.trailing == label.superview!.trailing - 10 label.top == label.superview!.safeAreaLayoutGuide.top + model.labelOffset tv.top == tv.superview!.safeAreaLayoutGuide.top + 50 tv.bottom == tv.superview!.safeAreaLayoutGuide.bottom - 50 tv.width == parentSize.width * widthFraction tv.leading == label.leading index.top == tv.top index.leading == tv.trailing + model.chordIndexOffset index.width == parentSize.width * 0.13 index.bottom == tv.bottom ciLabel.leading == index.leading ciLabel.height == 32 ciLabel.trailing == ciLabel.superview!.trailing - 10 ciLabel.top == ciLabel.superview!.safeAreaLayoutGuide.top + model.labelOffset } delay(0.1) { self.adjustButtons() } self.view.addShadowToView(image: true) }
解决方案
提供两种实用的实现方式:
方式一:裁剪超出边界的内容(直接隐藏)
给UITableView开启裁剪功能,单元格一超出边界就会被直接隐藏,操作最简单:
// 在setupTable方法中添加这行代码 self.tableView.clipsToBounds = true
方式二:实现渐隐效果
通过UITableViewDelegate的滚动监听方法,计算单元格的可见比例,动态调整透明度实现淡出:
- 在ViewController中添加滚动监听方法:
func scrollViewDidScroll(_ scrollView: UIScrollView) { guard let tableView = scrollView as? UITableView else { return } // 获取表格的可见区域 let visibleRect = CGRect(origin: tableView.contentOffset, size: tableView.bounds.size) let visibleFrame = tableView.convert(visibleRect, to: tableView.superview) // 遍历所有可见单元格,调整透明度 for cell in tableView.visibleCells { let cellFrame = tableView.convert(cell.frame, to: tableView.superview) // 计算单元格与可见区域的重叠比例 let intersection = visibleFrame.intersection(cellFrame) let visibleRatio = intersection.height / cellFrame.height // 控制透明度:重叠比例低于0.5时开始淡出,完全超出时透明度为0 cell.alpha = max(0, min(1, visibleRatio * 2)) } }
- 确认你的ViewController已经设置为
UITableViewDelegate(你的代码中已设置self.tableView.delegate = self,此步骤可跳过)。
你可以根据需求调整visibleRatio * 2的系数,改变淡出的快慢程度。
额外注意
如果表格包含表头或表尾,需要在计算可见区域时加入它们的高度,避免比例计算偏差。
内容的提问来源于stack exchange,提问作者polymerchm
相关产品推荐
相关产品推荐

