Swift - 自定义 SectionIndexTitles 在 Tableview 中不起作用

Swift - Custom SectionIndexTitles not working in Tableview

我有一个 UISplitViewController,我用 UIViewController 替换了其中的 UITableView。这个 ViewController 包含一个 UITableView 和一个 UIView。 UIView 包含我的自定义 SectionIndexTitles UIControl,以滚动到正确的部分。

我的自定义 SectionIndexTitles UIControl 在带有 UICollectionView 的 ViewController 中完美工作,但不知何故它在前面提到的配置中不起作用。我该如何解决这个问题?

应用程序编译并且没有崩溃。当我擦洗 UIControl 时,不会调用 indexViewValueChanged() 函数。我已经使用 View Debugger 检查了 View 层次结构,但它位于 TableView 之上。我还尝试添加一个手势识别器,它确实有效。最后我尝试设置 zPosition,但这没有任何效果。

Github example

ViewController

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var indexTitlesContainer: UIView!

    /* type to represent table items
    `section` stores a `UITableView` section */
    class User: NSObject {
        let name: String
        var section: Int?

        init(name: String) {
            self.name = name
        }
    }

    // custom type to represent table sections
    class Section {
        var users: [User] = []

        func addUser(user: User) {
            self.users.append(user)
        }
    }

    // raw user data
    let names = [
        "Clementine",
        "Tim",
        "Bessie",
        "Yolande",
        "Tynisha",
        "Ellyn",
        "Trudy",
        "Fredrick",
        "Letisha",
        "Ariel",
        "Bong",
        "Jacinto",
        "Dorinda",
        "Aiko",
        "Loma",
        "Augustina",
        "Margarita",
        "Jesenia",
        "Kellee",
        "Annis",
        "Charlena"
    ]

    // `UIKit` convenience class for sectioning a table
    let collation = UILocalizedIndexedCollation.currentCollation()


    // table sections
    var sections: [Section] {
        // return if already initialized
        if self._sections != nil {
            return self._sections!
        }

        // create users from the name list
        let users: [User] = names.map { name in
            let user = User(name: name)
            user.section = self.collation.sectionForObject(user, collationStringSelector: "name")
            return user
        }

        // create empty sections
        var sections = [Section]()
        for i in 0..<self.collation.sectionIndexTitles.count {
            sections.append(Section())
        }

        // put each user in a section
        for user in users {
            sections[user.section!].addUser(user)
        }

        // sort each section
        for section in sections {
            section.users = self.collation.sortedArrayFromArray(section.users, collationStringSelector: "name") as! [User]
        }

        self._sections = sections

        return self._sections!

    }
    var _sections: [Section]?

    var indexTitles: IndexTitles!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        indexTitles = IndexTitles(frame: CGRectZero, indexTitles: collation.sectionIndexTitles)

        indexTitles.addTarget(self, action: "indexViewValueChanged:", forControlEvents: .ValueChanged)
        indexTitlesContainer.addSubview(indexTitles)

    }

    func indexViewValueChanged(sender: IndexTitles) {
        print("perform function")
        var index = sender.index

        if self.sections[index].users.count == 0 {

            var shouldPerform = true

            for var i = index as Int; i < self.sections[index].users.count; i++ {
                if shouldPerform == true {
                    if self.sections[index].users.count != 0 {
                        shouldPerform = false
                        index = i
                    }
                }
            }

            for var i = index as Int; i > 0; i-- {
                if shouldPerform == true {
                    if self.sections[index].users.count != 0 {
                        shouldPerform = false
                        index = i
                    }
                }
            }
        }

        let path = NSIndexPath(forRow: 0, inSection: index)
        tableView.scrollToRowAtIndexPath(path, atScrollPosition: .Top, animated: false)

        let scrollPosition = tableView.contentOffset.y
        let collectionViewHeight = (tableView.contentSize.height - tableView.bounds.size.height) + 54

        if scrollPosition != collectionViewHeight {
            tableView.contentOffset = CGPoint(x: tableView.contentOffset.x, y: tableView.contentOffset.y - 22.0)
        }

    }

    override func viewDidLayoutSubviews() {
        let height = CGFloat(collation.sectionIndexTitles.count * 18)
        let y = (indexTitlesContainer.bounds.height - height) / 3
        indexTitles.frame = CGRectMake(0, y, indexTitlesContainer.bounds.width, height)

    }

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


}

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

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.sections[section].users.count
    }

    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return collation.sectionIndexTitles[section]
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let user = self.sections[indexPath.section].users[indexPath.row]

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        cell.textLabel!.text = user.name
        cell.backgroundColor = UIColor.clearColor()
        return cell
    }
}

自定义 UIControl

import UIKit

class IndexTitles: UIControl,UIGestureRecognizerDelegate {

    var indexTitles:NSArray!
    var visualEffect: UIVisualEffectView!
    var index:Int!

    func translate(touch:CGFloat) {
        let selectedIndex = Int(touch / 18)
        let indexCount = indexTitles.count - 1

        if selectedIndex < 0 {
            index = 0
        }
        else if selectedIndex > indexCount {
            index = indexCount
        }
        else {
            index = selectedIndex
        }

        sendActionsForControlEvents(.ValueChanged)
    }

    //Sets the right index when the label is selected.
    override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
        translate(touch.locationInView(self).y)
        return true
    }

    override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
        translate(touch.locationInView(self).y)
        return true
    }

    //Setup for when the view is being initialized.
    init(frame: CGRect, indexTitles:NSArray) {
        super.init(frame: frame)
        self.indexTitles = indexTitles

        let multiplier = 18

        visualEffect = UIVisualEffectView(frame: CGRectMake(0, 0, 18, CGFloat(multiplier * indexTitles.count)))
        visualEffect.effect = UIVibrancyEffect(forBlurEffect: UIBlurEffect(style: .ExtraLight))
        self.addSubview(visualEffect)

        for var i = 0; i < indexTitles.count; i++ {
            let label = UILabel(frame: CGRectMake(0, CGFloat(multiplier * i) , 20 , 18))
            label.font = UIFont.systemFontOfSize(12, weight: UIFontWeightSemibold)
            label.numberOfLines = 0
            label.textAlignment = .Center
            label.text = indexTitles[i] as? String
            visualEffect.contentView.addSubview(label)
        }

    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }


}

在 UIControl 中,子视图 UserInteractionEnabled 必须设置为 false