获取当前显示的VC

从一个需求问题看iOS的事件处理

本文从一个小需求点开始,简要整理下iOS事件处理相关的内容。鉴于容易吓到小朋友,就不以“一个XX引发的血案”做标题了,虽然本文用这类标题很吸引人也很“适合”。

前两天遇到的一个需求是封装一个SDK,在某个API调用的时候需要知道应用当前展现在屏幕最前层对应的Controller对象。最终大概的方案是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
UIViewController *result = nil ;
 
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
     NSArray *windows = [[UIApplication sharedApplication] windows];
     for (UIWindow * tmpWin in windows)
     {
         if (tmpWin.windowLevel == UIWindowLevelNormal)
         {
             window = tmpWin;
             break ;
         }
     }
}
 
UIView *frontView = [[window subviews] objectAtIndex:0];
id nextResponder = [frontView nextResponder];
 
if ([nextResponder isKindOfClass:[UIViewController class ]])
     result = nextResponder;
else
     result = window.rootViewController;

这其中有Window和Responder的概念,这些都是和iOS事件处理相关的内容,下面基于这个代码示例解释和整理一下。

0. 示例代码解释

前半部分是“找Window”,后半部分是“在Window中找View和对应的Controller”。

在iOS中,window这个概念对应于UIWindow类,主要负责展示视图和做事件分发处理。而UIWindow对象中有一个属性叫做windowLevel,标志着这个window在显示和事件处理方面的层级,我们正常运行中看到的window是默认的UIWindowLevelNormal,对应为0,此外还定义了两个级别的常量,对应statusBar和alert。而这里我们要找的,就是UIWindowLevelNormal这个层面的window对象。

Window既然是展现视图的,那么也就要从view找起,通过index为0的UIView向上找,直到“响应链”上的一个ViewController。

1. Responder链

在上面那段示例代码中,可以看到,后面寻找特定Controller的过程实际上就是根据nextResponder属性进行迭代。这个nextResponder实际上是UIResponder类的一个方法,返回的引用也是一个UIResponder类对象。

UIResponder是什么?它可以是一个UIView(包括UIControl和UIWindow)、UIViewController,甚至可以是一个UIApplication。

看UIResponder类,它提供了很多功能,而其中最主要的自然是负责响应事件。在iOS中,响应的事件可分为3类:

  • UIEventTypeTouches,屏幕触摸事件
  • UIEventTypeMotion,设备接受到的动作
  • UIEventTypeRemoteControl,遥控事件

而这3者都需要Responder链。其中Motion和RemoteControl事件需要FirstResponder,而Touch虽然和此二者不完全相同,对事件的响应路径也是基于Responder链的。

而Responder链的路径如下图所示(引自苹果官方文档):

2. 事件处理基本流程

上面通过对Responder Chain的介绍,解释了上面示例代码中的内容。借这个机会也把iOS事件处理的大致流程。

以触摸事件为例,操作系统会将用户的触屏操作记录下来,封装成事件对象并放到应用的事件队列。应用中的主循环会获取事件队列里的事件对象,交给window对象处理。

Window对象根据事件的情况和Responder Chain分发给特定的Responder对象进行处理。

对于触摸类型的事件,默认情况下,window对象会先将各个事件优先交给Gesture Recognizer分析处理,如果未能识别,特定的view会根据事件的时机做具体的处理。Gesture Recognizer采用优先状态机的方式对用户的手势进行识别。

3. 事件Event

在事件处理过程中,事件Event对象是一个比较基本的要素,我们再来稍微看下。

在iOS中,UIEvent是对应的类。我们可以通过UIKit下的UIEvent头文件来看这个类的定义,虽然这个头文件中有了Event的三种类型及子类型的定义。但毕竟Motion和RemoteControl的事件略有特别,类定义中更多的是触摸事件相关的。

对于Motion事件的处理,官方的文档给出了3个层面的方式:

  • 基本处理,使用UIDevice和Notification,监测orientation的变化
  • 简单响应,通过UIResponder对motion的几个方法定义
  • 复杂处理,使用加速器和陀螺仪相关的framework,对设备的动作细节数据做全面的收集、分析和处理

对于Remote Control,主要是对于多媒体的播放控制,这里不详细说。

最后,我们看下最常见的触摸事件,我们前面说到UIEvent类定义中很多是针对触摸的,其中用到了UITouch。UITouch类对触摸事件的位置、时长、次数、相关的view和所处阶段都有清晰的记录。

这篇文章为本人参考苹果文档整理的原创,欢迎大家沟通交流讨论。

以上转载自:http://www.molotang.com/articles/1513.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 MFC 中,可以使用 CStatic 控件来显示图片。以下是一个简单的示例代码,可以实现在当前窗口显示图片: ```cpp // 假设有一个 CStatic 控件 IDC_IMAGE CStatic* pImageControl = (CStatic*)GetDlgItem(IDC_IMAGE); // 加载图片 CImage image; image.Load(_T("path/to/image.jpg")); // 调整控件大小以适应图片 pImageControl->SetBitmap(image.Detach()); pImageControl->SizeToContent(); ``` 这里的关键是将加载的图片通过 `SetBitmap` 方法设置到 CStatic 控件中,并调用 `SizeToContent` 方法调整控件大小以适应图片。这样就可以在当前窗口中显示图片了。 ### 回答2: 要在VC MFC中将图片显示当前窗口而不是新建窗口显示,可以使用CStatic控件。 首先,在你的MFC对话框或窗口类的头文件中添加一个成员变量,类型为CStatic,例如: CStatic m_staticImage; 接下来,在OnInitDialog()函数中,关联这个变量与对应的控件,调用LoadImage()函数加载图片,并使用SetBitmap()函数将图片显示在CStatic控件上,例如: // 与控件关联 m_staticImage.SubclassDlgItem(IDC_STATIC_IMAGE, this); // 加载图片 HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, L"image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 显示图片 m_staticImage.SetBitmap(hBitmap); 注意:这里的IDC_STATIC_IMAGE是指你在对话框或窗口资源文件中设置的静态控件的ID,image.bmp是你要显示的图片的文件路径。 最后,在OnDestroy()函数中,销毁图片资源,例如: // 销毁图片 m_staticImage.SetBitmap(NULL); 这样就可以在当前窗口中显示图片了。记得在显示图片之后,还需要根据需要处理图片的大小和位置,可以使用MoveWindow()函数进行调整。 ### 回答3: 在VC MFC中要将图片显示当前窗口而不是新建窗口显示,可以通过以下步骤实现: 1. 首先,创建一个控件或者标签(CStatic)来承载图片。该控件或标签可以在对话框资源中添加或者通过代码动态创建。 2. 在对话框的类中添加一个变量来引用该控件,可以通过DDX_Control或者GetDlgItem函数进行关联。 3. 加载要显示的图片资源,可以使用LoadImage或者CImage类的Load函数来加载图片文件。 4. 将加载的图片设置到控件中,可以使用CStatic类的SetBitmap或者SetIcon函数来设置位图或者图标。 5. 在需要显示图片的时候,调用控件的相应函数来进行更新。 下面是一个简单的示例代码,演示了如何在VC MFC的对话框中显示图片到当前窗口: 1. 在对话框资源中添加一个静态文本框控件(IDC_STATIC_IMAGE)。 2. 在对话框类的头文件中添加成员变量用于引用该控件: ``` CStatic m_staticImage; ``` 3. 在DoDataExchange函数中将成员变量与对话框资源中的控件进行关联: ``` DDX_Control(pDX, IDC_STATIC_IMAGE, m_staticImage); ``` 4. 在OnInitDialog函数中加载并显示图片: ``` CImage image; image.Load(_T("image.bmp")); // 加载图片 HBITMAP hBitmap = (HBITMAP)image; // 获取位图句柄 m_staticImage.SetBitmap(hBitmap); // 设置位图到控件 ``` 通过以上步骤,就可以在VC MFC的对话框中将图片显示当前窗口而不是新建窗口显示了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值