一. cocos creator 提供的几种适配策略
EXACT_FIT:
整个应用程序在指定区域可见, 无需尝试保留原始纵横比. 可能会出现失真, 应用程序会被拉伸或压缩. 也就是说设计分辨率的长和宽不会等比缩放, 它们会各自进行缩放, 设计分辨率的宽会用 "屏幕宽 / 设计分辨率宽" 作为缩放因子, 设计分辨率的高会用 "屏幕高 / 设计分辨率高" 作为缩放因子.(2.0 版本这个策略有问题, 等修复)
NO_BORDER:
整个应用程序填充指定区域, 没有失真, 但可能会有一些裁剪, 同时保持原样应用程序的纵横比. 这个是等比进行缩放设计分辨率, 取 "屏幕宽 / 设计分辨率宽" "屏幕高 / 设计分辨率高" 中较大的一个作为缩放因子, 比如:"屏幕宽 / 设计分辨率宽" 是 2,"屏幕高 / 设计分辨率高" 是 1, 那么取 2 作为缩放因子, 这个时候高放大两倍, 自然超出屏幕之外看不见了.
SHOW_ALL:
整个应用程序在指定区域可见而不失真, 同时保持原样应用程序的纵横比. 边界可以出现在应用程序的两侧. 这个是等比进行缩放设计分辨率, 取 "屏幕宽 / 设计分辨率宽" "屏幕高 / 设计分辨率高" 中较小的一个作为缩放因子, 比如上述的那个例子, 取 1 作为缩放因子, 宽只放大一倍, 明显不够, 虽然整个应用程序都能看到, 但会有黑边.
FIXED_HEIGHT:
应用程序采用设计分辨率大小的高度并修改内部的宽度画布使其适合设备的纵横比, 不会发生失真. 这个是等比进行缩放设计分辨率, 保持设计分辨率的高度不变, 根据屏幕分辨率改变设计分辨率的宽度, 这个时候设计分辨率和屏幕分辨率一样了, 再进行等比缩放.
FIXED_WIDTH:
这个和 FIXED_HEIGHT 类似, 唯一不同的是它是保持的宽度不变.
是否等比缩放 | 宽的缩放比例 | 高的缩放比例 | 是否改变设计分辨率 | |
EXACT_FIT | 否 | 屏幕宽 / 设计宽 | 屏幕高 / 设计高 | 否 |
NO_BORDER | 是 | 较大的比 | 较大的比 | 否 |
SHOW_ALL | 是 | 较小的比 | 较小的比 | 否 |
FIXED_HEIGHT | 是 | 随便取,因为两个比一样 | 随便取,因为两个比一样 | 是 |
FIXED_WIDTH | 是 | 随便取,因为两个比一样 | 随便取,因为两个比一样 | 是 |
二. cocos 提供的几个获取 View 的函数
cc.view.getDesignResolutionSize()
获取的是你在编辑器中设计的分辨率, 也就是 canvas 组件下设置的设计分辨率.
cc.view.getFrameSize()
获取各种手机, pad 上的屏幕分辨率, 也就是硬件分辨率.
cc.view.getVisibleSizeInPixel()
获取的是 visibleSize 的基础上乘以各种适配策略下的缩放比例后的分辨率.
cc.view.getVisibleSize()
官方文档上说返回视图窗口可见区域尺寸, 经过输出对比发现, 这个可见区域尺寸实际上是指设计分辨率, 不过它返回的是经过各种适配策略后的设计分辨率, 在 EXACT_FIT,NO_BORDER,SHOW_ALL 中因为不改变设计分辨率, 所以和 cc.view.getDesignResolutionSize() 返回的结果一样. 但在 FIXED_HEIGHT,FIXED_WIDTH 中改变了设计分辨率, 所以返回的是修改后的设计分辨率.
后续通过查看 creator 源码也证实了这一点, 以下是源码解释:
- /**
- * !#en
- * Returns the visible area size of the view port.
- * !#zh 返回视图窗口可见区域尺寸.
- * @method getVisibleSize
- * @return {Size}
- */
- getVisibleSize: function () {
- return cc.size(this._visibleRect.width,this._visibleRect.height);
- },
getVisibleSize() 返回的是 this._visbleRect 的值, 我们来找找 this._visbleRect 在哪进行赋值
- cc.JS.mixin(View.prototype, {
- init () {
- .........
- var w = cc.game.canvas.width, h = cc.game.canvas.height;
- this._designResolutionSize.width = w;
- this._designResolutionSize.height = h;
- this._originalDesignResolutionSize.width = w;
- this._originalDesignResolutionSize.height = h;
- this._viewportRect.width = w;
- this._viewportRect.height = h;
- this._visibleRect.width = w;
- this._visibleRect.height = h;
- cc.winSize.width = this._visibleRect.width;
- cc.winSize.height = this._visibleRect.height;
- ......
- },
- ........
- }
可以看到在这里给一些保持分辨率的对象赋了同一个值, 那就是 cc.game.canvas 里面的值, 这个值代表的是屏幕分辨率, 因为后续进行适配策略是用的也是这个值, 这就奇怪了, 都一样了还怎么比较, 每个函数返回的值也应该一样呀, 所以一定有一个地方改变了它们, 继续找.
- setDesignResolutionSize: function (width, height, resolutionPolicy) {
- .........
- this.setResolutionPolicy(resolutionPolicy);
- var policy = this._resolutionPolicy;
- if (policy) {
- policy.preApply(this);
- }
- ..........28
- this._originalDesignResolutionSize.width = this._designResolutionSize.width = width;
- this._originalDesignResolutionSize.height = this._designResolutionSize.height = height;
- var result = policy.apply(this, this._designResolutionSize);
- if(result.scale && result.scale.length === 2){
- this._scaleX = result.scale[0];
- this._scaleY = result.scale[1];
- }
- if(result.viewport){
- var vp = this._viewportRect,
- vb = this._visibleRect,
- rv = result.viewport;
- vp.x = rv.x;
- vp.y = rv.y;
- vp.width = rv.width;
- vp.height = rv.height;
- vb.x = 0;
- vb.y = 0;
- vb.width = rv.width / this._scaleX;
- vb.height = rv.height / this._scaleY;
- }
- policy.postApply(this);
- cc.winSize.width = this._visibleRect.width;
- cc.winSize.height = this._visibleRect.height;
- ........64 },
我们直接来看 setDesignResolutionSize() 这个函数, 它是通过设置设计分辨率和匹配模式来进行游戏画面的屏幕适配. 所以它必然会改变相应的值. 可以看到第 29,30 行把我们传进来的设计分辨率赋值给了 this._originalDesignResolutionSize 和 this._designResolutionSize, 改变了它们的值. 那么什么时候改变 this._visbleRect 的值呢, 我们看 39 行到 52 行, 很明显就是在这里改变的. vb.width = rv.width / this._scaleX; vb.height = rv.height / this._scaleY;
那么凭什么说 this._visbleRect 是适配策略后到设计分辨率呢, 我们来看看 result.viewport 里面是什么东西, var result = policy.apply(this, this._designResolutionSize);policy 是一个适配策略的实例, 它根据你传入的适配策略来决定调用哪个适配策略的方法, 类似于 c++ 中的多态. 然后我们来看看每个适配策略做了什么, 这里主要就拿 SHOW_ALL 和 FIXED_HEIGHT 来加以说明:
- var ShowAll = cc.Class({
- name: "ShowAll",
- extends: cc.ContentStrategy,
- apply: function (view, designedResolution) {
- var containerW = cc.game.canvas.width, containerH = cc.game.canvas.height,
- designW = designedResolution.width, designH = designedResolution.height,
- scaleX = containerW / designW, scaleY = containerH / designH, scale = 0,
- contentW, contentH;
- scaleX < scaleY ? (scale = scaleX, contentW = containerW, contentH = designH * scale)
- : (scale = scaleY, contentW = designW * scale, contentH = containerH);
- return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
- }
- });
- var FixedHeight = cc.Class({
- name: "FixedHeight",
- extends: cc.ContentStrategy,
- apply: function (view, designedResolution) {
- var containerW = cc.game.canvas.width, containerH = cc.game.canvas.height,
- designH = designedResolution.height, scale = containerH / designH,
- contentW = containerW, contentH = containerH;
- return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
- }
- });
可以看到它们都继承于 cc.ContentStrategy. 在 apply 函数中返回值来自于 this._buildResult() 函数, 我们来看这个函数:
- _buildResult: function (containerW, containerH, contentW, contentH, scaleX, scaleY) {
- // Makes content fit better the canvas
- Math.abs(containerW - contentW) < 2 && (contentW = containerW);
- Math.abs(containerH - contentH) < 2 && (contentH = containerH);
- var viewport = cc.rect((containerW - contentW) / 2, (containerH - contentH) / 2, contentW, contentH);
- // Translate the content
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS){
- //TODO: modify something for setTransform
- //cc.game._renderContext.translate(viewport.x, viewport.y + contentH);
- }
- this._result.scale = [scaleX, scaleY];
- this._result.viewport = viewport;
- return this._result;
- },
主要来看 this._result 中的 viewport 的值, 它的 width 是 contentW,height 是 contentH. 到这里, 一切都清楚了. 我们假设屏幕分辨率的宽高是 Pw 和 Ph, 设计分辨率的宽高是 Sw 和 Sh.
那么在 SHOW_ALL 中: 假设 Pw/Sw 更小, contentW=Pw,contentH=Sh*(Pw/Sw), 在进行 this._visbleRect 赋值时, width = Pw/(Pw/Sw) = Sw,height = (Sh*(Pw/Sw))/(Pw/Sw) = Sh, 所以设计分辨率没有改变.
在 FIXED_HEIGHT 中: contentW=Pw,contentH=Ph,scale = Ph/Sh, 在进行 this._visbleRect 赋值时, width = Pw/(Ph/Sh) = Sh*(Pw/Ph),height = Ph/(Ph/Sh) = Sh, 所以设计分辨率是改变的.
从上述代码还发现 cc.winSize 和 cc.view.getVisibleSize() 的返回值是一样的, 二者可以通用.
在进行屏幕适配时主要用到 cc.view.getDesignResolutionSize() 和 cc.view.getFrameSize() 两个函数.
来源: https://www.cnblogs.com/liylove/p/13808142.html