Home | History | Annotate | Download | only in browser
      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      */
     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
     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
     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
     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
     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 
     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 
     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
    107     public void clearListener() {
    108         mListeners.clear();
    109     }
    110 }
    111 
    112