Недавно, столкнулся с проблемой работы 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)