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

如何制作左右侧边带弧形、类PickerView效果的TableView

Hey there! Let's break down how to build that TableView that behaves like a UIPickerView, plus add those curved side effects you're looking for. Here's a step-by-step solution tailored to your needs:

1. Make Your TableView Behave Like UIPickerView

UIPickerView's key behaviors are centered selection highlight, scroll snapping to rows, and a single-row focus. Here's how to replicate that:

Key Implementations:

  • Fixed Row Height: Set a consistent row height so scrolling snaps cleanly.
  • Centered Selection Detection: Track which row is in the center of the TableView as the user scrolls, then highlight it.
  • Scroll Snapping: When the user stops dragging, auto-scroll to the nearest full row to keep the selected item centered.

Code Examples:

First, add these properties to your ViewController:

@IBOutlet weak var pickerLikeTableView: UITableView!
private var selectedIndexPath: IndexPath?
private let rowHeight: CGFloat = 50

Configure your TableView in viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    pickerLikeTableView.rowHeight = rowHeight
    pickerLikeTableView.showsVerticalScrollIndicator = false
    pickerLikeTableView.delegate = self
    pickerLikeTableView.dataSource = self
}

Implement scroll delegates to handle selection and snapping:

extension YourViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        // Calculate the center point of the TableView
        let centerY = scrollView.contentOffset.y + scrollView.bounds.height / 2
        let centerPoint = CGPoint(x: scrollView.bounds.midX, y: centerY)
        
        // Find the row at the center point
        if let indexPath = pickerLikeTableView.indexPathForRow(at: centerPoint) {
            guard selectedIndexPath != indexPath else { return }
            selectedIndexPath = indexPath
            // Reload only the changed rows to update highlighting
            pickerLikeTableView.reloadRows(at: [indexPath], with: .fade)
        }
    }
    
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        // Calculate the target offset to snap to the nearest row
        let targetY = targetContentOffset.pointee.y
        let nearestRow = round(targetY / rowHeight) * rowHeight
        targetContentOffset.pointee.y = nearestRow
    }
}

Update cell styling to highlight the selected row:

extension YourViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PickerCell", for: indexPath)
        cell.textLabel?.text = "Option \(indexPath.row + 1)"
        
        // Customize highlight style
        if indexPath == selectedIndexPath {
            cell.textLabel?.font = .boldSystemFont(ofSize: 18)
            cell.textLabel?.textColor = .systemBlue
            cell.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.1)
        } else {
            cell.textLabel?.font = .systemFont(ofSize: 16)
            cell.textLabel?.textColor = .label
            cell.backgroundColor = .clear
        }
        return cell
    }
    
    // Don't forget to implement numberOfRowsInSection!
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // Replace with your data count
    }
}
2. Add Curved Side Effects to the TableView

For the curved left/right edges, you have two solid approaches—pick whichever fits your design better:

Method 1: Use a Shape Mask

This masks the TableView to only show the curved shape, so the background behind it shows through the curved areas.

Add this helper method to your ViewController:

private func applyCurvedMask(to tableView: UITableView) {
    let cornerRadius: CGFloat = 30 // Adjust this to control curve intensity
    let maskPath = UIBezierPath(roundedRect: tableView.bounds,
                                byRoundingCorners: [.topLeft, .bottomLeft, .topRight, .bottomRight],
                                cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
    
    let maskLayer = CAShapeLayer()
    maskLayer.path = maskPath.cgPath
    tableView.layer.mask = maskLayer
    
    // Optional: Add a border around the curved shape
    let borderLayer = CAShapeLayer()
    borderLayer.path = maskPath.cgPath
    borderLayer.strokeColor = UIColor.systemGray.cgColor
    borderLayer.fillColor = UIColor.clear.cgColor
    borderLayer.lineWidth = 1
    tableView.layer.addSublayer(borderLayer)
}

Call it in viewDidLayoutSubviews to ensure it updates when the frame changes:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    applyCurvedMask(to: pickerLikeTableView)
    // Adjust content inset so rows don't get cut off by the curve
    pickerLikeTableView.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
}

Method 2: Custom Curved Background View

If you want a solid curved background (instead of masking), create a custom view to draw the shape:

class CurvedBackgroundView: UIView {
    var cornerRadius: CGFloat = 30 {
        didSet { setNeedsDisplay() }
    }
    
    override func draw(_ rect: CGRect) {
        let path = UIBezierPath()
        
        // Draw left curved edge
        path.move(to: CGPoint(x: cornerRadius, y: 0))
        path.addArc(withCenter: CGPoint(x: cornerRadius, y: cornerRadius),
                    radius: cornerRadius,
                    startAngle: .pi * 3/2,
                    endAngle: .pi,
                    clockwise: false)
        path.addLine(to: CGPoint(x: 0, y: bounds.height - cornerRadius))
        path.addArc(withCenter: CGPoint(x: cornerRadius, y: bounds.height - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .pi,
                    endAngle: .pi/2,
                    clockwise: false)
        
        // Draw right curved edge
        path.addLine(to: CGPoint(x: bounds.width - cornerRadius, y: bounds.height))
        path.addArc(withCenter: CGPoint(x: bounds.width - cornerRadius, y: bounds.height - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .pi/2,
                    endAngle: 0,
                    clockwise: false)
        path.addLine(to: CGPoint(x: bounds.width, y: cornerRadius))
        path.addArc(withCenter: CGPoint(x: bounds.width - cornerRadius, y: cornerRadius),
                    radius: cornerRadius,
                    startAngle: 0,
                    endAngle: .pi * 3/2,
                    clockwise: false)
        
        path.close()
        
        // Fill the background color
        UIColor.white.setFill()
        path.fill()
        
        // Optional: Add border
        UIColor.systemGray.setStroke()
        path.lineWidth = 1
        path.stroke()
    }
}

Then set it as your TableView's background:

override func viewDidLoad() {
    super.viewDidLoad()
    // ... other TableView setup
    let curvedBackground = CurvedBackgroundView(frame: pickerLikeTableView.bounds)
    curvedBackground.cornerRadius = 30
    pickerLikeTableView.backgroundView = curvedBackground
    pickerLikeTableView.backgroundColor = .clear
    pickerLikeTableView.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    pickerLikeTableView.backgroundView?.frame = pickerLikeTableView.bounds
}

Quick Tips:

  • Adjust the cornerRadius value to make the curves more or less pronounced.
  • The contentInset ensures your TableView rows don't get hidden under the curved edges.
  • Test on different screen sizes to make sure the curves scale correctly (using viewDidLayoutSubviews helps with this).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:05:03