2012-03-07 10 views
12

मैं एक बड़ी परियोजना पर काम कर रहा हूं और मेरे पास बहुत सारे जीडब्ल्यूटी कोड लिखे गए हैं। अब मैं इस परियोजना को आईपैड और एंड्रॉइड टैबलेट जैसे टैबलेट के साथ पूरी तरह से संगत बनाने पर काम कर रहा हूं।कनवर्ट करना जीडब्ल्यूटी घटनाओं को स्पर्श करने के लिए घटनाओं पर क्लिक करें

इस के एक हिस्से के रूप में, मैंने देखा है कि स्पर्श डिवाइस 300ms क्लिक ईवेंट को संभालने में देरी करता है। इस परियोजना में, फिर से टच इवेंट लिखना एक बहुत ही कठिन काम है। मैंने इसमें बहुत सारे शोध किए हैं और Google Voice एप्लिकेशन में Google फास्ट बटन एपीआई का उपयोग किया है। मैंने कोशिश की और यह अच्छा काम कर रहा है लेकिन बहुत सारे कोडिंग और जेएसएनआई की आवश्यकता है।

मेरा सवाल है, क्या इस देरी को आसानी से दूर करने के लिए आपके ज्ञान में कुछ और उपलब्ध है?

+0

पता चला है कि इस सूत्र अभी भी जीवित है गुड ...: डी –

उत्तर

14

यहाँ तेजी से button.It का एक शुद्ध जावा कार्यान्वयन JNSI

की एक पंक्ति को शामिल नहीं करता
package com.apollo.tabletization.shared.util; 

import java.util.Date; 

import com.google.gwt.dom.client.Document; 
import com.google.gwt.dom.client.NativeEvent; 
import com.google.gwt.dom.client.Touch; 
import com.google.gwt.event.dom.client.HasAllTouchHandlers; 
import com.google.gwt.event.dom.client.HasClickHandlers; 
import com.google.gwt.user.client.DOM; 
import com.google.gwt.user.client.Event; 
import com.google.gwt.user.client.Window; 
import com.google.gwt.user.client.ui.Composite; 
import com.google.gwt.user.client.ui.Widget; 

/** Implementation of Google FastButton {@link http://code.google.com/mobile/articles/fast_buttons.html} */ 
public class FastButton extends Composite { 

    private boolean touchHandled = false; 
    private boolean clickHandled = false; 
    private boolean touchMoved = false; 
    private int startY; 
    private int startX; 
    private int timeStart; 

    public FastButton(Widget child) { 
    // TODO - messages 
    assert (child instanceof HasAllTouchHandlers) : ""; 
     assert (child instanceof HasClickHandlers) : ""; 
     initWidget(child); 
     sinkEvents(Event.TOUCHEVENTS | Event.ONCLICK); 
    } 

    @Override 
    public Widget getWidget() { 
    return super.getWidget(); 
    } 

    @Override 
    public void onBrowserEvent(Event event) { 
    timeStart = getUnixTimeStamp(); 
    switch (DOM.eventGetType(event)) { 
     case Event.ONTOUCHSTART: 
     { 
      onTouchStart(event); 
      break; 
     } 
     case Event.ONTOUCHEND: 
     { 
      onTouchEnd(event); 
      break; 
     } 
     case Event.ONTOUCHMOVE: 
     { 
      onTouchMove(event); 
      break; 
     } 
     case Event.ONCLICK: 
     { 
      onClick(event); 
      return; 
     } 
    } 

    super.onBrowserEvent(event); 
    } 

    private void onClick(Event event) { 
    event.stopPropagation(); 

    int timeEnd = getUnixTimeStamp(); 
    if(touchHandled) { 
     //Window.alert("click via touch: "+ this.toString() + "..." +timeStart+"---"+timeEnd); 
     touchHandled = false; 
     clickHandled = true; 
     super.onBrowserEvent(event); 
    } 
    else { 
     if(clickHandled) { 

     event.preventDefault(); 
     } 
     else { 
     clickHandled = false; 
     //Window.alert("click nativo: "+ this.toString()+ "..." +(timeStart-timeEnd)+"==="+timeStart+"---"+timeEnd); 
     super.onBrowserEvent(event); 
     } 
    } 
    } 

