主要学习与运行效果

在本节的内容中,我们将通过一个具体实例的实现过程,详细讲解在表视图当中,如何创建一个可展开可收缩的表视图。为了让读者有着更为直观的印象,我们将通过模仿QQ好友列表来实现这个效果。

该示例主要演示:

1.表视图外观设计

2.自定义用户组设计

3.从plist文件中读取数据

4.将数据显示在表视图中

5.实现表格的展开、收缩效果

运行效果如下所示:

表视图外观设计

我们使用Single View Application模板创建一个swift项目,命名为Friend List,为了简便起见,Devices我们选择iPhone进行开发。

打开Main.storyboard文件,删除View Controller Scene,从Xcode右下方的Object Library面板中将Navagation Controller拖动到故事板中,如下图所示:

Navigation Controller Scene包含了两个视图,一个是导航视图,一个是表视图。选中Navagation Controller Scene,取消Use Size Classes选项,勾选Is Initial View Controller选项,将其作为初始视图控制器运行。

设置完成后,故事板将如下图所示:

选 中Root View Controller的导航栏,修改其标题为“联系人”。完成此操作后,选择Table View中的Table View Cell,在Identifier项中输入:FriendCellIdentifier来为其增加标识符。对于Xcode来说,每一种表视图单元格都需要 声明其标识符,以让Xcode能够对其进行定位。如图所示:

此时的单元格高度还比较窄,为了能够达到我们想要的结果,我们需要设置其高度,同时也因为其高度固定,因此我们定位到单元格的Size inspector中,将Row Height设置为66(或者其他你看起来舒服的值)。如图所示:

向单元格中添加一个Image控件,两个Label控件,以完成粗略的QQ好友信息设计。设计效果如下图所示:

由于我们创建了一个自定义的表视图单元格,因此我们最好为其创建一个专门的类来定义其结构,以便以后能够借用此数据结构来保存从文件中读取的信息。

创建一个Friend.swift文件,文件内容如下:

  1. import UIKit
  2. class Friend: NSObject {
  3.     var Avatars: String =  "user_default"   // 图片名称,定义朋友的头像
  4.     var Name: String = ""           // 字符串,定义朋友的名字
  5.     var Intro: String = ""            // 字符串,定义朋友的个性签名
  6.     var VIP: Bool = false     // 布尔值,确定朋友是否为VIP
  7. }

其中,user_default文件为用户默认头像,已经放置在Image.xcassets中,用户可以自行添加你喜爱的头像并放置在xcassets中。

然后我们创建一个FriendCell.swift文件,这个文件将和我们刚刚创建的那个单元格进行绑定。文件内容如下:

  1. import UIKit
  2. class FriendCell: UITableViewCell {
  3.     @IBOutlet weak var ImgAvatars: UIImageView!
  4.     @IBOutlet weak var LblName: UILabel!
  5.     @IBOutlet weak var LblIntro: UILabel!
  6.     var friend: Friend = Friend()
  7.     // 设置朋友信息
  8.     func setFriend(newfriend: Friend) {
  9.         var Image: UIImage? = UIImage(named: "\(newfriend.Avatars)")
  10.         if Image != nil {
  11.             ImgAvatars.image = Image!
  12.         }else{
  13.             ImgAvatars.image = UIImage(named: "user_default")
  14.         }
  15.         LblName.text = newfriend.Name
  16.         LblIntro.text = newfriend.Intro
  17.         if friend.VIP {
  18.             LblName.textColor = UIColor.redColor()
  19.         }else{
  20.             LblName.textColor = UIColor.blackColor()
  21.         }
  22.     }
  23. }

其中,ImgAvatars与单元格中的Image控件进行绑定,LblName和LblIntro分别与单元格中的两个Label控件进行绑定。注意此时单元格的Identify inspector中的Class要设置为我们刚刚创建的FriendCell类。

接下来的代码就比较直观。这里我们对头像的读取进行了一个可选值的判定。首先先根据记录中的头像名称去读取存储好的头像。如果没有读取成功,那么Image变量将会返回一个nil值,这时就将头像设置为我们默认的头像:user_default。

