首页 > 其他分享 >Mac开发基础08-NSWindow(二)

Mac开发基础08-NSWindow(二)

时间:2024-08-06 14:40:20浏览次数:5  
标签:窗口 08 window alert Mac Objective NSWindow Swift

NSWindow 其他使用和技巧

NSWindow 是 macOS 应用程序中用于显示和管理窗口的核心类。可用于创建、编辑和管理应用程序的窗口。

1. 自定义窗口的内容视图层级

替换默认的内容视图

NSWindow 默认包含一个内容视图,你可以使用自定义内容视图来替换它。

Objective-C
NSView *customView = [[NSView alloc] initWithFrame:window.contentView.bounds];
window.contentView = customView;
Swift
let customView = NSView(frame: window.contentView!.bounds)
window.contentView = customView

使用 NSViewController 管理内容视图

你可以使用 NSViewController 来管理窗口的内容视图,这样可以更好地组织代码和管理视图逻辑。

Objective-C
NSViewController *customViewController = [[NSViewController alloc] init];
customViewController.view = customView;
window.contentViewController = customViewController;
Swift
let customViewController = NSViewController()
customViewController.view = customView
window.contentViewController = customViewController

2. 实现自定义窗口动画效果

使用 Core Animation 自定义动画

为了使窗口的出现更具吸引力,可以使用 Core Animation 为其添加淡入淡出的动画效果。

Objective-C
#import <QuartzCore/QuartzCore.h>

- (void)animateWindowAppearance:(NSWindow *)window {
    CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeAnimation.fromValue = @0;
    fadeAnimation.toValue = @1;
    fadeAnimation.duration = 1.0;

    [window.contentView setWantsLayer:YES];
    [window.contentView.layer addAnimation:fadeAnimation forKey:@"fadeIn"];
    window.alphaValue = 1;
}
Swift
import QuartzCore

func animateWindowAppearance(_ window: NSWindow) {
    let fadeAnimation = CABasicAnimation(keyPath: "opacity")
    fadeAnimation.fromValue = 0
    fadeAnimation.toValue = 1
    fadeAnimation.duration = 1.0
    
    window.contentView?.wantsLayer = true
    window.contentView?.layer?.add(fadeAnimation, forKey: "fadeIn")
    window.alphaValue = 1
}

3. 窗口模态(Modal)展示

模态窗口用于阻止用户与其他窗口交互直到完成当前窗口的任务。可以应用模态到整个应用或某个特定窗口。

应用模态

Objective-C
NSWindow *modalWindow = [[NSWindow alloc] initWithContentRect:frame
                                                    styleMask:NSWindowStyleMaskTitled
                                                      backing:NSBackingStoreBuffered
                                                        defer:NO];
[NSApp runModalForWindow:modalWindow];
Swift
let modalWindow = NSWindow(contentRect: frame, styleMask: [.titled], backing: .buffered, defer: false)
NSApp.runModal(for: modalWindow)

窗口模态

Objective-C
[window beginSheet:modalWindow completionHandler:^(NSModalResponse returnCode) {
    // 处理模态结束
}];
Swift
window.beginSheet(modalWindow, completionHandler: { response in
    // 处理模态结束
})

4. 自定义窗口阴影

阴影可以使窗口看起来更立体,以下为自定义窗口阴影的示例。

Objective-C
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowBlurRadius = 10.0;
shadow.shadowOffset = NSMakeSize(5, -5);
shadow.shadowColor = [[NSColor blackColor] colorWithAlphaComponent:0.5];
window.shadow = shadow;
Swift
let shadow = NSShadow()
shadow.shadowBlurRadius = 10.0
shadow.shadowOffset = NSSize(width: 5, height: -5)
shadow.shadowColor = NSColor.black.withAlphaComponent(0.5)
window.shadow = shadow

5. 验证窗口大小调整

可以通过实现 windowWillResize 方法来控制窗口调整大小的范围。

Objective-C
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize {
    NSSize newSize = frameSize;
    if (frameSize.width < 800) {
        newSize.width = 800;
    }
    if (frameSize.height < 600) {
        newSize.height = 600;
    }
    return newSize;
}
Swift
func windowWillResize(_ sender: NSWindow, to frameSize: NSSize) -> NSSize {
    var newSize = frameSize
    if frameSize.width < 800 {
        newSize.width = 800
    }
    if frameSize.height < 600 {
        newSize.height = 600
    }
    return newSize
}

