sencha full framework examples example architect extjs sencha-touch sencha-touch-2

extjs - full - sencha touch download



Sencha Touch: Al hacer clic rápidamente en un botón se presionará una vista dos veces (10)

Supongamos que tengo un botón que desencadena una nueva vista. Noté que si hago clic en él más de una vez, lo suficientemente rápido, empujará la misma vista dos veces.

Puede imitar este comportamiento utilizando sus documentos oficiales en esta página, donde tienen una muestra en vivo: http://docs.sencha.com/touch/2-0/#!/guide/navigation_view

la pregunta clara es, ¿cómo prevenirla?


El enmascaramiento evita con éxito el problema del doble golpeteo.

En mi código estoy usando dos funciones para el contenedor de navegación mask / unmask:

/** * Mask container with rolling wheel. Usually need if Ajax-request is sent to the server and app waiting for response * Best practice is masking the current navigator container, to prevent blocking whole app. Method warns if no container * is defined. In some cases warning could be suppress with parameter * * @param container * @param {boolean} [suppressWarning] */ startLoading: function(container, suppressWarning) { var loadingComponent = container; if (!loadingComponent) { // <debug> if (!suppressWarning) { console.warn(''Please define navigator container for non-blocking operation, or define suppressWarning parameter''); } // </debug> loadingComponent = Ext.Viewport; } // var lastMaskedContainer = container; this.lastMaskedContainer = container; loadingComponent.setMasked({ xtype: ''loadmask'', message: ''Loading...'' }); /* Ext.defer(function() { lastMaskedContainer.setMasked(false); }, Pipedrive.app.maskingTimeout * 1000) */ }, /** * * @param {Ext.Container} container * @param {boolean} [suppressWarning] */ stopLoading: function(container, suppressWarning) { var loadingComponent = container; if (!loadingComponent) { // <debug> if (!suppressWarning) { console.warn(''Please define either navigator container for non-blocking operation, or define suppressWarning parameter''); } // </debug> loadingComponent = Ext.Viewport; } var alreadyMasked = loadingComponent.getMasked(); var lastMaskedContainer = this.lastMaskedContainer; if (!alreadyMasked && !suppressWarning) { // <debug> if (lastMaskedContainer != container) { console.warn(''Found Start/Stop Loading inconsistency. Please revise code'' + (container ? ''. Container: '' + container.getId() : ''Ext.Viewport'') + (lastMaskedContainer ? '', last masked container: '' + lastMaskedContainer.getId() : '''') ); } // </debug> loadingComponent = Ext.Viewport; } loadingComponent.setMasked(false); }

que en el controlador de toque:

onDealDetailsTap: function(ct) { console.log(''onDealDetailsTap'', ct); var form = ct.getReferenceForm(), navigatorContainer = this.getNavigatorContainer(form), model = form.getRecord(); UiHelper.startLoading(navigatorContainer); Ext.Viewport.fireEvent(''detailfields'', { title: model.get(''title''), id: model.get(''id''), store: ''DealFields'', navigatorContainer: navigatorContainer }) },

para limpiar la máscara de carga:

control : { activitiesContainer: { push: ''onPushActivitiesContainer'' }, onPushActivitiesContainer: function(ct) { //console.log(''onPushActivitiesContainer'', ct); UiHelper.stopLoading(ct); },

especialmente es genial para esperar solicitudes de ajax a largo plazo ...

Saludos, Oleg


Simplemente suspende los eventos en el botón cuando se toca y retomales cuando la vista está presionada

button.suspendEvents(); ... button.resumeEvents();

No creo que haya otra manera. Como desarrollador o usuario, cuando toca un botón dos veces, espera que se llame al controlador de eventos dos veces.

Espero que esto ayude


simplemente enmascarar todo el contenedor y luego desenmascararlo; crea una referencia para el contenedor o panel en el que existe el botón en tu controlador y en el conjunto de tap:

ref.setMasked(true)

Después de empujar la nueva vista, simplemente desenmascarar

ref.setMasked(false)


Otro método es verificar cuál es la vista activa, y solo presionar si no es lo mismo que la vista que está a punto de pulsar. He probado esto y funciona.

P.ej

if (this.getNavigationView().getActiveItem().xtype != "someView") { this.getNavigationView().push({ xtype: "someView" }); }


Extendiendo la respuesta de jayteejee, he anulado el método push en una vista de navegación personalizada, como esta:

Ext.define(''BT.navigation.View'', { extend: ''Ext.navigation.View'', xtype: ''btnavigationview'', push: function (view) { if(this.getActiveItem().xtype != view.xtype) this.callParent(arguments); else console.warn("Prevented pushing a potentially duplicate view of xtype: " + view.xtype); } });

No estoy del todo seguro de si la suposición de xtype es lo suficientemente segura, pero no puedo pensar en ninguna situación en mi aplicación actual que requiera que una vista presione otra vista del mismo tipo en la pila de navegación. Por lo tanto, la solución funciona para mí, y es bastante ordenada. ¡La advertencia está ahí para ahorrarme dolores de cabeza más tarde y posiblemente para quitarme el pelo tratando de descubrir por qué el push no funcionaría!


Otra forma es voltear un parámetro una vez que se ha tocado el elemento de la lista una vez, así:

{ onListItemTap: function () { if (!this.tapped) { this.tapped = true; ... } } }

Por supuesto, eso solo funciona si está destruyendo la vista de lista tan pronto como el usuario vaya a una pantalla diferente.


Creé un método para verificar esto:

ENSURE_NO_DOUBLE_TAP : function(classNameToPush) { if (Ext.getClassName(Ext.getCmp(''MyViewport'').getActiveItem()) == classNameToPush) { return false; } return true; }

Luego, desde su aplicación antes de que se procese todo lo que podría ser doblemente aprovechado:

if (!ENSURE_NO_DOUBLE_TAP(''MyApp.view.View'')) { return; }


Si está escuchando el evento tap de un oyente usando oyentes, esta es mi solución:

listeners : { release : function(){ if(this.getDisabled())return false; this.setDisabled(true); this.fireEvent(''tap''); }, tap : function() { //do what you want } }


Ampliando las respuestas de jayteejee y Merott, agregué un código para interceptar varios intentos rápidos, no solo para evitar duplicados, sino también para evitar que aparezcan diferentes vistas antes de que la transición de página se complete. Piense en un usuario que toque diferentes elementos de la lista.

También observe el view.destroy(); método en el bloque else para evitar que las instancias de vista se acumulen en la memoria.

Ext.define(''Overrides.navigation.View'', { extend: ''Ext.navigation.View'', xtype: ''ovrnavigationview'', interceptPush: false, push: function (view) { var activeItem = this.getActiveItem(); // Prevent multiple pushes & duplicates if (!this.interceptPush && activeItem.xtype !== view.xtype) { // Set interceptPush this.interceptPush = true; // Reset interceptPush after 500 ms Ext.defer(function() { this.interceptPush = false; }, 500, this); // Handle push this.callParent(arguments); } else { // Warn developer console.warn("Prevented pushing view of xtype: " + view.xtype); // Destroy view view.destroy(); return false; } } });


Solo puede usar el evento "itemsingletap".

Si también quieres admitir dobles pulsaciones, crea un segundo oyente para "itemdoubletap" e invoque la misma función, ambos oyentes funcionan bien juntos.