ViewPositionObserver.java revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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    @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