自定义用户组设计

在iOS应用中,我们可以自定义表视图单元格的风格,其实原理就是向单元格中添加子视图。添加子视图的方法主要有三种:使用代码、从.xib文件加载以及直接使用storyboard进行设计。在上一节中我们就是使用storyboard进行设计,非常方便和直观。

在本节自定义用户组中,我们要设计单元格折叠后的父类单元格。出于代码的简便和直观起见,同时为了也为了让读者尽可能多的掌握自定义表视图的方法,因此这里我们采用.xib文件进行加载。

新建一个xib文件,依次选择New File -> iOS -> User Interface -> Empty,命名为SectionHeaderView

。这样我们就创建了一个xib文件。由图中可以看到,xib文件和storyboard的区别并不是很大。简单理解来说,可以把StoryBoard看做是一组viewController对应的xib,以及它们之间的转换方式的集合。

我 们强烈建议大家采用storyboard进行界面设计,因为storyboard是iOS 5之后苹果提供的以及强烈建议开发者使用的配置。但是,由于storyboard中已经不允许有单个view的存在,因此在某些时候我们还是需要借助于单 个的xib来自定义UI。这是由于storyboard的设计理念造成的。storyboard重视层次结构,重视UI的架构和设计,更重视项目的流程。 而对于单个的UI来说,则更注重于重用和定制。

向xib界面中拖入一个View,将其Attributes inspector中的Size修改为Freeform(允许调整View的大小),Status Bar修改为None(取消状态栏显示)。

向view中拖入一个Button控件和Label控件,适当调整大小,如图所示:

这时我们同样需要创建一个类来定义这个自定义用户组的数据结构,新建一个Group.swift文件,文件内容如下:

  1. import UIKit
  2. class Group: NSObject {
  3.     var name: String = ""       // 字符串,定义组名称
  4.     var friends: NSArray = NSArray()    // 数组,定义了该组内所有朋友
  5. }

接下来,我们需要为我们自定义的表视图创建一个类来与之进行绑定。创建一个SectionHeaderView.swift文件,文件内容如下:

  1. import UIKit
  2. // 该协议将被用户组的委托实现; 当用户组被打开/关闭时,它将通知发送给委托,来告知Xcode调用何方法
  3. protocol SectionHeaderViewDelegate: NSObjectProtocol {
  4.     func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int)
  5.     func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int)
  6. }
  7. class SectionHeaderView: UITableViewHeaderFooterView {
  8.     @IBOutlet weak var LblTitle: UILabel!
  9.     @IBOutlet weak var BtnDisclosure: UIButton!
  10.     var delegate: SectionHeaderViewDelegate!
  11.     var section: Int!
  12.     var HeaderOpen: Bool = false  // 标记HeaderView是否展开
  13.     override func awakeFromNib() {
  14.         // 设置disclosure 按钮的图片(被打开)
  15.         self.BtnDisclosure.setImage(UIImage(named: "carat-open"), forState: UIControlState.Selected)
  16.         // 单击手势识别
  17.         var tapGesture = UITapGestureRecognizer(target: self, action: "btnTap:")
  18.         self.addGestureRecognizer(tapGesture)
  19.     }
  20.     @IBAction func btnTap(sender: UITapGestureRecognizer) {
  21.         self.toggleOpen(true)
  22.     }
  23.     func toggleOpen(userAction: Bool) {
  24.         BtnDisclosure.selected = !BtnDisclosure.selected
  25.         // 如果userAction传入的值为真,将给委托传递相应的消息
  26.         if userAction {
  27.             if HeaderOpen {
  28.                 delegate.sectionHeaderView(self, sectionClosed: section)
  29.             }
  30.             else {
  31.                 delegate.sectionHeaderView(self, sectionOpened: section)
  32.             }
  33.         }
  34.     }
  35. }