    private void onTouchEnd(Event event) { 
    if (!touchMoved) { 
     touchHandled = true; 
     fireClick(); 
    } 
    } 

    private void onTouchMove(Event event) { 
    if (!touchMoved) { 
     Touch touch = event.getTouches().get(0); 
     int deltaX = Math.abs(startX - touch.getClientX()); 
     int deltaY = Math.abs(startY - touch.getClientY()); 

     if (deltaX > 5 || deltaY > 5) { 
     touchMoved = true; 
     } 
    } 
    } 

    private void onTouchStart(Event event) { 
    Touch touch = event.getTouches().get(0); 
    this.startX = touch.getClientX(); 
    this.startY = touch.getClientY();    
    touchMoved = false; 
    } 

    private void fireClick() { 
    NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false, 
     false, false, false); 
    getElement().dispatchEvent(evt); 
    } 

    private int getUnixTimeStamp() { 
    Date date = new Date(); 
    int iTimeStamp = (int) (date.getTime() * .001); 
    return iTimeStamp; 
    } 
} 
+0

असल में मैं इसे बदलने के लिए कुछ संकलन समय पैरामीटर को लागू करने के लिए देख रहा हूं। उदाहरण के लिए, हम ऐप ब्राउज़र विशिष्ट बनाने के लिए ब्राउज़र को परिभाषित करने के लिए मॉड्यूल फ़ाइल का उपयोग करते हैं। इसलिए यदि मैं इस तरह के कुछ मानकों के साथ एप्लिकेशन संकलित करता हूं, तो इसे आईओएस सफारी जैसे मोबाइल ब्राउज़र के लिए काम करना चाहिए। –

+1

आप मॉड्यूल.एक्सएमएल में उपयोगकर्ता एजेंट जोड़ सकते हैं और बटन से फास्टबटन कार्यान्वयन – sunnychayen

+0

हे @ सुन्नीचैयन से चुनने के लिए जीडब्ल्यूटी डिफर्ड बाध्यकारी का उपयोग कर सकते हैं, यह समाधान काम नहीं करता है अगर बच्चे के क्लिक हैंडलर डोम पर एक नया तत्व जोड़ता है (जैसे कहते हैं, ऑटोहोइड सेट के साथ एक पॉपअप सच करने के लिए सेट)। ब्राउजर क्लिक इवेंट नए तत्व और कारणों पर होता है: पॉपअप खुलता है -> ब्राउजर इसे क्लिकएवेंट को फायर करता है -> नए पॉपअप की बाहरी सीमाओं पर एक क्लिक है -> पॉपअप छुपाएं। event.preventDefault() नहीं कहा जाता है; –

6

मुझे लगता है कि पहले इस सवाल का जवाब लिखा रूप से कोड में कुछ समस्या है, विशेष रूप से जब में है उनके कई स्पर्श हैं।

(नोट: मैं कोड को देख रहा हूं जिसे मैंने एलिमेंटल लाइब्रेरी का उपयोग संदर्भ के रूप में लिखा था, इसलिए कुछ कॉल उपयोगकर्ता लाइब्रेरी में अलग हो सकती हैं)।

ए) कोड बटन के उद्देश्य से स्पर्श छूने वाला नहीं है; यह TouchEvent.getTouches() को कॉल करता है। आप अपने बटन के लिए स्पर्श प्राप्त करने के लिए Touchstart और touchmove पर TouchEvent.getTargetTouches() को कॉल करना चाहते हैं। आप स्पर्श स्पर्श प्राप्त करने के लिए touchend पर TouchEvent.getChangedTouches() को कॉल करना चाहते हैं।