6. 自定义窗口关闭行为

在关闭窗口前,可以弹出警告框来确认用户的操作。

Objective-C
- (BOOL)windowShouldClose:(NSWindow *)sender {
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:@"Confirm"];
    [alert setInformativeText:@"Are you sure you want to close this window?"];
    [alert addButtonWithTitle:@"Yes"];
    [alert addButtonWithTitle:@"No"];
    [alert setAlertStyle:NSAlertStyleWarning];
    return ([alert runModal] == NSAlertFirstButtonReturn);
}
Swift
func windowShouldClose(_ sender: NSWindow) -> Bool {
    let alert = NSAlert()
    alert.messageText = "Confirm"
    alert.informativeText = "Are you sure you want to close this window?"
    alert.alertStyle = .warning
    alert.addButton(withTitle: "Yes")
    alert.addButton(withTitle: "No")
    return alert.runModal() == .alertFirstButtonReturn
}

7. 窗口透明度和鼠标事件传递

设置窗口透明度

窗口透明度和背景透明设置可以实现具有不规则形状和透明背景的窗口。

Objective-C
window.opaque = NO;
window.backgroundColor = [NSColor clearColor];
Swift
window.isOpaque = false
window.backgroundColor = .clear

忽略鼠标事件

如需让窗口忽略鼠标事件,可以设置 ignoresMouseEvents 属性:

Objective-C
window.ignoresMouseEvents = YES;
Swift
window.ignoresMouseEvents = true

8. 使用 NSWindowController 管理窗口

使用 NSWindowController 可以更好地管理和组织你的窗口代码,比如在多窗口应用程序中。

Objective-C
NSWindowController *windowController = [[NSWindowController alloc] initWithWindow:window];
[windowController showWindow:nil];
Swift
let windowController = NSWindowController(window: window)
windowController.showWindow(nil)

9. 窗口层级管理

管理窗口层级可以控制窗口在不同层级的显示顺序。例如,将窗口设置为浮动窗口使它总是在其他窗口之上。

Objective-C
window.level = NSFloatingWindowLevel;
Swift
window.level = .floating

10. 使用 KVO 观察属性变化

通过 KVO 机制,可以监听窗口的属性变化,并根据变化作出相应处理。

Objective-C
@interface CustomWindowObserver : NSObject

@property (nonatomic, strong) NSWindow *observedWindow;

- (instancetype)initWithWindow:(NSWindow *)window;

@end

@implementation CustomWindowObserver

- (instancetype)initWithWindow:(NSWindow *)window {
    if (self = [super init]) {
        self.observedWindow = window;
        [window addObserver:self forKeyPath:@"isVisible" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"isVisible"]) {
        NSLog(@"Window visibility changed: %@", change[NSKeyValueChangeNewKey]);
    }
}

- (void)dealloc {
    [self.observedWindow removeObserver:self forKeyPath:@"isVisible"];
}

@end
Swift
class CustomWindowObserver: NSObject {
    private var observation: NSKeyValueObservation?

    init(window: NSWindow) {
        super.init()
        observation = window.observe(\.isVisible, options: [.new]) { window, change in
            if let isVisible = change.newValue {
                print("Window visibility changed: \(isVisible)")
            }
        }
    }
}

底层实现与原理

1. 窗口管理由 AppKit 和 Core Graphics 协同完成

NSWindow 是 AppKit 框架的一部分,但其底层渲染和管理依赖于 Core Graphics 框架。AppKit 负责窗口的高层逻辑和事件处理,而 Core Graphics 负责实际的渲染与显示。

2. 窗口的层级管理

在 macOS 中,窗口有不同的层级,如普通窗口、浮动窗口和主窗口。不同层级的窗口管理由系统层面的 WindowServer 处理。通过设置窗口的 level 属性,开发者可以控制窗口在这些层级之间切换。

3. 窗口的事件处理机制

窗口的事件处理包括鼠标、键盘等用户交互事件。这些事件会优先传递到对应的 NSWindow,再由窗口进一步传递到其内容视图或子视图。AppKit 通过事件循环(Run Loop)来管理事件的分发与处理。

4. 窗口的图像缓存

为了提升性能,窗口的内容通常会被缓存起来。如果窗口内容频繁变化,可以通过设置 backingType 属性来优化绘制性能。

