OpenGL ES: iOS 自定义 UIView 响应屏幕旋转
iOS下使用OpenGL 如果使用GLKit View 那么不用担心屏幕旋转的问题,说明如下:
If you change the size, scale factor, or drawable properties of a GLKit view, it automatically deletes and re-creates the appropriate framebuffer objects and renderbuffers the next time its contents are drawn.
GLKit view 自动设置好了 framebuffer 和 renderbuffer 对象,使用者直接设置具体的OpenGL 参数即可。但是GLKit view 在iOS10 下存在一些问题,不能使用,只能继承最简单的UIView,那么所有相关的设置都需要自己完成。
屏幕旋转时需要做的事
现在要自己处理屏幕旋转的事件。这一部分主要讲在屏幕旋转后我们需要做什么事情来让原来的图像以新的屏幕尺寸显示出来。如果参考Android的设计,解决思路就是在屏幕旋转的时候将所有的对象销毁再根据当前的屏幕状态重新创建。简单粗暴但是效率不行。我想不销毁对象的情况下,直接重新设置宽高数据让OpenGL绘制出正确的图像。于是我调用了如下的函数:
glViewport(0, 0, (GLsizei) (size.width * scale), (GLsizei) (size.height * scale));
_renderController->InitUniforms((int) (size.width * scale), (int) (size.height * scale));
首先设置viewport 然后第二行 InitUniforms 函数具体做的事情就是重新设置投影矩阵。很遗憾,这样的做法没有效果,将屏幕从竖屏旋转到横屏时,得到的结果如下:
上半部分什么也没有,下半部分扭曲严重。
问题出在 renderbuffer
Yes, the renderbuffer must be recreated when the interface is rotated, and set to the new size.
所以还需要重新创建renderbuffer,
// first DELETE buffers
glDeleteRenderbuffers(...);
glDeleteFramebuffers(...);
// recreate
glGenFramebuffers(1, &_framebuffer);
glGenRenderbuffers(1, &_renderbuffer);
// bind buffer and set framebuffer and renderbuffer...
具体代码可以参考Recreating the render buffer causes a crash on 3GS device (OpenGL ES 1.1)
在何处做上述的事情?
这一部分讲如何编码来准确监听屏幕旋转事件,来插入上面的那些代码。我们自定义我们的view(UIView),上级的view controller使用 [self.view addSubview:_subView]; 来将自定义view加进来。但是当旋转的事件通知到上级的view controller时, 他没有办法去通知subview。我们要自己找个时间点去通知底下的subview.看官方文档:
Instead, rotations are treated as a change in the size of the view controller’s view and are therefore reported using the
viewWillTransitionToSize:withTransitionCoordinator:method. When the interface orientation changes, UIKit calls this method on the window’s root view controller. That view controller then notifies its child view controllers, propagating the message throughout the view controller hierarchy.The
viewWillLayoutSubviewsmethod is also called after the view is resized and positioned by its parent.
如果你需要监听旋转从开始之前到结束的整个过程,推荐使用viewWillTransitionToSize:withTransitionCoordinator: 用法示例:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// Code here will execute before the rotation begins.
// Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Place code here to perform animations during the rotation.
// You can pass nil or leave this block empty if not necessary.
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Code here will execute after the rotation has finished.
// Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]
}];
}
来自 SO What is the “right” way to handle orientation changes in iOS 8?
另外一个,旋转完成后,调用 viewWillLayoutSubviews 方法。很有意思,上面的方法的 completion 回调也是在旋转完成以后被调用的,那么用哪个更合适呢?我自己试验了一下,会早于comletion回调,这个方法其实是在上级的view将要去layoutSubview的时候调用的,还没有完成呢!而且实践表明,如果在comletion回调中做,其实是错误的图像已经显示出来了,然后又去改变他,这里的最终的旋转效果就很糟糕了。
我的代码如下:
/**
Called just after the view controller's view's layoutSubviews method is invoked.
*/
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_subView.frame = self.view.frame;
[_subView layoutIfNeeded];
}
设置subview的frame尺寸以后,强制让他layout,会调用到subView自己的layoutSubviews方法,在里面做具体的操作即可。
值得参考的文档,来自大神,目前还是草稿状态:【草稿】iOS OpenGL ES 3 编程 2:绘制三角形、屏幕旋转与架构设计
OpenGL ES: iOS 自定义 UIView 响应屏幕旋转的更多相关文章
- OpenGL ES 响应屏幕旋转 iOS
iOS下使用OpenGL 如果使用GLKit View 那么不用担心屏幕旋转的问题,说明如下: If you change the size, scale factor, or drawable pr ...
- 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- IOS开发——手动设置屏幕旋转
在移动开发过程.您可能需要跨越看看你的手机.有可能是所有的接口必须跨越,有可能是一个交叉通过电话,当用户当,你的接口也希望他能跨越.还有可能的是,界面的一部分需要被侧向显示.视情况而定,有不同的方法来 ...
- IOS自定义UIView
IOS中一般会用到几种方式自定义UIView 1.继承之UIView的存代码的自定义View 2.使用xib和代码一起使用的自定义View 3.存xib的自定义View(不需要业务处理的那种) 本文主 ...
- iOs 自定义UIView 日历的实现 Swift2.1
学习Swift有一个月了,动手写一个UIView吧. 所有源代码在最后,直接用就可以了,第一次写Swift,和C#,Java还是有区别的 (博客园可以考虑在代码插入中添加Swift的着色了) 1 函 ...
- Android屏幕旋转
一个手机最基本的旋转方向有上面4种,而在Android开发中,涉及到屏幕旋转的地方很多,而且各个函数给出的角度值都不一样,比如 Activity的getRotate,Camera的setDisplay ...
- ##DAY3 自定义视图、视图控制器、视图控制器指定视图、loadView、 viewDidLoad、MVC、屏幕旋转、内存警告
##DAY3 自定义视图.视图控制器.视图控制器指定视图.loadView. viewDidLoad.MVC.屏幕旋转.内存警告 #pragma mark ———————自定义视图的步骤 —————— ...
- IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)
OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...
随机推荐
- Jenkins之定时任务
H的用法: H 10 * * * ,这里H不是小时的意思,符号H(代表“Hash”,后面用“散列”代替) 符号H 在一定范围内可被认为是一个随机值,但实际上它是任务名称的一个散列而不是随机函数,每个 ...
- AC自动机解题记录
1.HDU 2222 Keywords Search 模板题 #include <bits/stdc++.h> #define fir first #define sec second # ...
- linux服务器系统负载监控-shell脚本
一.监控服务器系统负载情况: 1.用uptime命令查看当前负载情况(1分钟,5分钟,15分钟平均负载情况) # uptime 15:43:59 up 186 days, 20:04, 1 us ...
- 251. Flatten 2D Vector 平铺二维矩阵
[抄题]: Implement an iterator to flatten a 2d vector. Example: Input: 2d vector = [ [1,2], [3], [4,5,6 ...
- printf 字符串格式化
在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望.由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出 ...
- centos 7 安装redis 3.2.1
https://www.cnblogs.com/zuidongfeng/p/8032505.html 下载安装包: http://download.redis.io/releases/ 根据需要自己选 ...
- flask 未完待续
Flask - 一个短小精悍.可扩展的一个Web框架很多可用的第三方组件:http://flask.pocoo.org/extensions/blogs:https://www.cnblogs.com ...
- HttpWebRequest 高效并发问题
默认请求连接数 是2,在服务器操作系统上默认为10. 如果不修改这个并发连接限制,那么客户端同时可以建立的 http 连接数就只有2个或10个. System.Net.ServicePointMana ...
- CentOS_mini下安装docker 之 yum mount
--->linux 终端输出太多前面看不到的解决办法:shift+page up --->mount命令[-参数] [设备名称] [挂载点] mkdir /mnt/CentOS mount ...
- trinitycore 魔兽服务器源码分析(二) 网络
书接上文 继续分析Socket.h SocketMgr.h template<class T>class Socket : public std::enable_shared_from_t ...