बी) कोड मल्टीटाउच को ध्यान में रखता नहीं है। टचस्टार्ट पर, आप जांच सकते हैं कि एक सिंगल टच उपलब्ध है और एक से अधिक होने पर जमानत हो सकती है। साथ ही, टचस्टार्ट पर, स्पर्श की आईडी को दूर करें, फिर इसे टचमोव में उपयोग करें और वापस लौटाए गए सरणी में अपनी टच आईडी ढूंढने के लिए स्पर्श करें (यदि उपयोगकर्ता ने बाद में दूसरी उंगली को छुआ है)। आप टचमोव और टचचेन्ड पर कई स्पर्शों को सरल और जांच भी सकते हैं और वहां फिर से जमानत कर सकते हैं।

सी) मुझे विश्वास है कि आपको टचस्टार्ट पर स्टॉपप्रॉपैगेशन कॉल करने की आवश्यकता है, क्योंकि आप ईवेंट को संभालने में सक्षम हैं। मुझे नहीं लगता कि वे टचस्टार्ट ईवेंट पर event.stopPropagation कहां कॉल करते हैं आप देख सकते हैं कि यह क्लिक हैंडलर में होता है, लेकिन टचस्टार्ट नहीं। यह स्पर्श को ब्राउज़र द्वारा स्वचालित रूप से एक क्लिक में बदलने से रोकता है, जो एकाधिक क्लिक का कारण बनता है।

एक आसान तरीका भी है। यदि आपको बटन पर शुरू करने के बारे में कोई परवाह नहीं है, तो आप टचस्टार्ट ईवेंट में बस अपने क्लिक तर्क को कॉल कर सकते हैं (और सुनिश्चित करें कि आप एकल स्पर्श की जांच करें, और event.stopPropagation पर कॉल करें) और टचमोव और टचचेंड को अनदेखा करें। सभी टचमॉव और टचचेन्ड सामान बटन पर ड्रैग करने की अनुमति देने के मामले को संभालने के लिए है।

+0

आपकी आखिरी टिप्पणी के जवाब में, क्या आप नहीं चाहते हैं कि उपयोगकर्ता लक्ष्य बटन पर दबाए रखें और चाहे उपयोगकर्ता ए) चलो -> आग घटना बी) बटन खींचें -> कोई आग नहीं? किस मामले में आप क्लिक लॉजिक को टच स्टार्ट पर कॉल नहीं करना चाहते हैं? –

+0

आपका मतलब लंबी प्रेस घटना है ...? –

+1

यदि आप बटन को दबाए रखना चाहते हैं, या यदि आप बटन को बंद कर देते हैं तो आप एक क्लिक को अस्वीकार करना चाहते हैं, तो आपको कम से कम टचेंड ईवेंट को संसाधित करना होगा और यह सुनिश्चित करना होगा कि यह बटन पर समाप्त हो जाए। तो, टचस्टार्ट पर, टच आईडी और टचचेंड पर याद रखें, बदले गए स्पर्श करें और आईडी द्वारा अपना स्पर्श ढूंढें और यह जांचने के लिए बटन के अंदर है कि बटन को क्लिक किया जाना चाहिए या नहीं। – Ezward

10

मैंने इस कार्यान्वयन पर एक स्टैब लेने के लिए उपरोक्त उत्तरों और टिप्पणियों का उपयोग करने का प्रयास किया है।

http://gwt-fast-touch-press.appspot.com/

https://github.com/ashtonthomas/gwt-fast-touch-press

कृपया ध्यान दें कि आप केवल समय बचाया है, तो आप कर रहे हैं देखने के लिए सक्षम हो जाएगा:

मैं भी एक नमूना GWT परियोजना जो आसान तुलना के लिए इस्तेमाल किया जा सकता posteds एक मोबाइल डिवाइस पर (या डिवाइस जो टच इवेंट को संभालते हैं और केवल ऑनक्लिक पर वापस नहीं आते हैं)।

