You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的滚动监听方法,计算单元格的可见比例,动态调整透明度实现淡出:

  1. 在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))
    }
}
  1. 确认你的ViewController已经设置为UITableViewDelegate(你的代码中已设置self.tableView.delegate = self,此步骤可跳过)。

你可以根据需求调整visibleRatio * 2的系数,改变淡出的快慢程度。

额外注意

如果表格包含表头或表尾,需要在计算可见区域时加入它们的高度,避免比例计算偏差。

内容的提问来源于stack exchange,提问作者polymerchm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:45:10