Skip to content

Instantly share code, notes, and snippets.

@passsy
Last active August 29, 2015 14:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save passsy/96f3e268f53a315ba7df to your computer and use it in GitHub Desktop.
Save passsy/96f3e268f53a315ba7df to your computer and use it in GitHub Desktop.
RxJava implementation for TouchEvents for Views. Analog to ClickEvents.
// known way to subscribe to click events
ViewObservable.clicks(button)
    .subscribe();
// use this to subscribe to touch events
ViewObservable.bindView(button, touches(button))
    .subscribe(new Action1<OnTouchEvent>() {
        @Override
        public void call(final OnTouchEvent event) {
            // do something with the event
        }
    });
    
// helper method
public static Observable<OnTouchEvent> touches(final View view) {
    return Observable.create(new OnSubscribeViewTouch(view));
}
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package rx.android.view;
import android.view.MotionEvent;
import android.view.View;
/**
* analog to {@link OnClickEvent}
*/
// TODO @AutoValue
public abstract class OnTouchEvent {
final static class ManualValue_OnTouchEvent extends OnTouchEvent {
private final MotionEvent event;
private final View view;
ManualValue_OnTouchEvent(View view, final MotionEvent event) {
if (view == null) {
throw new NullPointerException("Null view");
} else if (event == null) {
throw new NullPointerException("Null event");
} else {
this.view = view;
this.event = event;
}
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ManualValue_OnTouchEvent)) {
return false;
}
final ManualValue_OnTouchEvent that = (ManualValue_OnTouchEvent) o;
if (!event.equals(that.event)) {
return false;
}
return view.equals(that.view);
}
public MotionEvent event() {
return this.event;
}
@Override
public int hashCode() {
int result = event.hashCode();
result = 31 * result + view.hashCode();
return result;
}
public String toString() {
return "OnTouchEvent{view=" + this.view + ", event=" + event + "}";
}
public View view() {
return this.view;
}
}
private boolean handled = false;
public static OnTouchEvent create(View view, MotionEvent event) {
return new ManualValue_OnTouchEvent(view, event);
}
public void setHandled(final boolean handled) {
this.handled = handled;
}
public boolean handled() {
return handled;
}
public abstract View view();
public abstract MotionEvent event();
}
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package rx.android.view;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.AndroidSubscriptions;
import rx.android.internal.Assertions;
import rx.functions.Action0;
/**
* analog to {@link OnSubscribeViewClick}
*/
public final class OnSubscribeViewTouch implements Observable.OnSubscribe<OnTouchEvent> {
private static class CompositeOnTouchListener implements View.OnTouchListener {
private final List<View.OnTouchListener> listeners = new ArrayList<>();
public boolean addOnTouchListener(final View.OnTouchListener listener) {
return listeners.add(listener);
}
@Override
public boolean onTouch(final View view, final MotionEvent event) {
boolean handled = false;
for (final View.OnTouchListener listener : listeners) {
handled |= listener.onTouch(view, event);
}
return handled;
}
public boolean removeOnTouchListener(final View.OnTouchListener listener) {
return listeners.remove(listener);
}
}
private static class CachedListeners {
private static final Map<View, CompositeOnTouchListener> sCachedListeners
= new WeakHashMap<View, CompositeOnTouchListener>();
public static CompositeOnTouchListener getFromViewOrCreate(final View view) {
final CompositeOnTouchListener cached = sCachedListeners.get(view);
if (cached != null) {
return cached;
}
final CompositeOnTouchListener listener = new CompositeOnTouchListener();
sCachedListeners.put(view, listener);
view.setOnTouchListener(listener);
return listener;
}
}
private final View view;
public OnSubscribeViewTouch(final View view) {
this.view = view;
}
@Override
public void call(final Subscriber<? super OnTouchEvent> observer) {
Assertions.assertUiThread();
final CompositeOnTouchListener composite = CachedListeners.getFromViewOrCreate(view);
final View.OnTouchListener listener = new View.OnTouchListener() {
@Override
public boolean onTouch(final View v, final MotionEvent event) {
final OnTouchEvent touchEvent = OnTouchEvent.create(view, event);
observer.onNext(touchEvent);
return touchEvent.handled();
}
};
final Subscription subscription = AndroidSubscriptions.unsubscribeInUiThread(new Action0() {
@Override
public void call() {
composite.removeOnTouchListener(listener);
}
});
composite.addOnTouchListener(listener);
observer.add(subscription);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment