UIViewContentModeScaleAspectFit
这种模式,限制宽高的某一方, 会有黑边。
如果是竖屏,那就固定宽度, 如果是横屏,那就固定高度。
UIViewContentModeScaleAspectFill
这种是填充模式,不会拉伸,但是如果不是等比的宽高(手机16:9)可能会切割。
要实现自适应旋转,需要重写layoutSubviews方法
iOS layout机制相关方法
- (CGSize)sizeThatFits:(CGSize)size
- (void)sizeToFit
——————-
- (void)layoutSubviews
- (void)layoutIfNeeded
- (void)setNeedsLayout
——————–
- (void)setNeedsDisplay
- (void)drawRect
layoutSubviews在以下情况下会被调用:
-
init初始化不会触发layoutSubviews
但是是用initWithFrame 进行初始化时,当rect的值不为CGRectZero时,也会触发
-
addSubview会触发layoutSubviews
-
设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
-
滚动一个UIScrollView会触发layoutSubviews
-
旋转Screen会触发父UIView上的layoutSubviews事件
-
改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
在苹果的官方文档中强调:
You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.
layoutSubviews, 当我们在某个类的内部调整子视图位置时,需要调用。
反过来的意思就是说:如果你想要在外部设置subviews的位置,就不要重写。
刷新子对象布局
-layoutSubviews方法:
这个方法,默认没有做任何事情,需要子类进行重写
-setNeedsLayout方法:
标记为需要重新布局,异步调用layoutIfNeeded刷新布局,
不立即刷新,但layoutSubviews一定会被调用
-layoutIfNeeded方法:
如果有需要刷新的标记,立即调用layoutSubviews进行布局
(如果没有标记,不会调用layoutSubviews)
如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局
在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]
从5可以看出,旋转会调layoutSubviews,
所以,需要重写方法,在旋转的时候进入处理代码:
- (void)layoutSubviews {
[super layoutSubviews];
//屏幕的整个空间
CGRect rect = [UIScreen mainScreen].bounds;
self.frame = rect;
//从父视图的view中取出子视图OpenGL的view
UIView *openglView = [self viewWithTag:11001];
if (openglView) {
openglView.frame = rect;
}
}
注:[UIScreen mainScreen].bounds方法,
在不同iPhone设备各个屏幕分辨率:
4/4S : 320*480 1.5
5/5S : 320*568 568/320 = 1.775
6 : 750*1334 1.77866667
6+ : 1080*1920 1.77777778
16/9 = 1.77777778
所以可能会有黑边
另外,如果横竖屏切换的时候,可能Fit和Fill模式需要动态变化,
这时候就要在ijk SDL模块取修改opengl的渲染了。
防止屏幕黑边的办法:正常的竖屏直播用fill,竖屏不做旋转。
如果是宽大于高的源,用fit模式。
IJKSDLGLView.m
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_tryLockErrorCount = 0;
self.glActiveLock = [[NSRecursiveLock alloc] init];
_registeredNotifications = [[NSMutableArray alloc] init];
[self registerApplicationObservers];
[self registerApplicationObservers];
_didSetupGL = NO;
+ //gongjia modify. refresh for fit/fill mode
+ //[self setupGLOnce];
}
return self;
}
- (void)display: (SDL_VoutOverlay *) overlay
{
if (overlay == NULL)
return;
+ if (overlay->w > overlay->h) {
+ [self setContentMode:UIViewContentModeScaleAspectFit];
+ }
if (![self setupGLOnce])
return;
......
添加自适应模式代码:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.view.frame = aview.bounds;
aview.autoresizesSubviews = YES;
网友评论
这种模式,限制宽高的某一方, 会有黑边。
如果是竖屏,那就固定宽度, 如果是横屏,那就固定高度。
这样子说不对,没有说固定哪个的,看下面代码:
float dH = view_height / video_height;
float dW = view_width / video_width;
float dd = MIN(dH, dW); // UIViewContentModeScaleAspectFit 模式取最小
// fload dd = MAX(dH, dW); // UIViewContentModeScaleAspectFill模式取最大
float h = (video_height * dd / view_height);
float w = (video_width * dd / view_width);
接着用 w,h构造vertices
vertices[0] = -w;
vertices[1] = -h;
vertices[2] = -w;
vertices[3] = h;
vertices[4] = w;
vertices[5] = -h;
vertices[6] = w;
vertices[7] = h;
一般都是通过vertices 来实现,也可以通过vertices 和 texturecor 配合来实现。