使用协议的原因是SectionHeaderView是我们自定义的一个视图,而且我们专门为其新建了一个类文件来进行管理。……这 个协议定义了两个方法,这两个方法名称相同,但是参数不同,被称为函数重载。在接下来我们的使用中,可以直接使用Selector选择其参数名来进行调 用。

awakeFromNib()是.nib文件被加载的时候,创建view对象前调用的方法。其和viewDidLoad()的区别是, 当view对象被加载到内存时系统才会调用viewDidLoad()方法。因此,Xcode会先执行awakeFromNib()方法,才会执行 viewDidLoad()方法。

那为什么我们要用awakeFromNib()方法呢,那是因为UITableViewHeaderFooterView里面并不存在viewDidLoad()方法,我们没有办法对其重载调用,所以只能使用awakeFromNib()方法。

由于向.xib文件中直接添加手势,会导致该nib文件注册失败,因此我们用代码的形式来定义一个单击手势。这个手势将控制单元格的展开和收缩。

最 后要注意的是,由于我们的类继承的是UITableViewHeaderFooterView,虽然在UIKit中,这个类是UIView的子类,但是由 于swift还不完善的原因,在IB面板中(包括xib文件和storyboard文件)的Identity inspector的Class项中都不能够显示出我们刚刚创建出来的类,但是我们可以手动输入这个类的名称。

此时我们仅仅只是定义了SectionHeaderView.xib的属性和方法,但是由于用户组里面会包含多个FriendCell,因此我们还要在定义一个类来标明Group和SectionHeaderView之间的结构联系。

新建一个SectionInfo.swift文件,文件内容如下:

  1. import Foundation
  2. // 定义了用户组以及FriendCell的一系列属性、方法
  3. class SectionInfo: NSObject {
  4.     var group: Group = Group()
  5.     var headerView: SectionHeaderView = SectionHeaderView()
  6. }

至此,所有的表格结构、数据结构已经定义完成,接下来就是要从数据层面进行操作了。

从plist文件中读取数据

为了方便数据管理,我们使用数据持久化功能来保存用户组信息和朋友信息。这里我们采用属性列表来保存数据。应用程序在启动时会将该文件的全部内容读入内存,并在退出时注销。

新 建一个plist文件,依次选择New File -> iOS -> Resource -> Property List,命名为FriendInfo。这样我们就创建了一个plist文件。将文件中的Property List Type修改为None,然后按照下图所示设计文件内容:

接下来打开ViewController.swift文件,创建一个函数,命名为loadFriendInfo,用来读取文件。函数如下:

  1. func loadFriendInfo() -> NSArray {
  2.     var FriendInfo: NSMutableArray?
  3.     // 定位到plist文件并将文件拷贝到数组中存放
  4.     var fileUrl = NSBundle.mainBundle().URLForResource("FriendInfo", withExtension: "plist")
  5.     var GroupDictionariesArray = NSArray(contentsOfURL: fileUrl!)
  6.     FriendInfo = NSMutableArray(capacity: GroupDictionariesArray!.count)
  7.     // 遍历数组,根据组和单元格的结构分别赋值
  8.     for GroupDictionary in GroupDictionariesArray! {
  9.         var group: Group = Group()
  10.         group.name = GroupDictionary["GroupName"] as String
  11.         var friendDictionaries: NSArray = GroupDictionary["Friends"] as NSArray
  12.         var friends = NSMutableArray(capacity: friendDictionaries.count)
  13.         for friendDictionary in friendDictionaries {
  14.             var friendAsDic: NSDictionary = friendDictionary as NSDictionary
  15.             var friend: Friend = Friend()
  16.             friend.setValuesForKeysWithDictionary(friendAsDic)
  17.             friends.addObject(friend)
  18.         }
  19.         group.friends = friends
  20.         FriendInfo!.addObject(group)
  21.     }
  22.     return FriendInfo!
  23. }

我们来逐次分析这个函数。首先我们需要定位到我们创建的FriendInfo.plist文 件,NSBundle.mainBundle中保存了一系列当前项目的信息,包括版本号、程序名等等内容,这里我们使用URLForResource() 来获取FriendInfo.plist的URL地址。

