Недавно, столкнулся с проблемой работы responsiveConfig на iOS 13.x . Описываемые формулы не всегда работали правильно (путали landscape, portrait). Для начала создадим тестовое приложение, очень простое, всего лишь с двумя формулами.
Ext.define('MyApp.view.main.Main', {
extend: 'Ext.Container',
layout: 'fit',
items: [{
xtype: 'button',
responsiveConfig: {
'landscape': {
text: 'landscape'
},
'portrait': {
text: 'portrait'
},
},
},
]
});
В зависимости от ориентации экрана, мы будем менять текст кнопки. Соберем наше приложение, и задеплоим например сюда. Теперь давайте откроем наше приложение в браузере на iPad’e. Тестировать будем на трех браузерах Chrome, FireFox, Safari.
Как мы видим, адекватное поведение только в Safari. В остальных случаях мы видим баг. Для того что бы понять причину бага, следует посмотреть на текущий Ext.mixin.Responsive.context. И там будет видно что, height и width рассчитываются верно, а такие параметры landscape и portrait нет. Последние рассчитываются с помощью функции Ext.dom.Element.getOrientation.
// WIN - это window
// Я вижу что тут забыли что portrait ориентация это [0,180].includes(window.orientation)
// Все остальное landscape
getOrientation: function() {
if (Ext.supports.OrientationChange) {
return (WIN.orientation == 0) ? 'portrait' : 'landscape';
}
return (WIN.innerHeight > WIN.innerWidth) ? 'portrait' : 'landscape';
}
После того как мы добавили поддержку 180 градусов, согласно этому документу Мой iPad перестал показывать landscape в перевернутом виде. Это решило часть проблемы, но не полностью. После долгой и нудной отладки процедуры Ext.mixin.Responsive.updateContext (которая вызывается при resize событии window) было замечено что window.orientation остается старым на момент исполнения процедуры (и соответственно мы не правильно рассчитываем landscape, portrait).
В качестве решения, я предлагаю вызывать обновление контекста (для iOS 13.x) не при событии resize, а при orientationchange (да, это будет медленнее, но там нет этого race condition)
Прикладываю два override которые помогли мне решить проблему
/**
* @class Base.overrides.dom.Element
* @author Dmitry Kazarin <dikazarin@gmail.com>
*
* Альтернативная логика определения ориентации.
* Исправляет баг с определением ориентации.
*
**/
Ext.define('Base.overrides.dom.Element', {
override: 'Ext.dom.Element',
statics: {
getOrientation: function() {
if (Ext.supports.OrientationChange) {
return (window.orientation == 0 || window.orientation == 180) ? 'portrait' : 'landscape';
}
return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
},
}
});
Ext.define('Base.overrides.mixin.Responsive', {
override: 'Ext.mixin.Responsive',
privates: {
statics: {
activate: function() {
const Responsive = Ext.mixin.Responsive;
Responsive.active = true;
Responsive.updateContext();
if (Ext.is.iOS) {
Ext.Viewport.on('orientationchange', Responsive.onResize, Responsive);
} else {
Ext.on('resize', Responsive.onResize, Responsive);
}
},
deactivate: function() {
const Responsive = Ext.mixin.Responsive;
Responsive.active = false;
if (Ext.is.iOS) {
Ext.Viewport.un('orientationchange', Responsive.onResize, Responsive);
} else {
Ext.un('resize', Responsive.onResize, Responsive);
}
},
}
},
function() {
Ext.Object.each(Ext.ClassManager.classes, function(name, cls) {
if (cls.prototype && cls.prototype.mixins && cls.prototype.mixins.hasOwnProperty('responsive')) {
cls.prototype.activate = this.prototype.activate;
cls.prototype.deactivate = this.prototype.deactivate;
}
}, this);
}
});
Можно было конечно поступить проще, и убрать использование Ext.supports.OrientationChange и window.orientation из Ext.dom.Element.getOrientation. Но там видимо ещё что то есть, не во всех случаях работает правильно (а значит есть какой то race condition с обновлением window.orientation)