将 UITableView 排序为多个部分

Posted

技术标签:

【中文标题】将 UITableView 排序为多个部分【英文标题】:sorting UITableView into sections 【发布时间】:2016-04-24 19:10:33 【问题描述】:

我是 swift 和 Xcode 的新手(通过教程和 *** 自学)。我已经编写了一些代码,将地点添加到 TableView 中的列表中,现在我正在尝试将该地点列表分类为部分。

具体来说,我有一个 ViewController,我在其中输入姓名、邻居和朋友(所有字符串),这会在我的 TableView 底部添加一个 Place。

我想按社区对这个地点列表进行分组,并将同一社区中的所有地点一起显示在一个部分中,使用社区字符串作为部分标题。

我很接近,但我没有正确索引我的部分。 indexPath.section 我相信是我所缺少的..

到目前为止,我的 TableViewController 中有这段代码:

// MARK: Properties

var places = [Place]()

override func viewDidLoad() 
    super.viewDidLoad()

    // Use the edit button item provided by the table view controller.
    navigationItem.leftBarButtonItem = editButtonItem()

    // Load any saved places, otherwise load sample data.
    if let savedPlaces = loadPlaces() 
        places += savedPlaces
    

    else 
        // Load the sample data.
        loadSamplePlaces()
    

    // Sort by neighborhood
    places.sortInPlace  (place1, place2) -> Bool in
        return place1.neighborhood < place2.neighborhood
    


// MARK: Getting Count, Number and Name of Neighborhoods
func getCountForNeighborhood(neighborhood:String) -> Int 
    return places.filter  (place) -> Bool in
        return place.neighborhood == neighborhood
    .count


func getNumberOfNeighborhoods() -> Int 
    var neighborhoodCount = 0
    var neighborhoodPrev = "Not a real neighborhood"
    for place in places 
        if place.neighborhood != neighborhoodPrev 
            neighborhoodCount += 1
        
        neighborhoodPrev = place.neighborhood
    
    return neighborhoodCount


func getNeighborhoodForSection(section:Int) -> String 
    var previousNeighborhood:String = "Not a real neighborhood"
    var currentIndex = -1

    for place in places 

        if(place.neighborhood != previousNeighborhood) 
            currentIndex += 1
        
        if(currentIndex == section)
            return place.neighborhood
        
        previousNeighborhood = place.neighborhood
    

    return "Unknown"


func loadSamplePlaces() 

    let place1 = Place(name: "Motorino", neighborhood: "East Village", friend: "Maggles")!
    let place2 = Place(name: "Bar Primi", neighborhood: "Lower East Side", friend: "Em")!
    let place3 = Place(name: "El Carino", neighborhood: "Williamsburg", friend: "Ruby")!

    places += [place1, place2, place3]


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.



// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
    //alter this for To Try, Been To sections =2
    return getNumberOfNeighborhoods()


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    // #warning Incomplete implementation, return the number of rows

    let neighborhood = getNeighborhoodForSection(section)
    return getCountForNeighborhood(neighborhood)


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    // Table view cells are reused and should be dequeued using a cell identifier.
    let cellIdentifier = "PlaceTableViewCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! PlaceTableViewCell

    // Fetches the appropriate place for the data source layout.

    let place = places[indexPath.row]

    cell.placeLabel.text = place.name
    cell.neighborhoodLabel.text = place.neighborhood
    cell.friendLabel.text = place.friend

    return cell


//Add section headers
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
    return getNeighborhoodForSection(section)


我很确定这是我的 cellForRowAtIndexPath 方法的问题。我想我缺少一些代码来正确地将数据索引到各个部分......

当前版本显示

【问题讨论】:

【参考方案1】:

你把部分弄得一团糟。

在方法tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) 中,您根据indexPath 的行从places 数组中获取数据。 但是您根本不会“谈论”部分。这就是为什么您告诉数据源委托获取这 2 个位置对象的数据,而不管它询问您的部分。 您已经以这样的关系样式创建了一个数据结构:

neighbourhood1 - place1
neighbourhood1 - place2
neighbourhood2 - place3
neighbourhood2 - place4
neighbourhood3 - place5
neighbourhood3 - place6

相信我,将这个数据结构与UITableView 数据源概念结合起来真的很困难,因为很难从单个数据中确定节索引。 尝试将您的数据排列成这样的树:

neighbourhood1:
 - place1
 - place2
neighbourhood2:
 - place3
 - place4
neighbourhood3:
 - place5
 - place6

在一个数组数组中,然后它会很简单,因为 indexPath 对(节,行)将匹配您的 places[section][row] 的索引:

neighbourhood1: (section 0)
 - place1 (path 0.0)
 - place2 (path 0.1)
neighbourhood2: (section 1)
 - place3 (path 1.0)
 - place4 (path 1.1)
neighbourhood3: (section 2)
 - place5 (path 2.0)
 - place6 (path 2.1)

【讨论】:

【参考方案2】:

我同意另一个答案:如果您首先将数据存储在按邻域组织的二维数组中,然后放置第二个,然后按以下方式访问数据,这将更容易:

let place = places[indexPath.section, indexPath.row];

但是,对于您的具体问题和当前代码,我在这里看到了两件事。首先,您的样本数据每个社区有一个项目,但您的表格显示每个社区有两行。这表明您的 numberOfRowsInSection 函数在我们期望它为 1 时返回 2。确保您的 getNeighborhoodForSection 返回正确的部分。然后看看为什么getCountForNeighborhood 没有为每个部分返回 1。 (顺便说一句,您可能已经知道这一点,但getNeighborhoodForSection 假设您的数据始终按邻域排序。如果您无序插入新的邻域,则会遇到问题)。

其次,cellForRowAtIndexPath 你总是按indexPath.row 号码提取数据。当您为每个社区输入此函数时,indexPath.row 号码将始终在每个部分(社区)的 0 处重新开始。因此,您将从places (Motorino) 中拉出第一项,作为每个部分的第一行。这就是为什么您会在每个部分中看到相同的地点列表。

一旦每个社区的行数正确,在cellForRowAtIndexPath 中,您需要:

    使用您的getNeighborhoodForSection(index.section); 获取 index.section 的邻域 搜索places,直到找到那个邻域并保存起点的索引,我将其称为neighborHoodStartIndex let place = places[neighborHoodStartIndex + indexPath.row]

出于调试目的,我建议在每个社区中创建不同数量的示例位置。当您期望每个部分中的行数不同时,发现问题模式会更容易一些。

【讨论】:

以上是关于将 UITableView 排序为多个部分的主要内容,如果未能解决你的问题,请参考以下文章

自定义 UITableView 重新排序

iOS 5 - 按核心数据属性将 UITableView 划分为多个部分

UITableView 排序部分

UITableView 拉伸问题

按日期条件对 UItableView 部分进行排序

表视图的 headerView 中的 UITableView