NSArray的contentsOfURL:

由此,我们就完成了从plist文件中读取数据的操作,接下来我们可以使用FriendInfo数组里面的值,来完成值的赋予。

将数据显示在表视图中

有了上面的操作,现在我们就可以将我们读取到的数据显示在表视图当中了。

我们首先定义一个类型为NSArray数组的变量,用来存放我们读取后的数据,以及存放用户组、单元格信息的NSMutableArray变量:

  1. var groups: NSArray!
  2. var sectionInfoArray: NSMutableArray!

接下来,我们在viewDidLoad()方法中添加如下语句,完成数据的读取和存放:

  1. self.tableView.sectionHeaderHeight = CGFloat(HeaderHeight)    // 用户组高度
  2. opensectionindex = NSNotFound
  3. groups = loadFriendInfo()
  4. let sectionHeaderNib: UINib = UINib(nibName: "SectionHeaderView", bundle: nil)
  5. self.tableView.registerNib(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: SectionHeaderViewIdentifier)

后面两个语句本章后面会对其详细介绍。

接下来,我们从父类视图中重写viewWillAppear方法,来完成分组表的定义。

  1. override func viewWillAppear(animated: Bool) {
  2.     super.viewWillAppear(animated)
  3.     // 检查SectionInfoArray是否已被创建,如果已被创建,则检查组的数量是否匹配当前实际组的数量。通常情况下,您需要保持SectionInfo与组、单元格信息保持同步。如果扩展功能以让用户能够在表视图中编辑信息,那么需要在编辑操作中适当更新SectionInfo
  4.     if sectionInfoArray == nil || sectionInfoArray.count != self.numberOfSectionsInTableView(self.tableView) {
  5.         // 对于每个用户组来说,需要为每个单元格设立一个一致的SectionInfo对象
  6.         var infoArray: NSMutableArray = NSMutableArray()
  7.         for group in groups {
  8.             var dictionary: NSArray = (group as Group).friends
  9.             var sectionInfo = SectionInfo()
  10.             sectionInfo.group = group as Group
  11.             sectionInfo.headerView.HeaderOpen = false
  12.             infoArray.addObject(sectionInfo)
  13.         }
  14.         sectionInfoArray = infoArray
  15.     }
  16. }

接下来依次实现这几个方法:

  1. override func canBecomeFirstResponder() -> Bool {
  2.     return true
  3. }

判断一个对象是否可以成为第一响应者。默认返回false。

如果一个响应对象通过这个方法返回true,那么它成为了第一响应对象,并且可以接收触摸事件和动作消息。

我们的UITableView是UIView的子类,因此必须重写这个方法才可以成为第一响应者。

  1. override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
  2.     return self.groups.count
  3. }

numberOfSectionsInTableView()方法返回表视图有多少个section。一个用户组对应一个section。

  1. override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  2.     var sectionInfo: SectionInfo = sectionInfoArray[section] as SectionInfo
  3.     var numStoriesInSection = sectionInfo.group.friends.count
  4.     var sectionOpen = sectionInfo.headerView.HeaderOpen
  5.     return sectionOpen ? numStoriesInSection : 0
  6. }

tableView:numberOfRowsInSection:方法返回对应的section中有多少个元素,也就是多少行。在这里我们先确定用户组是否被打开,如果打开则返回对应的用户组中的所有朋友数量,否则为0。

  1. override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  2.     let FriendCellIdentifier = "FriendCellIdentifier"
  3.     var cell: FriendCell = tableView.dequeueReusableCellWithIdentifier(FriendCellIdentifier) as FriendCell
  4.     var group: Group = (sectionInfoArray[indexPath.section] as SectionInfo).group
  5.     cell.friend = group.friends[indexPath.row] as Friend
  6.     cell.setFriend(cell.friend)
  7.     return cell
  8. }

