UITableView的简单使用方式

一、前言

UITableView 的主要优势在于:

  1. 极简的列表实现 - 几行代码就能创建功能完整的列表
  2. 最佳性能 - 专门为垂直列表优化
  3. 丰富的内置功能 - 编辑模式、索引、刷新控制等
  4. 成熟的生态系统 - 大量第三方库和社区支持
    对于简单的垂直列表需求,UITableView 通常是最简单、最高效的选择。

二、示例代码

简单效果如下
在这里插入图片描述

//
//  CustomUITabView.swift
//  UiKitExample
//
//  Created by YM on 9/29/25.
//  这是一个练习UIKit中UITabView的使用方式
// MARK: - UITableView Selection API
//
// 【单选模式】
//   • 设置: allowsMultipleSelection = false (默认)
//   • 获取: tableView.indexPathForSelectedRow
//
// 【多选模式】
//   • 设置: allowsMultipleSelection = true
//   • 获取: tableView.indexPathsForSelectedRows
//
// 【编程操作】
//   • 选中: selectRow(at:animated:scrollPosition:)
//   • 取消: deselectRow(at:animated:)

import UIKit


// 数据模型
struct Fruit {
    let name: String
    let description: String
    let icon: String
}

class FruitCell: UITableViewCell {
    
    let iconImageView = UIImageView()
    let titleLabel = UILabel()
    let subtitleLabel = UILabel()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    func setupUI() {
        // 配置图标
        iconImageView.contentMode = .scaleAspectFit
        iconImageView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(iconImageView)
        
        // 配置标题
        titleLabel.font = .systemFont(ofSize: 17, weight: .semibold)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(titleLabel)
        
        // 配置副标题
        subtitleLabel.font = .systemFont(ofSize: 14)
        subtitleLabel.textColor = .gray
        subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(subtitleLabel)
        
        // 布局约束
        NSLayoutConstraint.activate([
            iconImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
            iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            iconImageView.widthAnchor.constraint(equalToConstant: 40),
            iconImageView.heightAnchor.constraint(equalToConstant: 40),
            
            titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 15),
            titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12),
            titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
            
            subtitleLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
            subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
            subtitleLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor)
        ])
    }
    
    func configure(with fruit: Fruit) {
        iconImageView.image = UIImage(systemName: fruit.icon)
        titleLabel.text = fruit.name
        subtitleLabel.text = fruit.description
    }
}

class CustomTabView: UIView{
    private let tableView = {
        let tableView = UITableView()
//        tableView.separatorStyle = .none
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .singleLine
        tableView.allowsSelection = true  // 允许选择(默认就是 true)
        tableView.allowsMultipleSelection = false  // 不允许多选(默认)
        tableView.separatorInset = UIEdgeInsets(top: 0, left: 70, bottom: 0, right: 0)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()
//    let data = ["苹果", "香蕉", "橙子", "葡萄", "西瓜", "草莓", "芒果", "樱桃"]
    let fruits = [
            Fruit(name: "苹果", description: "富含维生素C", icon: "apple.logo"),
            Fruit(name: "香蕉", description: "高钾水果", icon: "banana"),
            Fruit(name: "橙子", description: "酸甜可口", icon: "circle.fill"),
            Fruit(name: "葡萄", description: "营养丰富", icon: "circle.grid.cross"),
            Fruit(name: "西瓜", description: "夏季解暑", icon: "drop.fill"),
            Fruit(name: "草莓", description: "美容养颜", icon: "heart.fill"),
        ]
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupTableView()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    func setupTableView() {
        
        // 设置代理和数据源
        tableView.dataSource = self
        tableView.delegate = self
        // 注册 cell(使用系统默认的 UITableViewCell)
//        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.register(FruitCell.self, forCellReuseIdentifier: "cell")
        
        
        addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: topAnchor),
            tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
}

extension CustomTabView: UITableViewDataSource{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//        data.count
        fruits.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FruitCell
//        cell.textLabel?.text = data[indexPath.row]
//        cell.textLabel?.textColor = UIColor.white
//        cell.backgroundColor = .clear  // Cell 背景透明
        cell.configure(with: fruits[indexPath.row])
        
        // 自定义选中背景
//           let selectedView = UIView()
//           selectedView.backgroundColor = UIColor.white.withAlphaComponent(0.3)
//           cell.selectedBackgroundView = selectedView
//        cell.accessoryType = .disclosureIndicator
        cell.accessoryType = .checkmark
        return cell
    }
}

extension CustomTabView: UITableViewDelegate {
    
    // 选中时候调用
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 检查是否是当前选中的行,通过判断当前点击是选中还是取消来进行下一步状态更改
//         let isSelected = tableView.indexPathForSelectedRow == indexPath
        let isSelected = tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false
//            print("当前状态: \(isSelected ? "选中" : "未选中")")
//        print("选中了: \(data[indexPath.row])")
        print("当前点击了: \(fruits[indexPath.row].name)-->此时选择状态为:\(isSelected)")
        // 可以在这里跳转到详情页
        //        let alert = UIAlertController(title: "提示", message: "你选择了\(data[indexPath.row])", preferredStyle: .alert)
        //        alert.addAction(UIAlertAction(title: "确定", style: .default))
        ////        present(alert, animated: true)
    
        // 单选模式:获取选中的行
        if let selectedRow = tableView.indexPathForSelectedRow {
            print("当前选中索引: \(selectedRow.row)")
        }
        // 获取选中的索引
        // 多选模式下,获取所有选中的索引
//        if let selectedIndexPaths = tableView.indexPathsForSelectedRows {
//            let selectedItems = selectedIndexPaths.map { data[$0.row] }
//            print("选中项: \(selectedItems)")
//        }
        // 选中某一行
//        tableView.selectRow(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: .none)
//
//        // 取消选中某一行
//        tableView.deselectRow(at: IndexPath(row: 0, section: 0), animated: true)
//
//        // 取消所有选中
//        if let selectedRows = tableView.indexPathsForSelectedRows {
//            for indexPath in selectedRows {
//                tableView.deselectRow(at: indexPath, animated: true)
//            }
//        }
//        tableView.deselectRow(at: indexPath, animated: true) // 取消选中效果
    }
    
    // ❌ 取消选中时调用
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        print("❌ 取消选中: \(fruits[indexPath.row].name)")
        print("此时选择状态为: false")
        
        // 获取剩余选中的行
        if let selectedRows = tableView.indexPathsForSelectedRows {
            print("当前选中的行数: \(selectedRows.count)")
        } else {
            print("当前没有选中的行")
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 70
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值