首页 > 其他分享 >Mac开发基础20-NSCollectionView

Mac开发基础20-NSCollectionView

时间:2024-08-06 17:39:08浏览次数:11  
标签:indexPath NSCollectionView 20 collectionView return item Mac layout

NSCollectionView 是 macOS 开发中的一种强大控件,类似于 iOS 上的 UICollectionView,用于展示和管理网格、列表等多种布局的数据展示视图。

1. 基本使用

创建和初始化

Objective-C

#import <Cocoa/Cocoa.h>

// 创建并初始化一个 NSCollectionView 实例
NSCollectionView *collectionView = [[NSCollectionView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300)];

// 创建一个 NSCollectionView 流水布局(类似于 UICollectionView 的 UICollectionViewFlowLayout)
NSCollectionViewFlowLayout *layout = [[NSCollectionViewFlowLayout alloc] init];
layout.itemSize = NSMakeSize(100, 100); // 设置每个项目的大小
layout.sectionInset = NSEdgeInsetsMake(10, 10, 10, 10); // 设置每个节的内边距
layout.minimumInteritemSpacing = 10; // 行间距
layout.minimumLineSpacing = 10; // 列间距

// 设置 CollectionView 的布局
[collectionView setCollectionViewLayout:layout];

Swift

import Cocoa

// 创建并初始化一个 NSCollectionView 实例
let collectionView = NSCollectionView(frame: NSRect(x: 0, y: 0, width: 400, height: 300))

// 创建一个 NSCollectionView 流水布局(类似于 UICollectionView 的 UICollectionViewFlowLayout)
let layout = NSCollectionViewFlowLayout()
layout.itemSize = NSSize(width: 100, height: 100) // 设置每个项目的大小
layout.sectionInset = EdgeInsets(top: 10, left: 10, bottom: 10, right: 10) // 设置每个节的内边距
layout.minimumInteritemSpacing = 10 // 行间距
layout.minimumLineSpacing = 10 // 列间距

// 设置 CollectionView 的布局
collectionView.collectionViewLayout = layout

数据源和委托

NSCollectionView 依赖数据源(NSCollectionViewDataSource)和委托(NSCollectionViewDelegate)来提供数据和处理用户交互事件。

Objective-C

// 设置数据源和委托
[collectionView setDataSource:self];
[collectionView setDelegate:self];
// 实现数据源协议
- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView {
    return 1; // 返回节数
}

- (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return _dataArray.count; // 返回每个节中的项目数
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {
    NSCollectionViewItem *item = [collectionView makeItemWithIdentifier:@"ItemIdentifier" forIndexPath:indexPath];
    item.textField.stringValue = _dataArray[indexPath.item];
    return item; // 返回对应的项目
}
// 实现委托协议
- (void)collectionView:(NSCollectionView *)collectionView didSelectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths {
    NSIndexPath *selectedIndexPath = indexPaths.allObjects.firstObject;
    NSLog(@"Selected item at section: %ld, item: %ld", selectedIndexPath.section, selectedIndexPath.item); // 处理选择事件
}

Swift

// 设置数据源和委托
collectionView.dataSource = self
collectionView.delegate = self
// 实现数据源协议
func numberOfSections(in collectionView: NSCollectionView) -> Int {
    return 1 // 返回节数
}

func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
    return dataArray.count // 返回每个节中的项目数
}

func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
    let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("ItemIdentifier"), for: indexPath)
    item.textField?.stringValue = dataArray[indexPath.item]
    return item // 返回对应的项目
}
// 实现委托协议
func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
    if let selectedIndexPath = indexPaths.first {
        print("Selected item at section: \(selectedIndexPath.section), item: \(selectedIndexPath.item)") // 处理选择事件
    }
}

项目注册和重用

Objective-C

// 注册项目类
[collectionView registerNib:[[NSNib alloc] initWithNibNamed:@"MyCollectionViewItem" bundle:nil] forItemWithIdentifier:@"ItemIdentifier"];

Swift

// 注册项目类
let nib = NSNib(nibNamed: "MyCollectionViewItem", bundle: nil)
collectionView.register(nib, forItemWithIdentifier: NSUserInterfaceItemIdentifier("ItemIdentifier"))

2. 编辑和选择

允许选择项目

Objective-C

// 允许选择项目
[collectionView setAllowsSelection:YES];
[collectionView setAllowsMultipleSelection:YES]; // 允许多选

Swift

// 允许选择项目
collectionView.allowsSelection = true
collectionView.allowsMultipleSelection = true // 允许多选

自定义项目视图和布局

Objective-C

@interface CustomCollectionViewItem : NSCollectionViewItem
@end

@implementation CustomCollectionViewItem