tableView:cellForRowAtIndexPath:方法返回指定的行的单元格。一个朋友对应一个单元格。在这个方法 中,我们通过dequeueReusableCellWithIdentifier()方法来读取对应标识符的单元格,在这里是我们在 main.Stroyboard中定义的那个单元格。还记得我们给那个单元格添加了“FriendCellIdentifier”标识符吗?

  1. override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
  2.     // 返回指定的section header视图
  3.     var sectionHeaderView: SectionHeaderView = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier(SectionHeaderViewIdentifier) as SectionHeaderView
  4.     var sectionInfo: SectionInfo = sectionInfoArray[section] as SectionInfo
  5.     sectionInfo.headerView = sectionHeaderView
  6.     sectionHeaderView.LblTitle.text = sectionInfo.group.name
  7.     sectionHeaderView.section = section
  8.     sectionHeaderView.delegate = self
  9.     return sectionHeaderView
  10. }

和上面的方法相似,tableView:viewForHeaderInSection:方法返回section中的表头 (Header)类型。我们的SectionHeaderView声明的是UITableViewHeaderFooterView类型,这个方法是专门 用来返回该类型的实例的。

可以看到,这个方法中使用了和上面方法极其相似的 dequeueReusableHeaderFooterViewWithIdentifier()方法。这个方法的作用同样也是读取对应标识符的单元 格。不过不同的是,使用这个方法前需要注册nib文件或者注册描述这个单元格的类。因此,之前我们就使用了如下两条语句注册nib文件,以便于swift 能够读取到这个单元格。

  1. let sectionHeaderNib: UINib = UINib(nibName: "SectionHeaderView", bundle: nil)
  2. self.tableView.registerNib(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: SectionHeaderViewIdentifier)
  1. override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
  2.     return CGFloat(DefaultRowHeight)
  3. }

这个方法返回指定的单元格的高度,这里我们返回的是单元格的默认高度。

实现表格的展开、收缩效果

我们给ViewController这个类继承SectionHeaderViewDelegate协议,此时,类的头部变成这样:

  1. class ViewController: UITableViewController, SectionHeaderViewDelegate

接下来,我们在ViewController类中实现协议中定义的两个函数:

  1. func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int) {
  2.     var sectionInfo: SectionInfo = sectionInfoArray[sectionOpened] as SectionInfo
  3.     sectionInfo.headerView.HeaderOpen = true
  4.     //创建一个包含单元格索引路径的数组来实现插入单元格的操作:这些路径对应当前节的每个单元格
  5.     var countOfRowsToInsert = sectionInfo.group.friends.count
  6.     var indexPathsToInsert = NSMutableArray()
  7.     for (var i = 0; i < countOfRowsToInsert; i++) {
  8.         indexPathsToInsert.addObject(NSIndexPath(forRow: i, inSection: sectionOpened))
  9.     }
  10.     // 创建一个包含单元格索引路径的数组来实现删除单元格的操作:这些路径对应之前打开的节的单元格
  11.     var indexPathsToDelete = NSMutableArray()
  12.     var previousOpenSectionIndex = opensectionindex
  13.     if previousOpenSectionIndex != NSNotFound {
  14.         var previousOpenSection: SectionInfo = sectionInfoArray[previousOpenSectionIndex] as SectionInfo
  15.         previousOpenSection.headerView.HeaderOpen = false
  16.         previousOpenSection.headerView.toggleOpen(false)
  17.         var countOfRowsToDelete = previousOpenSection.group.friends.count
  18.         for (var i = 0; i < countOfRowsToDelete; i++) {
  19.             indexPathsToDelete.addObject(NSIndexPath(forRow: i, inSection: previousOpenSectionIndex))
  20.         }
  21.     }
  22.     // 设计动画,以便让表格的打开和关闭拥有一个流畅的效果
  23.     var insertAnimation: UITableViewRowAnimation
  24.     var deleteAnimation: UITableViewRowAnimation
  25.     if previousOpenSectionIndex == NSNotFound || sectionOpened < previousOpenSectionIndex {
  26.         insertAnimation = UITableViewRowAnimation.Top
  27.         deleteAnimation = UITableViewRowAnimation.Bottom
  28.     }else{
  29.         insertAnimation = UITableViewRowAnimation.Bottom
  30.         deleteAnimation = UITableViewRowAnimation.Top
  31.     }
  32.     // 应用单元格的更新
  33.     self.tableView.beginUpdates()
  34.     self.tableView.deleteRowsAtIndexPaths(indexPathsToDelete, withRowAnimation: deleteAnimation)
  35.     self.tableView.insertRowsAtIndexPaths(indexPathsToInsert, withRowAnimation: insertAnimation)
  36.     opensectionindex = sectionOpened
  37.     self.tableView.endUpdates()
  38.     }

