如何将 UITableView 放入 UIView
Posted
技术标签:
【中文标题】如何将 UITableView 放入 UIView【英文标题】:How to put UITableView inside a UIView 【发布时间】:2015-08-23 00:03:02 【问题描述】:我正在尝试在 UIView 中实现表格视图。我目前正在努力解决的一个问题是链接委托和数据源。如果我取消注释 Xcode 下面的两行会给出“预期声明”错误。如果我从文档大纲中链接它们,Xcode 说没问题,但是模拟会崩溃。如果有人能解决这个问题,那就太好了。
谢谢!
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
【问题讨论】:
我给你举个例子,等一下 快速提问,或者说真正的观察,将它放入 UIView 的目的是什么?可以将它放在 uiview 中,但您不需要将委派的内容粉碎到视图中。你需要在你的 UIViewConitroller 或 UITableViewContrioller 中调用 UIView 的 tableView 来控制这个视图,如果没有某种控制器,你就不能有一个独立的视图。所以,委托方法在 UIView 中有点没用,除非你真的需要它们,但这是一个很长的范围,而且是一些我认为你不打算的高级编码/ 我正在为游戏构建一个得分表应用程序。当用户点击 UIViewController 中的详细信息按钮时,我想显示一个动画 UIView。这个视图会有一个表格,显示前几轮比赛和球员的得分等。所以是的,这个类是用于自定义 UIView 的,它位于 UIViewController 内。顺便说一句,谢谢 触摸 uiviewcontroller 按钮弹出的视图应该是一个 uiviewcontroller 本身,它为 uitableview 提供数据,我会告诉你,很简单 任何需要控制内容的东西都应该是控制器,而不是视图,这是 MVC 的东西,控制器控制信息,视图只控制视图、布局、颜色等。最好做这是第一次正确的方式 【参考方案1】:这是一个完整的项目,它有效。弹出第一个视图控制器,您会看到一些按钮,我只是使用了一个带有一些随机名称的 tableview,您单击名称,然后弹出另一个 tableview,其标题与您在第一个视图上单击的单元格名称相同控制器。这通过使用块来工作,在 UIView 中没有委托,但我将所有内容都放在自定义视图中,除了使用“loadView”方法创建的第一个 viewcontroller 视图。正如你所看到的,没有数据从 UIView 传递到 UITableViewCells,你不这样做,你从第一个视图控制器的单元格中提取所有数据,并假设第一个视图控制器的表格单元格有大量的数据形式一个 JSON 数组或类似的东西,然后您可以通过属性声明变量将整个“分数数组”传递给下一个视图控制器,我只是向您展示如何使用 UIViewController 的“标题”属性传递信息,您可以创建您自己的属性并在单击单元格按钮或常规按钮时传递整个数组。您不想将此信息放入您的子类 tableViewCell 中,但您可以从 secondViewController 的 cellForRowAtIndexPath 传递数据来为第二页上的记分牌设置自定义信息,UIVeiw 可以接受 UIViewController 的要求,而不是反过来,您使用自定义 UITableView 向 UIView 发送命令,并且自定义 UITableView 的数据由 UIViewController 设置。这是做事的正确方法。为了使这个超级健壮,可以在这个示例中添加更多内容,但想法是这样的:
示例 1: UIViewController1
button1 ==> UIViewController 从网络中提取信息或告诉 UIView 从网络中提取该信息存储在您制作的自定义 UIButton 中,其中包含数据数组
button2 ==> UIViewController 从网络中提取信息或告诉 UIView 从网络中提取此信息,这些信息存储在您制作的自定义 UIButton 中,其中包含数据数组
button3 ==> UIViewController 从网络中提取信息或告诉 UIView 从网络中提取此信息,这些信息存储在您制作的自定义 UIButton 中,其中包含数据数组
UIViewcontroller2 UITableView 将您存储在上面数组中的每个按钮的数据传递给 secondViewController 然后填充表格,这就是它的工作原理。
示例 2: UIViewController1
button1 ==> UIViewController 只是给 UIButton 添加一个动作事件
button2 ==> UIViewController 只是给 UIButton 添加了一个动作事件
button3 ==> UIViewController 只是给 UIButton 添加一个动作事件
UIViewcontroller2 自定义方法中的 TableView 调用网络并根据 UIViewcontroller1 中按钮的标题填充数据数组,该数组通过使用从第二个视图控制器中的 viewdidload 调用的自定义方法被粉碎到第二个视图控制器中,然后,第二个视图控制器调用它自己的视图,该视图已被类型转换为带有 UITableView 的自定义 UIView 子类。这个 UIViewController2 然后调用“cellForRowAtIndexPath”并使用单元格上的 setter 方法填充表格,从而强制数据进入 UITableView
在这两种方法中,我们在自定义视图中设置了多少个委托?零,因为 UIViewControllers 应该负责设置数据并向下发送,除非 UIViewController 明确要求,否则 UIView 不应该向上发送数据:
工作简单的例子(程序化,没有故事板,所以你可以看到发生了什么):
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
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
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
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
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 ()
如上所述,位于自定义 UIView 中的 UITableView 已死,直到 UIViewController 告诉视图它没有死。这就是 MVC 应该如何工作的,事实上,为了补充这一点,我会亲自添加一些东西以使这一点更加明显。
1. ViewController.swift 的另一个自定义 UIView
2。 SecondViewController.swift 的另一个自定义 UITableViewCell
3.第一组 Button 数据的对象模型,这是一个 NSObject 子类,这是第一个 viewController 屏幕上的“按钮”数据
4.另一个对象模型(也许)对“分数”数据中的第二组数据进行建模
5. UILabel 的 2 个自定义子类
6. UIButton 的 2 个自定义子类
UIView 子类在上面的 5 和 6 中声明了子类 UIElement 的 AS 属性,因此 5 和 6 只控制它们自己,并且 UIView 有点像它们的直接父级,作为 UIView 本身的属性。
在这个项目结束时,我会为每个 ViewController 拥有大约 5-10 个 swift 子类,甚至可能更多(使用 ObjC,它会是这个大小的两倍)。子视图的父类只控制子视图的内容和属性,从不控制父视图的内容,ios就是这样设计的,封装了从UIViewController向下延伸的“数据喋喋不休”的流程,而不是其他方式。
无论如何,祝你在 Swift 冒险中好运,我也在学习 Swift,因为我回答了这样的问题并将密集和高级的 ObjC 代码翻译成 Swift。如果您还有其他问题,请询问。谢谢,祝你好运!
【讨论】:
感谢您的广泛反馈。我意识到了这个问题,并且对 MVC 有了更好的理解。正如您所说,我已将更改应用于我的代码,现在可以正常运行,但是,当我点击按钮时,我的表是空的。 这是我所做的:CustomViewClass:@IBOutlet weak var tableView: UITableView!
ViewController: self.detailsView.tableView.delegate = self self.detailsView.tableView.dataSource = self
在 viewDidLoad 和下面的部分 func tableView(tableView: UITableView, numberOfRowsInSection... func tableView(tableView: UITableView, cellForRowAtIndexPath ...
这样代码工作没有错误,但表格单元格由于某种原因不显示任何数据。
让我看看发生了什么事,给我几个小时,我会为你重新发布一些东西
你好 Larcerax 。我不在城里,仍然无法查看为什么我的表格视图加载空单元格的问题,但再次感谢您的支持!如果我能解决问题,我会添加评论。
是的,给我几个小时以上是关于如何将 UITableView 放入 UIView的主要内容,如果未能解决你的问题,请参考以下文章
将 UITableViewController 插入其他 UIView
如何将 UITableView 作为子视图添加到 xib 中的 UIView?
Swift:UIView 出现在 UITableView 单元格中