- (void)viewDidLoad {
    [super viewDidLoad];
    // 自定义视图的配置
    self.view.wantsLayer = YES;
    self.view.layer.backgroundColor = [NSColor lightGrayColor].CGColor;
}

@end

Swift

class CustomCollectionViewItem: NSCollectionViewItem {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 自定义视图的配置
        self.view.wantsLayer = true
        self.view.layer?.backgroundColor = NSColor.lightGray.cgColor
    }
}

3. 高级用法

动态内容的添加和删除

Objective-C

- (void)addItem {
    [_dataArray addObject:@"New Item"];
    [collectionView reloadData]; // 添加新项目并刷新数据
}

- (void)removeItemAtIndexPath:(NSIndexPath *)indexPath {
    [_dataArray removeObjectAtIndex:indexPath.item];
    [collectionView deleteItemsAtIndexPaths:[NSSet setWithObject:indexPath]]; // 移除项目并刷新数据
}

Swift

func addItem() {
    dataArray.append("New Item")
    collectionView.reloadData() // 添加新项目并刷新数据
}

func removeItem(at indexPath: IndexPath) {
    dataArray.remove(at: indexPath.item)
    collectionView.deleteItems(at: [indexPath]) // 移除项目并刷新数据
}

项目拖放操作

Objective-C

// 开始拖放时
- (BOOL)collectionView:(NSCollectionView *)collectionView canDragItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths withEvent:(NSEvent *)event {
    return YES; // 允许拖放
}

- (NSArray<NSPasteboardWriting> *)collectionView:(NSCollectionView *)collectionView pasteboardWriterForItemAtIndexPath:(NSIndexPath *)indexPath {
    return @[[NSNumber numberWithInteger:indexPath.item]]; // 将项目索引写入剪贴板
}

// 验证拖放
- (NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id<NSDraggingInfo>)draggingInfo proposedIndexPath:(NSIndexPath *__autoreleasing  _Nullable *)proposedDropIndexPath dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation {
    return NSDragOperationMove; // 允许移动操作
}

// 接受拖放
- (BOOL)collectionView:(NSCollectionView *)collectionView acceptDrop:(id<NSDraggingInfo>)draggingInfo indexPath:(NSIndexPath *)indexPath dropOperation:(NSCollectionViewDropOperation)dropOperation {
    NSPasteboard *pasteboard = [draggingInfo draggingPasteboard];
    NSString *itemIndexString = [pasteboard stringForType:NSPasteboardTypeString];
    NSInteger fromIndex = [itemIndexString integerValue];
    
    // 移动项目并更新数据
    id movingItem = _dataArray[fromIndex];
    [_dataArray removeObjectAtIndex:fromIndex];
    [_dataArray insertObject:movingItem atIndex:indexPath.item];
    
    [collectionView reloadData]; // 刷新数据
    return YES;
}

Swift

// 开始拖放时
func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {
    return true // 允许拖放
}

func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {
    return NSNumber(value: indexPath.item) // 将项目索引写入剪贴板
}

// 验证拖放
func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath: AutoreleasingUnsafeMutablePointer<IndexPath>, dropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
    return .move // 允许移动操作
}

// 接受拖放
func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
    guard let itemIndexString = draggingInfo.draggingPasteboard.string(forType: .string),
          let fromIndex = Int(itemIndexString) else {
        return false
    }
    
    // 移动项目并更新数据
    let movingItem = dataArray[fromIndex]
    dataArray.remove(at: fromIndex)
    dataArray.insert(movingItem, at: indexPath.item)
    
    collectionView.reloadData() // 刷新数据
    return true
}

自定义节头视图和脚视图

Objective-C

// 自定义节头视图
@interface CustomHeaderView : NSView
@property (nonatomic, strong) NSTextField *headerLabel;
@end

@implementation CustomHeaderView

- (instancetype)initWithFrame:(NSRect)frameRect {
    self = [super initWithFrame:frameRect];
    if (self) {
        _headerLabel = [[NSTextField alloc] initWithFrame:self.bounds];
        [_headerLabel setBezeled:NO];
        [_headerLabel setDrawsBackground:NO];
        [_headerLabel setEditable:NO];
        [_headerLabel setSelectable:NO];
        [self addSubview:_headerLabel];
    }
    return self;
}

@end

// 返回自定义节头视图
- (NSView *)collectionView:(NSCollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    if (kind == NSCollectionElementKindSectionHeader) {
        CustomHeaderView *headerView = [collectionView makeSupplementaryViewOfKind:kind withIdentifier:@"HeaderViewIdentifier" forIndexPath:indexPath];
        headerView.headerLabel.stringValue = @"Section Header";
        return headerView; // 返回自定义节头视图
    }
    return nil;
}

