简体   繁体   English

如何将UITableView放在UIView中

[英]How to put UITableView inside a UIView

I'm trying to implement a table view inside a UIView. 我正在尝试在UIView中实现一个表视图。 One problem I'm currently struggling with is linking delegate and dataSource. 我目前正在努力解决的一个问题是链接委托和dataSource。 If I uncomment two lines below Xcode gives an "expected declaration" error. 如果我取消注释Xcode下面的两行,则会出现“预期声明”错误。 If I link them from document outline Xcode says okay but then simulation crashes. 如果我从文档大纲中链接它们Xcode说没关系然后模拟崩溃。 It would be great if someone can figure out the problem. 如果有人能够找出问题,那就太好了。

Thanks! 谢谢!

import UIKit
class CurrentGameDetailView: UIView, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!
    var theGame: GameObject? = nil

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return theGame!.roundNumber
    }

//    tableView.delegate = self
//    tableView.dataSource = self

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("OldGameDetailCell", forIndexPath: indexPath) as! OldGameDetailCell

        cell.roundLabel.text = theGame!.gameRounds[indexPath.row].gamePlayed.description
        ...

        return cell
    }
}

Here's the shake down, full project, and it works. 这是震撼,完整的项目,它的工作原理。 The first view controller pops up, you see some buttons, I just used a tableview with some random names, you click the names, and another tableview pops up with the title of the table the same name as the cell you clicked on the first view Controller. 第一个视图控制器弹出,你看到一些按钮,我只是使用带有一些随机名称的tableview,你点击名称,然后弹出另一个tableview,表格的标题与你在第一个视图上点击的单元格相同控制器。 This works through using blocks, no delegation in the UIView, but I put everything in a custom view except for the first viewcontroller's view which is created with the "loadView" method. 这通过使用块来实现,UIView中没有委托,但我将所有内容放在自定义视图中,除了使用“loadView”方法创建的第一个viewcontroller视图。 As you can see, no data is passed from the UIView into the UITableViewCells, you don't do it this way, you pull in all data from the first view controller's cells and assuming that the first viewcontroller's table cells have a TON of data form a JSON array or something like this then you can pass that entire "scores array" to the next view controller through a property declaration variable, I'm just showing you how to pass information using the "title" property of a UIViewController, you can create your own properties and pass an entire array when the button of a cell or regualr button is clicked. 如您所见,没有数据从UIView传递到UITableViewCells,您不这样做,您从第一个视图控制器的单元格中提取所有数据,并假设第一个viewcontroller的表格单元格具有TON数据形式一个JSON数组或类似的东西然后你可以通过属性声明变量将整个“得分数组”传递给下一个视图控制器,我只是告诉你如何使用UIViewController的“title”属性传递信息,你可以创建自己的属性,并在单击单元格或regualr按钮的按钮时传递整个数组。 You don't want to put this information into you Subclassed tableViewCell, but you can PASS data from the secondViewController's cellForRowAtIndexPath to set custom information for the scoreboard that is on the second page, the UIVeiw is there to ACCEPT the demands of the UIViewController, not the other way around, you send commands to the UIView with the custom UITableView and the custom UITableView's data is set by the UIViewController. 您不希望将此信息放入Subclassed tableViewCell,但是您可以从secondViewController的cellForRowAtIndexPath传递数据来为第二页上的记分板设置自定义信息,UIVeiw可以接受UIViewController的需求,而不是相反,您使用自定义UITableView将命令发送到UIView,并且UIViewController设置自定义UITableView的数据。 This is the correct way to do things. 这是做事的正确方法。 There's much much more that could be added to this example to make this super robust, but the idea is this: 还有更多可以添加到这个例子来使这个超级健壮,但这个想法是这样的:

Example 1: UIViewController1 示例1: UIViewController1

button1 ==> UIViewController pulls information from network or tells the UIView to pull from network this information is stored in the custom UIButton that you make that holds an ARRAY of data button1 ==> UIViewController从网络中提取信息或告诉UIView从网络中提取此信息存储在您拥有的包含ARRAY数据的自定义UIButton中

button2 ==> UIViewController pulls information from network or tells the UIView to pull from network this information is stored in the custom UIButton that you make that holds an ARRAY of data button2 ==> UIViewController从网络中提取信息或告诉UIView从网络中提取此信息存储在您拥有的包含ARRAY数据的自定义UIButton中

