1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.support.v4.app; 17 18 19import android.view.View; 20import android.view.ViewTreeObserver; 21 22/** 23 * An OnPreDrawListener that will remove itself after one OnPreDraw call. Typical 24 * usage is: 25 * <pre><code> 26 * OneShotPreDrawListener.add(view, () -> { view.doSomething(); }) 27 * </code></pre> 28 * <p> 29 * The onPreDraw always returns true. 30 * <p> 31 * The listener will also remove itself from the ViewTreeObserver when the view 32 * is detached from the view hierarchy. In that case, the Runnable will never be 33 * executed. 34 */ 35class OneShotPreDrawListener implements ViewTreeObserver.OnPreDrawListener, 36 View.OnAttachStateChangeListener { 37 private final View mView; 38 private ViewTreeObserver mViewTreeObserver; 39 private final Runnable mRunnable; 40 41 private OneShotPreDrawListener(View view, Runnable runnable) { 42 mView = view; 43 mViewTreeObserver = view.getViewTreeObserver(); 44 mRunnable = runnable; 45 } 46 47 /** 48 * Creates a OneShotPreDrawListener and adds it to view's ViewTreeObserver. 49 * @param view The view whose ViewTreeObserver the OnPreDrawListener should listen. 50 * @param runnable The Runnable to execute in the OnPreDraw (once) 51 * @return The added OneShotPreDrawListener. It can be removed prior to 52 * the onPreDraw by calling {@link #removeListener()}. 53 */ 54 public static OneShotPreDrawListener add(View view, Runnable runnable) { 55 OneShotPreDrawListener listener = new OneShotPreDrawListener(view, runnable); 56 view.getViewTreeObserver().addOnPreDrawListener(listener); 57 view.addOnAttachStateChangeListener(listener); 58 return listener; 59 } 60 61 @Override 62 public boolean onPreDraw() { 63 removeListener(); 64 mRunnable.run(); 65 return true; 66 } 67 68 /** 69 * Removes the listener from the ViewTreeObserver. This is useful to call if the 70 * callback should be removed prior to {@link #onPreDraw()}. 71 */ 72 public void removeListener() { 73 if (mViewTreeObserver.isAlive()) { 74 mViewTreeObserver.removeOnPreDrawListener(this); 75 } else { 76 mView.getViewTreeObserver().removeOnPreDrawListener(this); 77 } 78 mView.removeOnAttachStateChangeListener(this); 79 } 80 81 @Override 82 public void onViewAttachedToWindow(View v) { 83 mViewTreeObserver = v.getViewTreeObserver(); 84 } 85 86 @Override 87 public void onViewDetachedFromWindow(View v) { 88 removeListener(); 89 } 90} 91