我们来解析一下这个函数。首先创建了一个包含单元格索引路径的数组来实现插入单元格的操作,这个数组存放有将要打开的用户组 中的所有朋友信息。接下来是创建了一个包含单元格索引路径的数组来实现删除单元格的操作。首先将先前已打开的用户组关闭(调用toggleOpen()函 数),随后将数组中放入已打开的用户组中的所有朋友信息。

最后,执行删除行的操作,再执行插入行的操作,注意顺序不要颠倒了(想想为什么?)

我们使用beginUpdates()方法和endUpdates()方法将删除、插入操作“包”了起来,这两个方法是配合起来使用的,标记了一个tableView的动画块,分别代表动画的开始和结束。

  1. func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int) {
  2.     // 在表格关闭的时候,创建一个包含单元格索引路径的数组,接下来从表格中删除这些行
  3.     var sectionInfo: SectionInfo = self.sectionInfoArray[sectionClosed] as SectionInfo
  4.     sectionInfo.headerView.HeaderOpen = false
  5.     var countOfRowsToDelete = self.tableView.numberOfRowsInSection(sectionClosed)
  6.     if countOfRowsToDelete > 0 {
  7.         var indexPathsToDelete = NSMutableArray()
  8.         for (var i = 0; i < countOfRowsToDelete; i++) {
  9.             indexPathsToDelete.addObject(NSIndexPath(forRow: i, inSection: sectionClosed))
  10.         }
  11.         self.tableView.deleteRowsAtIndexPaths(indexPathsToDelete, withRowAnimation: UITableViewRowAnimation.Top)
  12.     }
  13.     opensectionindex = NSNotFound
  14. }

和上面的方法类似,在此我们不做过多的解释了。

到这里,我们的教程就结束了。有兴趣的同学可以去我的 Github 上面下载demo项目的源代码:TVAnimationsGestures-Swift,这个 demo 是苹果官方提供的 demo 的 Swift 版本,大家可以基于这个版本来实现可展开可收缩的表视图。

