3

我有一个如下所示的手风琴菜单示例,我想制作一个嵌套菜单(例如菜单中的菜单),这主要与可扩展的 tableViews 相关,但我需要在可扩展的 tableView 或任何其他解决方案中进行扩展,这里的代码来自做单步手风琴的互联网,我需要嵌套的: PS:我的项目有点重,所以我不想添加其他库,也许只是一个类,非常感谢你提前

//  Created by ingdanni on 05/11/15.
//  Copyright (c) 2015 ManaguaIO. All rights reserved.
//

import UIKit

struct Section {
    let title: String
    let rows: [String]
    var selected: Bool
}

class ViewController: UIViewController {

    let CellIdentifier = "Cell"
    var sections = [Section]()

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup Sections
        sections.append(Section(title: "A", rows: ["1","2","3","4"], selected: false))
        sections.append(Section(title: "B", rows: ["5","6","7","8"], selected: false))
        sections.append(Section(title: "C", rows: ["9","10"], selected: false))

        // Set cell reuse identifier
        self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: CellIdentifier)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return sections.count
    }


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{

        if sections[section].selected
        {
            return sections[section].rows.count
        }
        return 0
    }

    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return ""
    }

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        return 50
    }

    func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 1
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if sections[indexPath.section].selected {
            return 50
        }
        return 2
    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let headerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 40))

        headerView.backgroundColor = UIColor.lightGrayColor()
        headerView.tag = section

        let headerString = UILabel(frame: CGRect(x: 10, y: 10, width: tableView.frame.size.width-10, height: 30)) as UILabel

        headerString.text = sections[section].title
        headerView.addSubview(headerString)

        let headerTapped = UITapGestureRecognizer(target: self, action:"sectionHeaderTapped:")
        headerView.addGestureRecognizer(headerTapped)

        return headerView
    }

    func sectionHeaderTapped(recognizer: UITapGestureRecognizer) {

        let indexPath = NSIndexPath(forRow: 0, inSection:(recognizer.view?.tag as Int!)!)

        if indexPath.row == 0 {

            sections[indexPath.section].selected = !sections[indexPath.section].selected

            //reload specific section animated
            let range = NSMakeRange(indexPath.section, 1)

            let sectionToReload = NSIndexSet(indexesInRange: range)

            self.tableView.reloadSections(sectionToReload, withRowAnimation:UITableViewRowAnimation.Fade)
        }

    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

        let cell = self.tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath)
        cell.textLabel?.text = sections[indexPath.section].rows[indexPath.row]
        return cell
    }


}

像这样

并且像这样示意性地

4

1 回答 1

0

实际上,在如何制作嵌套手风琴的问题上苦苦挣扎之后,我找到了答案,但后来决定不将它用于来自服务器和 JSON Web 服务的动态数据(例如,当你有嵌套的树形菜单时,它具有来自服务器的动态结构)因此我在一个页面中使用了每个类别并定义了三个级别并使用 segues,但是如果您需要制作这样的菜单,我发现制作 NSObject 的技巧是为了定义每个单元格的属性:

import UIKit

class AMPGenericObject: NSObject {

    var name:String?
    var parentName:String?
    var canBeExpanded = false // Bool to determine whether the cell can be expanded
    var isExpanded = false    // Bool to determine whether the cell is expanded
    var level:Int?            // Indendation level of tabelview
    var type:Int?
    var children:[AMPGenericObject] = []

    enum ObjectType:Int{
        case OBJECT_TYPE_REGION = 0
        case OBJECT_TYPE_LOCATION
        case OBJECT_TYPE_USERS
    }

}

这是视图控制器:

import UIKit

class AMPTableViewController: UITableViewController {


var dataArray:[AMPGenericObject] = []
var indendationLevel:Int   = 0
var indendationWidth:CGFloat = 20.0

override func viewDidLoad() {
    super.viewDidLoad()

    for var i=0; i<=10; i++ {

    }

    for i in 0..<10 {

        let prod = AMPGenericObject()
        prod.name = "Region \(i)"
        prod.parentName = ""
        prod.isExpanded = false
        prod.level = 0;
        prod.type  = 0;
        // Randomly assign canBeExpanded status
        let rem = i % 2
        if(rem == 0)
        {
            prod.canBeExpanded  = true;
        }
        else
        {
            prod.canBeExpanded = false;
        }
        dataArray.append(prod)

    }
}

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

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

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

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    let obj = dataArray[indexPath.row]
    // All optionals are ensured to have values, so we can safely unwrap
    cell.textLabel!.text = obj.name!;
    cell.detailTextLabel!.text = obj.parentName!;
    cell.indentationLevel = obj.level!;
    cell.indentationWidth = indendationWidth;
    // Configure the cell...
    // Show disclosure only if the cell can expand
    if(obj.canBeExpanded)
    {
        cell.accessoryView = self.viewForDisclosureForState(obj.isExpanded)
    }
    else
    {
        //cell.accessoryType = UITableViewCellAccessoryNone;
        cell.accessoryView = nil;
    }

    return cell
}