मैंने 3 तेज बटन और 3 सामान्य बटन जोड़े हैं। पुराने मोबाइल उपकरणों पर और कभी-कभी कम होने पर आप आसानी से सुधार देख सकते हैं (सैमसंग गैलेक्सी नेक्सस ने केवल 100 एमएमएस की देरी दिखायी है जबकि पहला जीन आईपैड लगभग हर बार 400 एमएमएस से अधिक था)। सबसे बड़ी सुधार है आप जब तेजी से और लगातार बॉक्स क्लिक करने के लिए

package io.ashton.fastpress.client.fast; 

import com.google.gwt.core.client.Scheduler; 
import com.google.gwt.core.client.Scheduler.RepeatingCommand; 
import com.google.gwt.core.client.Scheduler.ScheduledCommand; 
import com.google.gwt.dom.client.Touch; 
import com.google.gwt.event.shared.HandlerRegistration; 
import com.google.gwt.user.client.DOM; 
import com.google.gwt.user.client.Event; 
import com.google.gwt.user.client.ui.Composite; 
import com.google.gwt.user.client.ui.Widget; 

/** 
* 
* GWT Implementation influenced by Google's FastPressElement: 
* https://developers.google.com/mobile/articles/fast_buttons 
* 
* Using Code examples and comments from: 
* http://stackoverflow.com/questions/9596807/converting-gwt-click-events-to-touch-events 
* 
* The FastPressElement is used to avoid the 300ms delay on mobile devices (Only do this if you want 
* to ignore the possibility of a double tap - The browser waits to see if we actually want to 
* double top) 
* 
* The "press" event will occur significantly fast (around 300ms faster). However the biggest 
* improvement is from enabling fast consecutive touches. 
* 
* If you try to rapidly touch one or more FastPressElements, you will notice a MUCH great 
* improvement. 
* 
* NOTE: Different browsers will handle quick swipe or long hold/drag touches differently. 
* This is an edge case if the user is long pressing or pressing while dragging the finger 
* slightly (but staying on the element) - The browser may or may not fire the event. However, 
* the browser will always fire the regular tap/press very quickly. 
* 
* TODO We should be able to embed fastElements and have the child fastElements NOT bubble the event 
* So we can embed the elements if needed (???) 
* 
* @author ashton 
* 
*/ 
public abstract class FastPressElement extends Composite implements HasPressHandlers { 

    private boolean touchHandled = false; 
    private boolean clickHandled = false; 
    private boolean touchMoved = false; 
    private boolean isEnabled = true; 
    private int touchId; 
    private int flashDelay = 75; // Default time delay in ms to flash style change 

    public FastPressElement() { 
    // Sink Click and Touch Events 
    // I am not going to sink Mouse events since 
    // I don't think we will gain anything 

    sinkEvents(Event.ONCLICK | Event.TOUCHEVENTS); // Event.TOUCHEVENTS adds all (Start, End, 
                // Cancel, Change) 

    } 

    public FastPressElement(int msDelay) { 
    this(); 
    if (msDelay >= 0) { 
     flashDelay = msDelay; 
    } 
    } 

    public void setEnabled(boolean enabled) { 
    if (enabled) { 
     onEnablePressStyle(); 
    } else { 
     onDisablePressStyle(); 
    } 
    this.isEnabled = enabled; 
    } 

    /** 
    * Use this method in the same way you would use addClickHandler or addDomHandler 
    * 
    */ 
    @Override 
    public HandlerRegistration addPressHandler(PressHandler handler) { 
    // Use Widget's addHandler to ensureHandlers and add the type/return handler 
    // We don't use addDom/BitlessHandlers since we aren't sinkEvents 
    // We also aren't even dealing with a DomEvent 
    return addHandler(handler, PressEvent.getType()); 
    } 

    /** 
    * 
    * @param event 
    */ 
    private void firePressEvent(Event event) { 
    // This better verify a ClickEvent or TouchEndEvent 
    // TODO might want to verify 
    // (hitting issue with web.bindery vs g.gwt.user package diff) 
    PressEvent pressEvent = new PressEvent(event); 
    fireEvent(pressEvent); 
    } 

