Skip to content

Instantly share code, notes, and snippets.

@caseykulm
Last active July 21, 2016 20:21
Show Gist options
  • Save caseykulm/e146bae972a4e6481ee6fce4c22f7daf to your computer and use it in GitHub Desktop.
Save caseykulm/e146bae972a4e6481ee6fce4c22f7daf to your computer and use it in GitHub Desktop.
FrameLayout that knows when it first becomes visible on screen
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import java.util.HashSet;
import java.util.Set;
public class EventView extends FrameLayout {
private static final String TAG = EventView.class.getSimpleName();
private String eventViewId;
public EventView(Context context) {
super(context);
init();
}
public EventView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public EventView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EventView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setWillNotDraw(false);
getViewTreeObserver().addOnGlobalLayoutListener(new EventViewGlobalLayoutListener(this, onScreenListener));
getViewTreeObserver().addOnScrollChangedListener(new EventViewScrollChangeListener(this, onScreenListener));
}
private final OnScreenListener onScreenListener = new OnScreenListener() {
private Set<String> seenIds = new HashSet<>();
@Override
public void onScreen(EventView eventView) {
if (!seenIds.contains(eventView.getEventViewId())) {
firstSeen();
seenIds.add(eventView.getEventViewId());
}
}
};
protected void firstSeen() {
Log.d(TAG, "onScreen() - eventView: " + getEventViewId());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (eventViewId == null || eventViewId.isEmpty()) {
throw new IllegalStateException("eventViewId must be set");
}
}
public void setEventViewId(String eventViewId) {
this.eventViewId = eventViewId;
}
public String getEventViewId() {
return eventViewId;
}
interface OnScreenListener {
void onScreen(EventView eventView);
}
private static class EventViewSubject {
private EventView eventView;
private OnScreenListener onScreenListener;
private final Rect rect;
private final Point globalOffset;
EventViewSubject(EventView view, OnScreenListener onScreenListener) {
Log.d(TAG, "eventViewSubject() - ev: " + view.hashCode() + ", osl: " + onScreenListener.hashCode());
this.eventView = view;
this.onScreenListener = onScreenListener;
this.rect = new Rect();
this.globalOffset = new Point();
}
public void processEvent() {
if (eventViewVisible()) {
onScreenListener.onScreen(eventView);
}
}
private boolean eventViewVisible() {
if (eventView == null) {
return false;
}
boolean isVisibleOnScreen = eventView.getGlobalVisibleRect(rect, globalOffset);
Log.d(TAG, "onListener() - ev " + eventView.getEventViewId() + " data - width: " + eventView.getWidth() + ", height: " + eventView.getHeight() + ", x: " + eventView.getX() + ", y: " + eventView.getY() + ", visibleOnScreen: " + isVisibleOnScreen);
return isVisibleOnScreen;
}
}
private static class EventViewScrollChangeListener implements ViewTreeObserver.OnScrollChangedListener {
private final EventViewSubject eventViewSubject;
EventViewScrollChangeListener(EventView view, OnScreenListener onScreenListener) {
this.eventViewSubject = new EventViewSubject(view, onScreenListener);
}
@Override
public void onScrollChanged() {
eventViewSubject.processEvent();
}
}
private static class EventViewGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
private final EventViewSubject eventViewSubject;
EventViewGlobalLayoutListener(EventView view, OnScreenListener onScreenListener) {
this.eventViewSubject = new EventViewSubject(view, onScreenListener);
}
@Override
public void onGlobalLayout() {
eventViewSubject.processEvent();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment