当前位置: 首页 > news >正文

07. 容器控件(一) - NSCollectionView 网格、NSTabView 卡片、NSPopover 弹出层

本节主要讲述三个使用比较频繁的容器控件,包括tab页、表格以及集合面板三种。

NSTabView

Tab卡片视图,这个很简单就是如下样式,在使用过程中还可以动态增加和删除。
在这里插入图片描述

基本设置

  • tabs:指定tab的个数;
  • initial tab:指定默认被选中的tab;
  • style:指定tab的位置;
  • identifier:tab的id值(设置tabItem的);

事件响应

需要实现NSTabViewDelegate代理协议,当tab加载时调用(默认加载或点击),本示例中因为是委托给了ViewController,所以需要outlets到View Controller。
在这里插入图片描述

extension ViewController: NSTabViewDelegate{func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {//点击和加载的默认事件print("title:\(tabViewItem?.label) id:\(tabViewItem?.identifier)")}
}

动态添加TabItem

编程实现tabitem的动态添加:

    @IBOutlet weak var tabView: NSTabView! @IBAction func addTabItemAction(_ sender: NSButton) {let tabViewItem = NSTabViewItem(identifier: "Untitled")tabViewItem.label = "dyItemTitle"let view = NSView(frame: NSZeroRect) //系统常量,类似的还有NSZeroPoint等tabViewItem.view = viewself.tabView.addTabViewItem(tabViewItem)}

动态选择TabItem

比如添加一个 NSSegmentedControl ,然后根据索引设置tab显示,即不使用NSTabView自带的切换按钮,而是从外部控件其视图的显示。
在这里插入图片描述
示例代码如下:

    @IBOutlet weak var tabView: NSTabView!@IBAction func segmentAction(_ sender: NSSegmentedControl) {let index = sender.selectedSegmenttabView.selectTabViewItem(at: index)}

NSPopover

弹出容器,可以指定其位置等属性,其内容来自于别一个NSViewController。
在这里插入图片描述

基本设置

  • behavior:设置关闭行为,transient=只要点击Popover区域外就会关闭, semitransient=只要点击Popover区域外就会关闭,但点击到当前App外则不关闭
  • animates:是否有动画效果;
  • contentViewController:要显示的控制器;

事件响应

  1. 添加一个NSViewController,并设置其storyboard id值;
  2. 给需要弹出popover面板的控件加点击事件;
    //延迟加载技术,主要为了提升性能,在被调用时才初始化lazy var sharePopover:NSPopover = {let popover = NSPopover()let controller = self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Share")) as! NSViewControllerpopover.contentViewController = controllerpopover.behavior = .transient //关闭行为return popover}()@IBAction func showPopupAction(_ sender: NSButton) {//relativeTo:显示时参考的矩形, of:参考点,preferredEdge:显示位置,上面sharePopover.show(relativeTo: sender.bounds, of: sender, preferredEdge: .minY)//sharePopover.close()}

NSCollectionView

一个带有自动分布功能的Grid面板控件,类似九宫格,在使用此控件之前需要先了解两个核心对象:

  • NSCollectionView:相当于一个容器,内容会被封装到一个名为 content 的属性中,content 是一个NSCollectionViewItem数组;
  • NSCollectionViewItem:是NSCollectionView中的内容,它也是一个容器,它继承了NSViewController,所以使用时需要binding 数据;
    在这里插入图片描述

Demo示例

  1. 拖动NSCollectionView控件到主面板上;
  2. 添加 add Constraints 这样可以达到自动适应的一个效果;***见Auto Layout应用
  3. 拖动一个NSCollectionViewItem控件到空白处,同时设置其storyboard ID;
  4. 在NSCollectionViewItem控件中添加NSImageView和Label;
  5. 绑定 NSImageView和NSLabel 到 NSCollectionViewItem; ***见bindings 模型

Auto Layout应用

  1. 拖动一个NSCollectionView到面板中;
  2. 然后在导航区选择Bordered Scroll View,点击右下角第二个按钮 add Constraints;这样NSCollectionView就可以随父窗口变化而变化了,这个Container的作用是固定元素到父元素的边距大小,相当于一个内容区域自适应功能。
    在这里插入图片描述

上面设置的等价代码实现如下:

    //下面代码采用swift 4func autoLayoutConfig() {// tableScrollView 为自定义的view      let topAnchor = self.tableScrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0)let bottomAnchor = self.tableScrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0)let leftAnchor =  self.tableScrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0)let rightAnchor = self.tableScrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0)NSLayoutConstraint.activate([topAnchor, bottomAnchor, leftAnchor, rightAnchor])}

Bindings 数据模型

这里要做的就是把NSCollectionViewItem中的相应属性和相空的控件绑定在一起,比如 NSCollectionViewItem面板中添加了一个image如下:
在这里插入图片描述
则点击image然后切换到bindings 面板:
在这里插入图片描述
这里的 Bind to 表示要绑定的控件类,Model key path 表示代码中的数据属性名称(representedObject是一个固定值),通过以上设置,就把元素和控件的类属性绑定在一起了。

组装NSCollectionView和NSCollectionViewItem

   @IBOutlet weak var collectionView: NSCollectionView!override func viewDidLoad() {//collectionViewItem 为 NSCollectionViewItem的storyboardid,在identity面板中设置let itemPrototype = self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "collectionViewItem"))  as! NSCollectionViewItem//设置NSCollectionView内容为NSCollectionViewItemself.collectionView.itemPrototype = itemPrototype//更新数据self.updateContent()}

添加内容,这样就实现了动态添加内容了

    var content = [NSDictionary]()func updateContent(){let item1: NSDictionary = ["title" : "computer","image" : NSImage(named: NSImage.Name.computer)!]let item2: NSDictionary = ["title" : "folder","image" : NSImage(named: NSImage.Name.folder)!]let item3: NSDictionary = ["title" : "home","image" : NSImage(named: NSImage.Name.homeTemplate)!]let item4: NSDictionary = ["title" : "list","image" : NSImage(named: NSImage.Name.listViewTemplate)!]let item5: NSDictionary = ["title" : "network","image" : NSImage(named: NSImage.Name.network)!]let item6: NSDictionary = ["title" : "share","image" : NSImage(named: NSImage.Name.shareTemplate)!]content.append(item1)content.append(item2)content.append(item3)content.append(item4)content.append(item5)content.append(item6)self.collectionView.content = content}

其在拖动时,也可以自由变换位置,如下:
在这里插入图片描述

编码实现

(示例有点显示问题)

  1. 创建一个 NSCollectionViewItem 子类,并附带XIB界面实现,这里需要重新绑定元素,默认的自动绑定不好用
  2. 手动编码
    在这里插入图片描述

创建NSCollectionViewItem

选择新建Cocos class 类,然后按下图设置
在这里插入图片描述
此时会生成一个CollectionViewItem.xib文件和一个名为CollectionViewItem.swift的源文件重新绑定元素

//CollectionViewItem.swift
import Cocoaclass CollectionViewItem: NSCollectionViewItem {//这两个变量要重新绑定,否则不生效,报nil找不到错误@IBOutlet weak var image: NSImageView!@IBOutlet weak var titleField: NSTextField!override func viewDidLoad() {super.viewDidLoad()}override var representedObject: Any? {didSet {let data = self.representedObject as! NSDictionaryif let image = data["image"] as? NSImage {self.image.image = image}if let title = (data["title"] as? String) {self.titleField.stringValue = title}}}
}

创建 NSCollectionView

在ViewController.swift中一步步手工编码即可

import Cocoa//1、 得到一个名为CollectionViewItem的界面元素,声明为全局变量
extension NSUserInterfaceItemIdentifier {static let collectionViewItem = NSUserInterfaceItemIdentifier("CollectionViewItem")
}class ViewController: NSViewController {//声明 NSScrollView 对象lazy var scrollView: NSScrollView = {let scrollView = NSScrollView()scrollView.focusRingType = .nonescrollView.autohidesScrollers = truescrollView.borderType = .noBorderscrollView.documentView = self.collectionViewreturn scrollView}()// 声明 NSCollectionView 对象--内容面板lazy var collectionView: NSCollectionView = {let view = NSCollectionView()view.isSelectable = trueview.delegate     = selfview.dataSource   = selfview.collectionViewLayout = self.flowLayoutview.register(CollectionViewItem.self, forItemWithIdentifier: .collectionViewItem) //注册view.backgroundColors[0] = NSColor.redreturn view}()var sectionInset: NSEdgeInsets = NSEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)lazy var flowLayout: NSCollectionViewFlowLayout = {let layout = NSCollectionViewFlowLayout()layout.scrollDirection = .horizontallayout.itemSize = NSSize(width: 40, height: 40)layout.sectionInset = self.sectionInsetlayout.minimumInteritemSpacing = 10layout.minimumLineSpacing = 10return layout}()//添加到window中override func viewDidLoad() {super.viewDidLoad()scrollView.frame = self.view.boundsself.view.addSubview(scrollView)self.updateContent()let dd = NSCollectionViewGridLayout()}//更新元素var content = [NSDictionary]()func updateContent(){let item1: NSDictionary = ["title" : "computer","image" : NSImage(named: NSImage.Name.computer)!]let item2: NSDictionary = ["title" : "folder","image" : NSImage(named: NSImage.Name.folder)!]let item3: NSDictionary = ["title" : "home","image" : NSImage(named: NSImage.Name.homeTemplate)!]let item4: NSDictionary = ["title" : "list","image" : NSImage(named: NSImage.Name.listViewTemplate)!]let item5: NSDictionary = ["title" : "network","image" : NSImage(named: NSImage.Name.network)!]let item6: NSDictionary = ["title" : "share","image" : NSImage(named: NSImage.Name.shareTemplate)!]content.append(item1)content.append(item2)content.append(item3)content.append(item4)content.append(item5)content.append(item6)collectionView.reloadData()}
}//以下全是扩展协议
extension ViewController: NSCollectionViewDataSource {func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {return content.count}func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {//let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CollectionViewItem"), for: indexPath)let item = collectionView.makeItem(withIdentifier: .collectionViewItem, for: indexPath)let itemIndex = (indexPath as NSIndexPath).itemitem.representedObject = content[itemIndex]return item}func numberOfSections(in collectionView: NSCollectionView) -> Int {return 1}
}extension ViewController: NSCollectionViewDelegate {func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {print(indexPaths)}
}extension ViewController: NSCollectionViewDelegateFlowLayout {func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {return NSSize(width: 100, height: 100)}
}

http://www.mrgr.cn/news/52843.html

相关文章:

  • 一分钟学会MATLAB-数值计算
  • JavaWeb 22.Node.js_简介和安装
  • React Native 项目中使用 Expo Application Services (EAS) 进行多渠道打包
  • 黑盒测试 | 挖掘.NET程序中的反序列化漏洞
  • 进化吧!原始人
  • JVM详解
  • vllm技术详解
  • Kinect Fusion介绍
  • plt.pie饼图的绘制
  • Rocky Linux 9安装Asterisk 20和freepbx 17脚本——筑梦之路
  • 【企业家日活动】威海企联举办“保驾护航·优商兴企”政企恳谈会
  • 分布式数据库:中高级开发者的使用技巧
  • 【刷题】东方博宜OJ 1135 - 歌德巴赫猜想
  • 如何使用外呼电话机器人的功能可以更高效的获客?
  • vue3使用element-plus手动更改url后is-active和菜单的focus颜色不同步问题
  • 车辆管理智能化:SpringBoot技术的应用
  • redis客户端
  • 充电宝怎么选才不会后悔?2024年度最值得购买的五款充电宝推荐!
  • 33--一个进程最多可以创建多少个线程?
  • 基于Neo4j与Django的员工地址距离展示系统