button3 ==> UIViewController pulls information from network or tells the UIView to pull from network this information is stored in the custom UIButton that you make that holds an ARRAY of data button3 ==> UIViewController从网络中提取信息或告诉UIView从网络中提取此信息存储在您拥有的包含ARRAY数据的自定义UIButton中

UIViewcontroller2 UITableView the data for each button that you stored in the array above is passed to the secondViewController and then populates the table, this is how it works. UIViewcontroller2 UITableView将存储在上面数组中的每个按钮的数据传递给secondViewController,然后填充表,这就是它的工作原理。

Example 2: UIViewController1 示例2: UIViewController1

button1 ==> UIViewController just adds an action event to the UIButton button1 ==> UIViewController只是向UIButton添加一个动作事件

button2 ==> UIViewController just adds an action event to the UIButton button2 ==> UIViewController只是向UIButton添加一个动作事件

button3 ==> UIViewController just adds an action event to the UIButton button3 ==> UIViewController只是向UIButton添加一个动作事件

UIViewcontroller2 TableView in a custom method calls the network and populates an array of data based on the title of the Buttons in UIViewcontroller1, this array is smashed into the second view controller by using a custom method that is called from your viewdidload in the second view controller, then, this second viewcontroller calls to its own view which has been typecast to the custom UIView subclass with a UITableView. UIViewcontroller2自定义方法中的TableView调用网络并根据UIViewcontroller1中按钮的标题填充数据数组,通过使用从第二个视图控制器中的viewdidload调用的自定义方法将此数组粉碎到第二个视图控制器中然后,第二个viewcontroller调用它自己的视图,该视图使用UITableView对自定义UIView子类进行了类型转换。 This UIViewController2 then calls to "cellForRowAtIndexPath" and populates the table with setter methods on the cell, thereby forcing data into the UITableView 然后,这个UIViewController2调用“cellForRowAtIndexPath”并在单元格上用setter方法填充表,从而强制数据进入UITableView

IN both methods, how many delegates did we set up in a custom view? 在这两种方法中,我们在自定义视图中设置了多少个代理? ZERO, because the UIViewControllers should be in charge of setting the data and sending it downward, a UIView should never send data upward unless specifically asked to by the UIViewController: ZERO,因为UIViewControllers应该负责设置数据并向下发送,UIView绝不应该向上发送数据,除非UIViewController特别要求:

Working simple example (programmatic, no storyboards, so you can see what's going on): 工作简单的例子(程序化,没有故事板,所以你可以看到发生了什么):

AppDelegate.swift: AppDelegate.swift:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var rootViewController: UINavigationController?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        rootViewController = UINavigationController(rootViewController: ViewController())
        if let window = window {
            window.backgroundColor = UIColor.whiteColor()
            window.rootViewController = rootViewController
            window.makeKeyAndVisible()
        }
        return true
    }
}

ViewController.swift ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var tableView : UITableView?
    var items = [
        "Ginger",
        "larry",
        "Moe",
        "Fred",
        "Terry"]

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView = UITableView(frame: CGRectMake(0, 0, 414, 736), style: UITableViewStyle.Plain)
        tableView!.delegate = self
        tableView!.dataSource = self
        tableView!.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
        self.view .addSubview(tableView!)
    }
    override func loadView() {
        var stuf = UIView()
        stuf.frame = CGRectMake(0, 0, 414, 736)
        stuf.backgroundColor = UIColor .redColor()
        self.view = stuf
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count;
    }
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat {
        return 44
    }   
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomTableViewCell
        cell.doWork = {
            () -> Void in
            self.doStuff(indexPath.row)
        }
        cell.labelMessage.text = items[indexPath.row] as String
        return cell
    }
    func doStuff(integer: NSInteger) {
        var newViewController = SecondViewController()
        newViewController.title = items[integer] as String
        var dismissButton = UIBarButtonItem(title: "done", style: UIBarButtonItemStyle.Plain, target: self, action: "dismiss")
        newViewController.navigationItem.rightBarButtonItem = dismissButton
        var navControl =  UINavigationController(rootViewController: newViewController);
        self.navigationController?.presentViewController(navControl, animated: true, completion: { () -> Void in })
    }
    func dismiss() {
        self.navigationController?.dismissViewControllerAnimated(true, completion: { () -> Void in})
    }
}

SecondViewController.swift SecondViewController.swift

import UIKit

class SecondViewController: UIViewController , UITableViewDataSource, UITableViewDelegate {

    var items = [
        "sports score1",
        "sports score2",
        "sports score3",
        "sports score4",
        "sports score5"]