Objective-C
window.backingType = NSBackingStoreBuffered;
Swift
window.backingType = .buffered

标签:窗口,08,window,alert,Mac,Objective,NSWindow,Swift
From: https://www.cnblogs.com/chglog/p/18345085

相关文章

  • Mac开发基础06-NSView(二)
    要理解NSView更深层的知识,涉及到其渲染机制、事件处理流程、与CALayer的关系及性能优化等方面。1.NSView绘制和渲染机制NSView的绘制过程主要依赖于drawRect:(Objective-C)或draw(_:)(Swift)方法。这个方法被调用是由系统驱动的,通常发生在需要重新绘制视图的时候,如窗口首次......
  • Mac开发基础05-NSView
    NSView概述NSView是macOS应用中所有用户界面元素的基类。它提供了一系列功能用于视图的绘制、事件处理、动画、自动布局等。1.基本属性bounds和framebounds描述了视图自身坐标系中的矩形区域,而frame描述了视图在其父视图坐标系中的矩形区域。Objective-CNSView*v......
  • 洛谷P1081【NOIP2012提高组】开车旅行
    题目见[NOIP2012提高组]开车旅行-洛谷(懒得打题目了)我们直接上代码#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#include<cstring>#include<iomanip>#include<algorithm>#include<ctime>#include<queue>......
  • 20240806:点分治,虚树选做
    POJ-1741Tree题意:给定一棵树,求多少无序对\((u,v)\)满足\(\text{dist}(u,v)\lek\)。对于树上的路径进行分类:经过根;不经过根。第二类路径点可以通过递归子树求出。对于经过根的路径,可以一遍dfs求出每个点到根的距离\(\text{dis}(u)\)。问题转化为求\(\text{dis}(u)......
  • T240806【2-(一)-1】
    [T240806]设连续函数\(C:~z=z(t),~t\in[\alpha,\beta]\),有\(z'(t_0)\neq0~~(t_0\in[\alpha,\beta])\),试证明曲线\(C\)在点\(z(t_0)\)处有切线.证:先证明曲线\(C\)存在无重点的\(z(t_0)\)邻域.由题设知\(\exists\delta>0\),对\(\forallt_1\inU_{\delta}^......
  • Plugin Boutique Scaler EQ V1.1.3_WIN-TCD&MAC-HCiSO(2024.08更新),持续更新长期有效
    一。PluginBoutiqueScalerEQ1.1.3WIN-TCD&MAC-HCiSO   紧随屡获殊荣的音乐理论插件Scaler之后,ScalerEQ以一种引人注目的全新方式提供了音乐性和色彩的均衡。ScalerEQ是PluginBoutique推出的一款创新均衡器插件,结合传统和和声均衡功能,专注于音乐理论,为音乐制作和混......
  • [20240804]关于kitty设置与linux LANG环境设置问题.txt
    [20240804]关于kitty设置与linuxLANG环境设置问题.txt--//更正我以前理解的一个混沌的地方:--//我以前个人的工作习惯:LANG=en_US,kittyRemotecharacterset选择Usefontencoding.--//目前这样的设置存在一些问题:--//kitty设置LANG=en_US.UTF-8的情况下,kittywindow->Trans......
  • L2-008 最长对称子串 C++
    对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定IsPAT&TAPsymmetric?,最长对称子串为sPAT&TAPs,于是你应该输出11。输入格式:输入在一行中给出长度不超过1000的非空字符串。输出格式:在一行中输出最长对称子串的长度。输入样例:IsPAT&TAPsymmetric?输出样......
  • A087-基于SpringBoot+Vue实现的超市管理系统(源码+数据库+部署文档+部署演示视频)
    (======查看博主个人介绍,有源码获取联系方式========)这里提供的系统介绍和演示视频,展示了一个基于SpringBoot和Vue实现的超市管理系统,采用了前后端分离的架构方式。系统设计包括管理员和员工两种角色,涵盖了销售管理、人事管理、个人中心、库存管理、会员管理、系统管理和商品管......
  • 【闲话】08.05.24
    0805闲话头图:今日推歌:《1212。》エイハブ/A4。おおおのべつ幕無しのこの世噢噢噢如此无止境的人世间本能の赴くままに在本能的驱使下随之逐流生きる意義は推して知るべし最后在其中知晓活着的意义そりゃ幸じゃんか这是多么幸运啊好久没听到这么舒服的人声了…......