1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.content.browser; 6 7 import android.view.View; 8 import android.view.ViewTreeObserver; 9 10 import java.util.ArrayList; 11 12 /** 13 * Used to register listeners that can be notified of changes to the position of a view. 14 */ 15 public class ViewPositionObserver implements PositionObserver { 16 private View mView; 17 // Absolute position of the container view relative to its parent window. 18 private final int[] mPosition = new int[2]; 19 20 private final ArrayList<Listener> mListeners; 21 private ViewTreeObserver.OnPreDrawListener mPreDrawListener; 22 23 /** 24 * @param view The view to observe. 25 */ ViewPositionObserver(View view)26 public ViewPositionObserver(View view) { 27 mView = view; 28 mListeners = new ArrayList<Listener>(); 29 updatePosition(); 30 mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { 31 @Override 32 public boolean onPreDraw() { 33 updatePosition(); 34 return true; 35 } 36 }; 37 } 38 39 /** 40 * @return The current x position of the observed view. 41 */ 42 @Override getPositionX()43 public int getPositionX() { 44 // The stored position may be out-of-date. Get the real current position. 45 updatePosition(); 46 return mPosition[0]; 47 } 48 49 /** 50 * @return The current y position of the observed view. 51 */ 52 @Override getPositionY()53 public int getPositionY() { 54 // The stored position may be out-of-date. Get the real current position. 55 updatePosition(); 56 return mPosition[1]; 57 } 58 59 /** 60 * Register a listener to be called when the position of the underlying view changes. 61 */ 62 @Override addListener(Listener listener)63 public void addListener(Listener listener) { 64 if (mListeners.contains(listener)) return; 65 66 if (mListeners.isEmpty()) { 67 mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); 68 updatePosition(); 69 } 70 71 mListeners.add(listener); 72 } 73 74 /** 75 * Remove a previously installed listener. 76 */ 77 @Override removeListener(Listener listener)78 public void removeListener(Listener listener) { 79 if (!mListeners.contains(listener)) return; 80 81 mListeners.remove(listener); 82 83 if (mListeners.isEmpty()) { 84 mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); 85 } 86 } 87 notifyListeners()88 private void notifyListeners() { 89 for (int i = 0; i < mListeners.size(); i++) { 90 mListeners.get(i).onPositionChanged(mPosition[0], mPosition[1]); 91 } 92 } 93 updatePosition()94 private void updatePosition() { 95 int previousPositionX = mPosition[0]; 96 int previousPositionY = mPosition[1]; 97 mView.getLocationInWindow(mPosition); 98 if (mPosition[0] != previousPositionX || mPosition[1] != previousPositionY) { 99 notifyListeners(); 100 } 101 } 102 103 /** 104 * Clears installed listener(s). 105 */ 106 @Override clearListener()107 public void clearListener() { 108 mListeners.clear(); 109 } 110 } 111 112