2017-09-05 2 views
0

Gibt es eine Möglichkeit, wie Touch Touch-Ereignis abfangen/dekorieren ohne View oder Umbruch in einigen ViewGroup (die untergeordnete Ereignisse abfangen kann)?Abfangen von Click/Touch-Ereignis ohne Override ViewGroup oder View-Methoden

Angenommen, ich habe ExpandableListView, die Element Click Events behandelt. Wenn ich OnClickListener oder OnTouchListener in der vom Adapter zurückgegebenen überlagerten Elementansicht einstelle, führt ExpandableListView keine entsprechende Aktion durch - die Gruppenerweiterung, da Ereignis vom Element Listener verbraucht wurde.

Der Grund, warum ich ExpandableListView#setOnItemClickListener nicht verwenden möchte, ist, dass ich Click-Ereignis in Adapter verzieren möchte, ohne ExpandableListView Abhängigkeit zu verwenden.

Antwort

0

Ich habe eine funktionierende Lösung für dieses Problem gefunden.

Lösung: Sammeln von Ereignisklonen in OnTouchListener und dann zur übergeordneten Ansicht.

private final Queue<MotionEntry> consumedEvents = new LinkedList<>(); 
private final AtomicBoolean isDispatching = new AtomicBoolean(false); 
... 
    groupView.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent e) { 
      // we don't want to handle re-dispatched event... 
      if (isDispatching.get()) { 
       return false; 
      } 
      // create clone as event might be changed by parent 
      MotionEvent clone = MotionEvent.obtain(e); 
      MotionEntry entry = new MotionEntry(v, clone); 
      consumedEvents.add(entry); 

      // consume ACTION_DOWN in order to receive subsequent motion events 
      // like ACTION_MOVE, ACTION_CANCEL/ACTION_UP... 
      if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 
       return true; 
      } 
      // we do not want to handle canceled motion... 
      if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { 
       consumedEvents.clear(); 
       return false; 
      } 
      // at this moment we have intercepted whole motion 
      // = re-dispatch to parent in order to apply default handling... 
      if (event.getActionMasked() == MotionEvent.ACTION_UP) { 
       dispatchEvents(); 
      } 
      return true; 
     } 
    }); 
... 

Versandmethode:

private void dispatchEvents() { 
    isDispatching.set(true); 
    while (!consumedEvents.isEmpty()) { 
     MotionEntry entry = consumedEvents.poll(); 

     ViewGroup parent = (ViewGroup) entry.view.getParent(); 
     if (parent == null || entry.view.getVisibility() != View.VISIBLE) { 
      continue; // skip dispatching to detached/invisible view 
     } 
     // make position relative to parent... 
     entry.event.offsetLocation(entry.view.getLeft(), entry.view.getTop()); 
     entry.event.setSource(PARENT_DISPATCHER); 
     parent.dispatchTouchEvent(entry.event); 

     if (event.getActionMasked() == MotionEvent.ACTION_UP) { 
      clickListener.onClick(entry.view); 
     } 
    } 
    isDispatching.set(false); 
} 

Helper Klasse

private class MotionEntry { 
    private final View view; 
    private final MotionEvent event; 

    public MotionEntry(View view, MotionEvent event) { 
     this.view = view; 
     this.event = event; 
    } 
} 
Verwandte Themen