    /** 
    * Implement the handler for pressing but NOT releasing the button. Normally you just want to show 
    * some CSS style change to alert the user the element is active but not yet pressed 
    * 
    * ONLY FOR STYLE CHANGE - Will briefly be called onClick 
    * 
    * TIP: Don't make a dramatic style change. Take note that if a user is just trying to scroll, and 
    * start on the element and then scrolls off, we may not want to distract them too much. If a user 
    * does scroll off the element, 
    * 
    */ 
    public abstract void onHoldPressDownStyle(); 

    /** 
    * Implement the handler for release of press. This should just be some CSS or Style change. 
    * 
    * ONLY FOR STYLE CHANGE - Will briefly be called onClick 
    * 
    * TIP: This should just go back to the normal style. 
    */ 
    public abstract void onHoldPressOffStyle(); 

    /** 
    * Change styling to disabled 
    */ 
    public abstract void onDisablePressStyle(); 

    /** 
    * Change styling to enabled 
    * 
    * TIP: 
    */ 
    public abstract void onEnablePressStyle(); 

    @Override 
    public Widget getWidget() { 
    return super.getWidget(); 
    } 

    @Override 
    public void onBrowserEvent(Event event) { 
    switch (DOM.eventGetType(event)) { 
     case Event.ONTOUCHSTART: { 
     if (isEnabled) { 
      onTouchStart(event); 
     } 
     break; 
     } 
     case Event.ONTOUCHEND: { 
     if (isEnabled) { 
      onTouchEnd(event); 
     } 
     break; 
     } 
     case Event.ONTOUCHMOVE: { 
     if (isEnabled) { 
      onTouchMove(event); 
     } 
     break; 
     } 
     case Event.ONCLICK: { 
     if (isEnabled) { 
      onClick(event); 
     } 
     return; 
     } 
     default: { 
     // Let parent handle event if not one of the above (?) 
     super.onBrowserEvent(event); 
     } 
    } 

    } 

    private void onClick(Event event) { 
    event.stopPropagation(); 

    if (touchHandled) { 
     // if the touch is already handled, we are on a device 
     // that supports touch (so you aren't in the desktop browser) 

     touchHandled = false;// reset for next press 
     clickHandled = true;// 

     super.onBrowserEvent(event); 

    } else { 
     if (clickHandled) { 
     // Not sure how this situation would occur 
     // onClick being called twice.. 
     event.preventDefault(); 
     } else { 
     // Press not handled yet 

     // We still want to briefly fire the style change 
     // To give good user feedback 
     // Show HoldPress when possible 
     Scheduler.get().scheduleDeferred(new ScheduledCommand() { 
      @Override 
      public void execute() { 
      // Show hold press 
      onHoldPressDownStyle(); 

      // Now schedule a delay (which will allow the actual 
      // onTouchClickFire to executed 
      Scheduler.get().scheduleFixedDelay(new RepeatingCommand() { 
       @Override 
       public boolean execute() { 
       // Clear the style change 
       onHoldPressOffStyle(); 
       return false; 
       } 
      }, flashDelay); 
      } 
     }); 

     clickHandled = false; 
     firePressEvent(event); 

     } 
    } 
    } 

    private void onTouchStart(Event event) { 

    onHoldPressDownStyle(); // Show style change 

    // Stop the event from bubbling up 
    event.stopPropagation(); 

    // Only handle if we have exactly one touch 
    if (event.getTargetTouches().length() == 1) { 
     Touch start = event.getTargetTouches().get(0); 
     touchId = start.getIdentifier(); 
     touchMoved = false; 
    } 

    } 

