ViewPositionObserver.java revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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
5package org.chromium.content.browser;
6
7import android.view.View;
8import android.view.ViewTreeObserver;
9
10import java.util.ArrayList;
11
12/**
13 * Used to register listeners that can be notified of changes to the position of a view.
14 */
15public 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    public int getPositionX() {
43        // The stored position may be out-of-date. Get the real current position.
44        updatePosition();
45        return mPosition[0];
46    }
47
48    /**
49     * @return The current y position of the observed view.
50     */
51    public int getPositionY() {
52        // The stored position may be out-of-date. Get the real current position.
53        updatePosition();
54        return mPosition[1];
55    }
56
57    /**
58     * Register a listener to be called when the position of the underlying view changes.
59     */
60    public void addListener(Listener listener) {
61        if (mListeners.contains(listener)) return;
62
63        if (mListeners.isEmpty()) {
64            mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
65            updatePosition();
66        }
67
68        mListeners.add(listener);
69    }
70
71    /**
72     * Remove a previously installed listener.
73     */
74    public void removeListener(Listener listener) {
75        if (!mListeners.contains(listener)) return;
76
77        mListeners.remove(listener);
78
79        if (mListeners.isEmpty()) {
80            mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
81        }
82    }
83
84    private void notifyListeners() {
85        for (int i = 0; i < mListeners.size(); i++) {
86            mListeners.get(i).onPositionChanged(mPosition[0], mPosition[1]);
87        }
88    }
89
90    private void updatePosition() {
91        int previousPositionX = mPosition[0];
92        int previousPositionY = mPosition[1];
93        mView.getLocationInWindow(mPosition);
94        if (mPosition[0] != previousPositionX || mPosition[1] != previousPositionY) {
95            notifyListeners();
96        }
97    }
98}
99
100