Swift 可展开可收缩的表视图的更多相关文章

  1. iOS开发高级分享 - iOS的可折叠表视图

    导言 我曾经开发过一个iphone应用程序,它显示了大量的输入,这些输入分为不同的类别,在`UITableView`...若要更改其中一个输入的值,用户按下表视图中的对应行,并在出现的单独屏幕中更改该 ...

  2. 表视图控制器(TableViewController)(三) 、 表视图搜索

    1 乐库的设置界面 1.1 问题 tableView分为静态(static)和动态(dynamic),之前使用的都是动态的tableView,表视图的有多少分区.有多少行以及每一行显示的内容都不是固定 ...

  3. 表视图控制器(TableViewController)(二)

    1 tableView的编辑模式 1.1 问题 表视图可以进入编辑模式,当进入编辑模式就可以进行删除.插入.移动单元等操作,本案例还是使用联系人界面学习如何进入编辑模式,以及进入编辑模式之后的删除.插 ...

  4. 表视图(UITableView)与表视图控制器(UITableViewController)

    表视图(UITableView)与表视图控制器(UITableViewController)其实是一回事. 表视图控制器是一种只能显示表视图的标准视图控制器,可在表视图占据整个视图时使用这种控制器.虽 ...

  5. iOS开发之多表视图滑动切换示例(仿"头条"客户端)---优化篇

    前几天发布了一篇iOS开发之多表视图滑动切换示例(仿"头条"客户端)的博客,之所以写这篇博客,是因为一位iOS初学者提了一个问题,简单的写了个demo做了个示范,让其在基础上做扩展 ...

  6. iOS开发之表视图爱上CoreData

    在接触到CoreData时,感觉就是苹果封装的一个ORM.CoreData负责在Model的实体和sqllite建立关联,数据模型的实体类就相当于Java中的JavaBean, 而CoreData的功 ...

  7. iOS企业级开发初级课程-表视图(13集)

    首先了解了表视图的组成.表视图类的构成.表视图的分类以及表视图的两个重要协议(委托协议和数据源协议),对表视图有了一个整体上的认识.接下来我们掌握了如何实现简单表视图和分节表视图,以及表视图中索引.搜 ...

  8. mysql常用表/视图管理语句

    查看所有表  show tables; 查看表/视图结构 desc 表名/视图名: 查看建表过程  show create table 表名: 查看建视图过程 show create view 视图名 ...

  9. 表视图控制器(TableViewController)(一)

    1 创建一个UITableViewController并展示简单数据 1.1 问题 有很多移动客户端的应用都是采用表的形式来展示数据,因为表视图能使数据看起来更规整.更有调理,比如微信界面就是使用的表 ...

随机推荐

  1. 采用xml的方式保存数据

    package com.example.myxmlmake; import java.io.File; import java.io.FileOutputStream; import java.uti ...

  2. 改ucosii的中断禁止和恢复代码,这是一个荒谬的错误【 mrs msr】

    ucosii原来的禁止中断以及恢复中断的代码是最简的,但是使用之前,必须声明一个固定名为 OS_CPU_SR   cpu_sr 的变量,吊在那里感觉很怪. ;********************* ...

  3. 在win8.1上用Bitvise SSH Server 6.24(原名winsshd)搭建SSH2服务器

    注意:此SSH是指运维领域的 SSH,不是指JavaWeb框架中的SSH. 运维领域:SSH=Secure Shell安全外壳协议 JavaWeb框架:SSH=Spring+Struts+Hibern ...

  4. python xpath

    提取Item 选择器介绍 我们有很多方法从网站中提取数据.Scrapy 使用一种叫做 XPath selectors的机制,它基于 XPath表达式.如果你想了解更多selectors和其他机制你可以 ...

  5. Vbox视图热键

    Vbox屏幕热键 在Vbox中一般host主键会默觉得"右Ctrl",例如以下图所看到的,在选择自己主动调整窗体后,"视图"选项栏会消失.这时若想更改视图设置能 ...

  6. C# - Environment类,获取桌面的路径

    private void button1_Click(object sender, EventArgs e) { string Path = Environment.GetFolderPath(Env ...

  7. BZOJ 1112: [POI2008]砖块Klo1112( BST )

    枚举每个长度为k的区间, 然后用平衡树找中位数进行判断, 时间复杂度O(nlogn). 早上起来精神状态不太好...连平衡树都不太会写了...果断去看了会儿番然后就A了哈哈哈 ------------ ...

  8. Ch03 视图基础

    3.1  视图简介 3.1.1  选择待渲染视图 3.1.2  重写视图名 3.2  给视图传递数据 3.2.1  ViewDataDictionary 3.2.2  ViewBag 3.2.3  带 ...

  9. 如何在VC中显示透明背景位图

    简单的调用系统API. Windows NT/2000/XP: Included in Windows 2000 and later.Windows 95/98/Me: Included in Win ...

  10. java BigDecimal的使用和四舍五入及格式规范(精准数据)

    • Java中的简单浮点数类型float和double不能够进行运算.不光是Java,在其它很多编程语言中也有这样的问题. 如果我们编译运行下面这个程序会看到什么? public   class  T ...