    /** 
    * Check to see if the touch has moved off of the element. 
    * 
    * NOTE that in iOS the elasticScroll may make the touch/move cancel more difficult. 
    * 
    * @param event 
    */ 
    private void onTouchMove(Event event) { 

    if (!touchMoved) { 
     Touch move = null; 

     for (int i = 0; i < event.getChangedTouches().length(); i++) { 
     if (event.getChangedTouches().get(i).getIdentifier() == touchId) { 
      move = event.getChangedTouches().get(i); 
     } 
     } 

     // Check to see if we moved off of the original element 

     // Use Page coordinates since we compare with widget's absolute coordinates 
     int yCord = move.getPageY(); 
     int xCord = move.getPageX(); 

     boolean yTop = getWidget().getAbsoluteTop() > yCord; // is y above element 
     boolean yBottom = (getWidget().getAbsoluteTop() + getWidget().getOffsetHeight()) < yCord; // y 
                           // below 
     boolean xLeft = getWidget().getAbsoluteLeft() > xCord; // is x to the left of element 
     boolean xRight = (getWidget().getAbsoluteLeft() + getWidget().getOffsetWidth()) < xCord; // x 
                           // to 
                           // the 
                           // right 
     if (yTop || yBottom || xLeft || xRight) { 
     touchMoved = true; 
     onHoldPressOffStyle();// Go back to normal style 
     } 

    } 

    } 

    private void onTouchEnd(Event event) { 
    if (!touchMoved) { 
     touchHandled = true; 
     firePressEvent(event); 
     event.preventDefault(); 
     onHoldPressOffStyle();// Change back the style 
    } 
    } 

} 
+0

रहा है यह वास्तव में अच्छा है ... और अधिक देखने के लिए अच्छा है GWT डेवलपर्स आ रहे हैं। मैंने इस पोस्ट को एक बार छोड़ दिया क्योंकि मुझे @ सुनचेचैन ने क्या किया था इसके अलावा मुझे कोई अन्य समाधान नहीं मिला ....! –

+0

मुझे टचक्लिक फियर() पर अमूर्त विधि के अलावा हैंडलर जोड़ने के लिए एक अलग विधि का उपयोग करके इसे अपडेट करने की आवश्यकता होगी और संभवतया सिर्फ "नाम" –

+0

पर क्लिक करें, मैंने अपना जवाब अपडेट करने के लिए बेहतर तरीके से अपडेट किया है PressEvent कहा जाता है (पैकेज में सभी फ़ाइलों के लिए गिट रेपो देखें: 'तेज़') –

1

भी प्रयास करें FastClick

FastClick है की कोशिश (यहाँ नहीं वास्तव में बटन लेकिन अनुकूलित किया जा सकता) एक सरल, आसानी से उपयोग 300ms को समाप्त करने के लिए लाइब्रेरी एक भौतिक टैप और मोबाइल ब्राउज़र पर क्लिक ईवेंट की गोलीबारी के बीच देरी। इसका उद्देश्य अपने वर्तमान तर्क के साथ हस्तक्षेप से बचने के दौरान अपने आवेदन को कम लगी और अधिक प्रतिक्रियाशील महसूस करना है।

फास्टक्लिक वित्तीय टाइम्स का हिस्सा एफटी लैब्स द्वारा विकसित किया गया है।

पुस्तकालय एफटी वेब एप्लिकेशन के हिस्से के रूप में तैनात किया गया है और कोशिश की और निम्न मोबाइल ब्राउज़र पर परीक्षण किया गया है:

  • मोबाइल आईओएस 3 पर iOS 5 पर सफारी और ऊपर की तरफ
  • क्रोम और ऊपर की तरफ
  • Android पर Chrome (आईसीएस)
  • ओपेरा मोबाइल 11.5 और ऊपर की तरफ
  • Android ब्राउज़र के बाद से एंड्रॉयड 2
  • PlayBoo के ओएस 1 और ऊपर

फास्टक्लिक किसी भी श्रोताओं को डेस्कटॉप ब्राउज़र पर संलग्न नहीं करता है क्योंकि इसकी आवश्यकता नहीं है। उन है कि परीक्षण किया गया है कर रहे हैं:

  • सफारी
  • क्रोम
  • इंटरनेट एक्सप्लोरर
  • फ़ायरफ़ॉक्स
  • ओपेरा
+0

यह एक अच्छा समाधान की तरह लगता है, लेकिन हम इसे जीडब्ल्यूटी में कैसे कार्यान्वित करते हैं? –

संबंधित मुद्दे