func viewForDisclosureForState(isExpanded:Bool)->UIView{

    var imageName:String = ""
    if(isExpanded)
    {
        imageName = "ArrowD_blue";
    }
    else
    {
        imageName = "ArrowR_blue";
    }
    let view = UIView(frame: CGRectMake(0, 0, 40, 40))
    let imageView = UIImageView(image: UIImage(named: imageName))
    imageView.frame = CGRectMake(0, 6, 24, 24)
    view.addSubview(imageView)
    return view
}

func fetchChildrenforParent(parentProduct:AMPGenericObject){

    // If canBeExpanded then only we need to create child
    if(parentProduct.canBeExpanded)
    {
        // If Children are already added then no need to add again
        if(parentProduct.children.count > 0){
        return
        }
        // The children property of the parent will be filled with this objects
        // If the parent is of type region, then fetch the location.
        if (parentProduct.type == 0) {
            for i in 0..<10
            {
                let prod = AMPGenericObject()
                prod.name = "Location \(i)"
                prod.level  = parentProduct.level! + 1;
                prod.parentName = "Child \(i) of Level \(prod.level!)"
                // This is used for setting the indentation level so that it look like an accordion view
                prod.type = 1 //OBJECT_TYPE_LOCATION;
                prod.isExpanded = false;

                if(i % 2 == 0)
                {
                    prod.canBeExpanded = true
                }
                else
                {
                    prod.canBeExpanded = false
                }
                parentProduct.children.append(prod)
            }
        }
            // If tapping on Location, fetch the users
        else{

            for i in 0..<10
            {
                let prod = AMPGenericObject()
                prod.name = "User \(i)"
                prod.level  = parentProduct.level! + 1;
                prod.parentName = "Child \(i) of Level \(prod.level!)"
                // This is used for setting the indentation level so that it look like an accordion view
                prod.type = 1 //OBJECT_TYPE_LOCATION;
                prod.isExpanded = false;
                // Users need not expand
                prod.canBeExpanded = false
                parentProduct.children.append(prod)
            }
        }

    }
}

func collapseCellsFromIndexOf(prod:AMPGenericObject,indexPath:NSIndexPath,tableView:UITableView)->Void{

    // Find the number of childrens opened under the parent recursively as there can be expanded children also
    let collapseCol = self.numberOfCellsToBeCollapsed(prod)
    // Find the end index by adding the count to start index+1
    let end = indexPath.row + 1 + collapseCol
    // Find the range from the parent index and the length to be removed.
    let collapseRange =  Range(start: indexPath.row+1, end: end)
    // Remove all the objects in that range from the main array so that number of rows are maintained properly
    dataArray.removeRange(collapseRange)
    prod.isExpanded = false
    // Create index paths for the number of rows to be removed
    var indexPaths = [NSIndexPath]()
    for i in 0..<collapseRange.count {
        indexPaths.append(NSIndexPath.init(forRow: collapseRange.startIndex+i, inSection: 0))
    }
    // Animate and delete
    tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Left)

}

func expandCellsFromIndexOf(prod:AMPGenericObject,indexPath:NSIndexPath,tableView:UITableView)->Void{

    // Create dummy children
    self.fetchChildrenforParent(prod)


    // Expand only if children are available
    if(prod.children.count>0)
    {
        prod.isExpanded = true
        var i = 0;
        // Insert all the child to the main array just after the parent
        for prodData in prod.children {
            dataArray.insert(prodData, atIndex: indexPath.row+i+1)
            i++;
        }
        // Find the range for insertion
        let expandedRange = NSMakeRange(indexPath.row, i)

        var indexPaths = [NSIndexPath]()
        // Create index paths for the range
        for i in 0..<expandedRange.length {
            indexPaths.append(NSIndexPath.init(forRow: expandedRange.location+i+1, inSection: 0))
        }
        // Insert the rows
        tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Left)
    }
}

func numberOfCellsToBeCollapsed(prod:AMPGenericObject)->Int{

    var total = 0

    if(prod.isExpanded)
    {
        // Set the expanded status to no
        prod.isExpanded = false
        let child = prod.children
        total = child.count

        // traverse through all the children of the parent and get the count.
        for prodData in child{

            total += self.numberOfCellsToBeCollapsed(prodData)
        }
    }
    return total
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    let prod = dataArray[indexPath.row]
    let selectedCell = tableView.cellForRowAtIndexPath(indexPath)

    if(prod.canBeExpanded)
    {
        if(prod.isExpanded){
        self.collapseCellsFromIndexOf(prod, indexPath: indexPath, tableView: tableView)
        selectedCell?.accessoryView = self.viewForDisclosureForState(false)
        }
        else{
            self.expandCellsFromIndexOf(prod, indexPath: indexPath, tableView: tableView)
            selectedCell?.accessoryView = self.viewForDisclosureForState(true)
        }
    }

}

}

我特别感谢用户 anoopm,我丢失了任何人拥有的存储库的链接,把它放在这里很好,顺便感谢您阅读本文

于 2016-06-03T16:51:02.367 回答