Swift

// 自定义节头视图
class CustomHeaderView: NSView {
    var headerLabel: NSTextField!

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        headerLabel = NSTextField(frame: self.bounds)
        headerLabel.isBezeled = false
        headerLabel.drawsBackground = false
        headerLabel.isEditable = false
        headerLabel.isSelectable = false
        addSubview(headerLabel)
    }

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

// 返回自定义节头视图
func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView {
    if kind == NSCollectionView.elementKindSectionHeader {
        let headerView = collectionView.makeSupplementaryView(ofKind: kind, withIdentifier: NSUserInterfaceItemIdentifier("HeaderViewIdentifier"), for: indexPath) as! CustomHeaderView
        headerView.headerLabel.stringValue = "Section Header"
        return headerView // 返回自定义节头视图
    }
    return NSView()
}

封装工具类

为了更方便地使用 NSCollectionView,我们可以封装一个工具类,提供常见功能的高层接口。

Objective-C

#import <Cocoa/Cocoa.h>

@interface NSCollectionViewHelper : NSObject

+ (NSCollectionView *)createCollectionViewWithFrame:(NSRect)frame itemIdentifiers:(NSArray<NSString *> *)itemIdentifiers layout:(NSCollectionViewLayout *)layout target:(id)target;
+ (void)setupDragAndDropForCollectionView:(NSCollectionView *)collectionView;
+ (void)registerHeaderViewForCollectionView:(NSCollectionView *)collectionView withIdentifier:(NSString *)identifier;

@end

@implementation NSCollectionViewHelper

+ (NSCollectionView *)createCollectionViewWithFrame:(NSRect)frame itemIdentifiers:(NSArray<NSString *> *)itemIdentifiers layout:(NSCollectionViewLayout *)layout target:(id)target {
    NSCollectionView *collectionView = [[NSCollectionView alloc] initWithFrame:frame];
    collectionView.collectionViewLayout = layout;

    for (NSString *identifier in itemIdentifiers) {
        [collectionView registerClass:[NSCollectionViewItem class] forItemWithIdentifier:identifier];
    }

    collectionView.dataSource = target;
    collectionView.delegate = target;
    return collectionView;
}

+ (void)setupDragAndDropForCollectionView:(NSCollectionView *)collectionView {
    [collectionView registerForDraggedTypes:@[NSPasteboardTypeString]];
    collectionView.draggingSourceOperationMask = NSDragOperationEvery;
}

+ (void)registerHeaderViewForCollectionView:(NSCollectionView *)collectionView withIdentifier:(NSString *)identifier {
    [collectionView registerClass:[CustomHeaderView class] forSupplementaryViewOfKind:NSCollectionElementKindSectionHeader withIdentifier:identifier];
}

@end

Swift

import Cocoa

class NSCollectionViewHelper {
    
    // 创建 CollectionView 并注册项目标识符
    static func createCollectionView(frame: NSRect, itemIdentifiers: [String], layout: NSCollectionViewLayout, target: AnyObject) -> NSCollectionView {
        let collectionView = NSCollectionView(frame: frame)
        collectionView.collectionViewLayout = layout
        
        for identifier in itemIdentifiers {
            collectionView.register(NSCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier))
        }
        
        collectionView.dataSource = target as? NSCollectionViewDataSource
        collectionView.delegate = target as? NSCollectionViewDelegate
        return collectionView
    }
    
    // 配置拖放功能
    static func setupDragAndDrop(for collectionView: NSCollectionView) {
        collectionView.registerForDraggedTypes([.string])
        collectionView.draggingSourceOperationMask = .every
    }
    
    // 注册节头视图
    static func registerHeaderView(for collectionView: NSCollectionView, withIdentifier identifier: String) {
        collectionView.register(CustomHeaderView.self, forSupplementaryViewOfKind: NSCollectionView.elementKindSectionHeader, withIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier))
    }
}

使用示例

Objective-C

// 创建 CollectionView
NSCollectionViewFlowLayout *layout = [[NSCollectionViewFlowLayout alloc] init];
layout.itemSize = NSMakeSize(100, 100);

NSCollectionView *collectionView = [NSCollectionViewHelper createCollectionViewWithFrame:NSMakeRect(0, 0, 400, 300)
                                                                         itemIdentifiers:@[@"ItemIdentifier"]
                                                                                  layout:layout
                                                                                  target:self];

// 配置拖放功能
[NSCollectionViewHelper setupDragAndDropForCollectionView:collectionView];

// 注册节头视图
[NSCollectionViewHelper registerHeaderViewForCollectionView:collectionView withIdentifier:@"HeaderViewIdentifier"];

Swift

// 创建 CollectionView
let layout = NSCollectionViewFlowLayout()
layout.itemSize = NSSize(width: 100, height: 100)

let collectionView = NSCollectionViewHelper.createCollectionView(frame: NSRect(x: 0, y: 0, width: 400, height: 300),
                                                                 itemIdentifiers: ["ItemIdentifier"],
                                                                 layout: layout,
                                                                 target: self)

// 配置拖放功能
NSCollectionViewHelper.setupDragAndDrop(for: collectionView)

// 注册节头视图
NSCollectionViewHelper.registerHeaderView(for: collectionView, withIdentifier: "HeaderViewIdentifier")

总结

通过了解这些常见 API 和基础技巧,以及一些高级用法和封装工具类,可以更高效地使用 NSCollectionView 实现复杂的数据展示和用户交互。在开发复杂的 macOS 应用时,熟练掌握 NSCollectionView 的使用将大大提高工作效率。

标签:indexPath,NSCollectionView,20,collectionView,return,item,Mac,layout
From: https://www.cnblogs.com/chglog/p/18345692

相关文章

  • HDU-ACM 2024 Day1
    T1009数位的关系(HDU7441)考虑\(l=r\)的情况,此时只要计算一个数字,我们将其展开为一个字符串\(S\)。设\(f_{i,j,k}\)表示考虑了\(S\)的前\(i\)位,选出了\(j\)个数字加入子序列,最后一个加入子序列的数字是\(k\)的方案数,转移平凡。拓展到\(l\neqr\),经典地将答......
  • Mac开发基础19-NSTableView(二)
    进阶使用和技巧1.单击和双击行事件处理Objective-C//单击行时的处理-(void)tableView:(NSTableView*)tableViewdidClickTableColumn:(NSTableColumn*)tableColumn{NSIntegerclickedRow=[tableViewclickedRow];if(clickedRow>=0){NSLog(@"Si......
  • 力扣每日一题2024.8.5
    600.不含连续1的非负整数(困难)给定一个正整数n,请你统计在[0,n]范围的非负整数中,有多少个整数的二进制表示中不存在连续的1。示例1:输入:n=5输出:5解释:下面列出范围在[0,5]的非负整数与其对应的二进制表示:0:01:12:103:114:1005:101......
  • (连续四届EI检索|稳定ACM出版、EI检索|线上线下结合)2024年第五届医学人工智能国际学术
    第五届医学人工智能国际学术会议(ISAIMS2024)将于2024年8月13-17日于荷兰阿姆斯特丹自由大学召开,国内分会场将于2024年10月25-27日于中国武汉召开。会议自2020年至今已经成功举办四届,吸引了来自海内外相关领域学者600余名。本届会议将继续围绕人工智能在医学领域的最新研究成果,为......
  • 2024暑假集训测试18
    前言比赛链接。这次有大量外校人员参加,\(90\)来个人,T1胡了个结论上去结果大小样例都过了,造hack还没hack了,索性交了,但是有捆绑感觉会爆零,没想到结论是对的,直接A了;打完T1就罚坐了,三个小时就弄出来\(5\)分,当时都绝望了,想到了很多东西。因为感觉T1A不了,后面状态不......
  • 2024MX-MF-DAY1-text题解
    T1【题目描述】有\(n\)个人按编号从\(1\)到\(n\)坐成一圈,即第\(i\in[1,n]\)个人右边是\(i+1\),第\(n\)个人右边的人是\(1\)。初始,每个人手上有\(m\)个球。随后,\(n\)个人按编号从小到大的顺序依次执行如下操作:把自己手中的球分成数量相同且尽可能多的三份,......
  • Mac开发基础18-NSTableView(一)
    NSTableView是macOS应用程序中用于显示和管理数据表格的控件。它提供了丰富的API和高度自定义的能力,使得开发者可以精细地控制表格的显示和行为。本文将详细介绍NSTableView的常见API和一些基础技巧,并深入探讨其相关知识。1.基本使用创建和初始化Objective-C#import......
  • LlamaCoder:一款开源的平替 Claude Artifacts 项目
    LlamaCoder是一个开源项目,旨在提供一种替代ClaudeArtifacts的解决方案。ClaudeArtifacts是一个商业软件,可能包含一些专有技术或特定的功能集,而LlamaCoder则致力于提供类似的功能,但以开源的形式,允许更广泛的社区参与和贡献。由于LlamaCoder是一个假想的开源项目,我将......
  • 免费【2024】springboot 分类信息服务平台移动端的设计与实现
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......
  • 免费【2024】springboot 微信小程序反诈科普平台的设计与实现
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......