    var myView: CustomViewWithTableView! {
        return self.view as! CustomViewWithTableView
    }
    override func loadView() {
        let height = self.navigationController!.navigationBar.frame.size.height as CGFloat

        view = CustomViewWithTableView(frame: CGRectMake(0, height, UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height-height as CGFloat))
    }
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        self.myView.tableView.delegate = self
        self.myView.tableView!.dataSource = self
        self.myView.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count;
    }
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat {
        return 44
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
        cell.textLabel!.text =  items[indexPath.row] as String
        return cell
    }
}

CustomViewWithTableView.swift CustomViewWithTableView.swift

import Foundation
import UIKit

class CustomViewWithTableView: UIView {

    var tableView: UITableView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        tableView = UITableView(frame: CGRectMake(frame.origin.x, frame.origin.y, frame.width, frame.height), style: .Plain)
        self.addSubview(tableView)
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

CustomTableViewCell.swift CustomTableViewCell.swift

import Foundation
import UIKit

class CustomTableViewCell: UITableViewCell, UIGestureRecognizerDelegate {

    var labelMessage = UILabel()

    var doWork: (() -> Void)?

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        let touchie: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "this")
        touchie.delegate = self
        touchie.cancelsTouchesInView = false
        self.addGestureRecognizer(touchie)
        labelMessage.setTranslatesAutoresizingMaskIntoConstraints(false)
        contentView.addSubview(labelMessage)

        //custom layout constraints
        var viewsDict =  ["labelMessage" : labelMessage]

        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[labelMessage]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[labelMessage]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))

    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

   //custom touch interceptor for presentation navigation
    func this () {
        if let callback = self.doWork {
            println("swipe detected, cell function run")
            callback ()
        }
    }

}

As I stated above, the UITableView that sits in the custom UIView is dead until the UIViewController tells the view that it's not dead. 正如我上面所说,位于自定义UIView中的UITableView已经死了,直到UIViewController告诉视图它没有死。 This is how MVC should work, and in fact, to add on to this, there's a few things that I would add personally to make the point even more pronounced. 这就是MVC应该如何工作,事实上,除此之外,还有一些我个人会添加的东西,以使这一点更加明显。

1. Another Custom UIView for the ViewController.swift 1. ViewController.swift的另一个自定义UIView

2. Another Custom UITableViewCell for the SecondViewController.swift 2. SecondViewController.swift的另一个自定义UITableViewCell

3. An object Model for the first set of Button data, this is an NSObject subclass, this is the "button" data on the first viewController's screen 3.第一组Button数据的对象模型,这是一个NSObject子类,这是第一个viewController屏幕上的“按钮”数据

4. Another object model (perhaps) to model the second set of data in the "scores" data 4.另一个对象模型(可能),用于对“得分”数据中的第二组数据进行建模

5. 2 custom subclasses of UILabel 5. 2个UILabel的自定义子类

6. 2 custom subclasses of UIButton 6. UIButton的2个自定义子类

The UIView subclasses declare AS properties the subclassed UIElements in 5 and 6 above, so 5 and 6 control just themself and the UIViews are sort of like their immediate parent as a property of the UIView itself. UIView子类在上面的5和6中声明AS属性是子类UIElements,因此5和6只控制它们自己,UIViews就像它们的直接父类一样,是UIView本身的属性。

At the end of this project, I would have, for each ViewController around 5-10 subclasses with swift and possibly more (with ObjC it would be double this size). 在这个项目的最后,我会为每个ViewController提供大约5-10个带有swift和可能更多的子类(使用ObjC,它将是这个大小的两倍)。 The parent class of the subViews only control the content of their subViews and properties, and NEVER control the content of the Parent view, this is how IOS was designed, encapsulation with the flow of "data chatter" extending downward from the UIViewController and not the other way around. subViews的父类只控制其子视图和属性的内容,并且永远不会控制父视图的内容,这就是IOS的设计方式,封装了从UIViewController向下延伸的“数据聊天”流而不是其他方式。

Anyway, good luck in your Swift adventures, I'm also learning Swift as I answer questions like this and translate intense and advanced ObjC code to Swift. 无论如何,在你的Swift冒险中好运,我也在学习Swift,因为我回答这样的问题并将强烈和高级的ObjC代码翻译成Swift。 Should you have additional questions, then please ask. 如果您有其他问题,请询问。 Thanks and good luck! 谢谢,祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM