【问题标题】:NSTableView: Floating (or fixed) columnsNSTableView:浮动(或固定)列
【发布时间】:2023-03-23 19:51:01
【问题描述】:

我想要实现的是这样的:
DevExpress Grid
Table with fixed columns

以上链接中的表格可以有“固定”列,不随其他内容滚动。

我知道NSTableViewfloatsGroupRows 功能,以及NSScrollViewaddFloatingSubview:forAxis: 方法;但要实现上述目标,这些还不够:

  • 首先列不是NSViews
  • 表头和表内容放在NSScrollView下的2个独立的NSClipViews中(这是NSTableView的默认操作)

所以只要我找不到任何内置的解决方案。我唯一的想法是相邻使用 3 个NSTableViews(左侧+1,右侧+1);并手动同步其中的垂直滚动。如何同步水平滚动,现在这是一个更难的问题。左右两侧不应该滚动,所以应该“浮动”。 对于表格的内容,NSScrollViewaddFloatingSubview:forAxis: 方法应该适用于 IMO(*);但列标题是不同的动物。好的,仍然应该有一种方法可以通过修改列的绘图来实现这种浮动行为......

但是,我仍然没有开始实现上述的,因为我的 NSTableView 已经足够慢了 (NSTableview View Based Scrolling Performance),而且我确信这些加上一些东西会大大减慢它。

有没有人(更好的)想法如何在 Cocoa 中实现浮动列? 非常感谢任何帮助!

编辑

(*):NSScrollViewaddFloatingSubview:forAxis: 不适用于此。正如我现在所看到的,如果赋予此方法的NSViewNSTableView 的子视图,它会得到特殊处理。可能该表将自己的逻辑添加到;现在对我来说,NSTableView 一次只能有 1 个浮动行。

【问题讨论】:

  • 如何同步水平滚动:Synchronizing Scroll Views.
  • 谢谢,有用的资源。 (虽然是垂直滚动的同步,而不是水平滚动。水平滚动不需要任何同步)
  • 我会告诫不要尝试通过组合现成的可可组件来模拟这些屏幕截图。正如您所理解的那样,组合和填充多个表视图,然后同步滚动,然后克服性能问题将成为一个令人头疼的问题。相反,放弃你的理想方法,专注于提出一个以更传统的方式使用可用组件的解决方案——如果你这样做,我认为你会付出很多努力,并最终得到一个很好的 UI更容易使用。
  • 问题是,我找不到任何以常规方式使用可用组件来解决此任务:) 另外,我使用了一个子类 NSTableView,它已经扩展了很多功能;现在这只是一个更改请求。因此,从头开始编写自己的表,或者使用已经编写好的第 3 方组件,现在对我来说不是一个解决方案。

标签: cocoa nstableview floating nstablecolumn


【解决方案1】:

我已经实现了两个 NSTableView 的垂直同步。不太清楚为什么你需要三个,但无论如何。请注意,这是使用 Xamarin.Mac 库的所有 c# 代码。这些是原生 Cocoa 平台的包装器。您必须自己将其转换为 obj c/swift。这应该不难。

从笔尖醒来:

table1.EnclosingScrollView.ContentView.PostsBoundsChangedNotifications = true;
NSNotificationCenter.DefaultCenter.AddObserver (NSView.BoundsChangedNotification, BoundsDidChangeNotification, table1.EnclosingScrollView.ContentView);
table2.EnclosingScrollView.ContentView.PostsBoundsChangedNotifications = true;
NSNotificationCenter.DefaultCenter.AddObserver (NSView.BoundsChangedNotification, BoundsDidChangeNotification, table2.EnclosingScrollView.ContentView);

因此,每当其中一个表滚动时,就会调用 BoundsDidChangeNotification,它负责同步 y 轴。请注意,即使由于惯性滚动或边界的编程更改(或放大/缩小或调整视图大小等)而发生滚动,这也有效。此类事件可能并不总是触发专门用于“用户滚动”的事件,因此,这是更好的方法。下面是 BoundsDidChangeNotification 方法:

public void BoundsDidChangeNotification (NSNotification o)
    {
        if (o.Object == table1.EnclosingScrollView.ContentView) {
            var bounds = new CGRect (new CGPoint (table2.EnclosingScrollView.ContentView.Bounds.Left, table1.EnclosingScrollView.ContentView.Bounds.Top), table2.EnclosingScrollView.ContentView.Bounds.Size);
            if (bounds == table2.EnclosingScrollView.ContentView.Bounds)
                return;
            table2.ScrollPoint (bounds.Location);
        } else {
            var bounds = new CGRect (new CGPoint(table1.EnclosingScrollView.ContentView.Bounds.Left, table2.EnclosingScrollView.ContentView.Bounds.Top), table1.EnclosingScrollView.ContentView.Bounds.Size);
            if (table1.EnclosingScrollView.ContentView.Bounds == bounds)
                return;
            table1.ScrollPoint (bounds.Location);
        }
    }

这里没有什么太花哨的...有一些边界相等检查以避免最终的无限循环(table1 告诉 table2 同步,然后 table2 告诉 table1 等等,永远)。 AFAI 记得,如果你 ScrollPoint 到当前滚动的位置,不会触发 bounds 的变化,但是因为否则会发生无限循环,我认为额外的检查是值得的 - 你永远不知道在未来的 os x 版本中会发生什么。

【讨论】:

    猜你喜欢
    • 2015-05-18
    • 2011-01-23
    • 1970-01-01
    • 2012-04-04
    • 2016-12-29
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 2011-06-12
    相关资源
    最近更新 更多