137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson/*
237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * Copyright (C) 2011 The Android Open Source Project
337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *
437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License");
537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * you may not use this file except in compliance with the License.
637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * You may obtain a copy of the License at
737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *
837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *      http://www.apache.org/licenses/LICENSE-2.0
937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *
1037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * Unless required by applicable law or agreed to in writing, software
1137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS,
1237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * See the License for the specific language governing permissions and
1437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * limitations under the License.
1537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson */
1637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
1737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonpackage com.android.calendar;
1837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
1937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.content.Context;
2037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.graphics.Color;
2137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.util.AttributeSet;
2237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.view.Gravity;
2337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.view.View;
2437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.view.ViewGroup;
2537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.widget.AbsListView;
2637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.widget.AbsListView.OnScrollListener;
2737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.widget.Adapter;
2837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.widget.FrameLayout;
2937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonimport android.widget.ListView;
3037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
3137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson/**
3237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * Implements a ListView class with a sticky header at the top. The header is
3337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * per section and it is pinned to the top as long as its section is at the top
3437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * of the view. If it is not, the header slides up or down (depending on the
3537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * scroll movement) and the header of the current section slides to the top.
3637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * Notes:
3737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * 1. The class uses the first available child ListView as the working
3837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    ListView. If no ListView child exists, the class will create a default one.
3937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * 2. The ListView's adapter must be passed to this class using the 'setAdapter'
4037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    method. The adapter must implement the HeaderIndexer interface. If no adapter
4137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    is specified, the class will try to extract it from the ListView
4237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * 3. The class registers itself as a listener to scroll events (OnScrollListener), if the
4337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    ListView needs to receive scroll events, it must register its listener using
4437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    this class' setOnScrollListener method.
4537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * 4. Headers for the list view must be added before using the StickyHeaderListView
4637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson * 5. The implementation should register to listen to dataset changes. Right now this is not done
4737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    since a change the dataset in a listview forces a call to OnScroll. The needed code is
4837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson *    commented out.
4937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson */
5037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonpublic class StickyHeaderListView extends FrameLayout implements OnScrollListener {
5137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
5237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    private static final String TAG = "StickyHeaderListView";
5337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected boolean mChildViewsCreated = false;
5437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected boolean mDoHeaderReset = false;
5537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
5637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected Context mContext = null;
5737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected Adapter mAdapter = null;
5837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected HeaderIndexer mIndexer = null;
59c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    protected HeaderHeightListener mHeaderHeightListener = null;
6037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected View mStickyHeader = null;
6137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected View mDummyHeader = null; // A invisible header used when a section has no header
6237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected ListView mListView = null;
6337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected ListView.OnScrollListener mListener = null;
6437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
65e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson    private int mSeparatorWidth;
66e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson    private View mSeparatorView;
67c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int mLastStickyHeaderHeight = 0;
68e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson
6937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // This code is needed only if dataset changes do not force a call to OnScroll
7037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // protected DataSetObserver mListDataObserver = null;
7137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
7237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
7337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected int mCurrentSectionPos = -1; // Position of section that has its header on the
7437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                                           // top of the view
7537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected int mNextSectionPosition = -1; // Position of next section's header
7637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected int mListViewHeadersCount = 0;
7737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
7837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    /**
7937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson     * Interface that must be implemented by the ListView adapter to provide headers locations
8037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson     * and number of items under each header.
8137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson     *
8237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson     */
8337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public interface HeaderIndexer {
8437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        /**
8537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * Calculates the position of the header of a specific item in the adapter's data set.
8637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * For example: Assuming you have a list with albums and songs names:
8737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * Album A, song 1, song 2, ...., song 10, Album B, song 1, ..., song 7. A call to
8837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * this method with the position of song 5 in Album B, should return  the position
8937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * of Album B.
9037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * @param position - Position of the item in the ListView dataset
9137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * @return Position of header. -1 if the is no header
9237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         */
9337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
9437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        int getHeaderPositionFromItemPosition(int position);
9537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
9637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        /**
97980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson         * Calculates the number of items in the section defined by the header (not including
9837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * the header).
9937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * For example: A list with albums and songs, the method should return
10037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * the number of songs names (without the album name).
10137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         *
10237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * @param headerPosition - the value returned by 'getHeaderPositionFromItemPosition'
10337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         * @return Number of items. -1 on error.
10437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson         */
10537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        int getHeaderItemsNumber(int headerPosition);
10637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
10737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
108c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    /***
109c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    *
110c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    * Interface that is used to update the sticky header's height
111c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    *
112c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    */
113c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson   public interface HeaderHeightListener {
114c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
115c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson       /***
116c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        * Updated a change in the sticky header's size
117c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        *
118c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        * @param height - new height of sticky header
119c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        */
120c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson       void OnHeaderHeightChanged(int height);
121c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson   }
122c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
123e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
124e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Sets the adapter to be used by the class to get views of headers
125e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
126e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param adapter - The adapter.
127e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
12837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
129e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    public void setAdapter(Adapter adapter) {
130e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson
131e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        // This code is needed only if dataset changes do not force a call to
132e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        // OnScroll
13337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // if (mAdapter != null && mListDataObserver != null) {
134e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        // mAdapter.unregisterDataSetObserver(mListDataObserver);
13537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // }
13637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
137e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        if (adapter != null) {
138e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson            mAdapter = adapter;
139e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson            // This code is needed only if dataset changes do not force a call
140e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson            // to OnScroll
141e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson            // mAdapter.registerDataSetObserver(mListDataObserver);
14237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
14337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
14437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
145e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
146e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Sets the indexer object (that implements the HeaderIndexer interface).
147e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
148e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param indexer - The indexer.
149e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
150e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson
151e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    public void setIndexer(HeaderIndexer indexer) {
152e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        mIndexer = indexer;
15337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
15437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
155e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
156e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Sets the list view that is displayed
157e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param lv - The list view.
158e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
159e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson
16037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public void setListView(ListView lv) {
16137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mListView = lv;
16237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mListView.setOnScrollListener(this);
16337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mListViewHeadersCount = mListView.getHeaderViewsCount();
16437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
16537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
166e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
167e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Sets an external OnScroll listener. Since the StickyHeaderListView sets
168e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * itself as the scroll events listener of the listview, this method allows
169e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * the user to register another listener that will be called after this
170e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * class listener is called.
171e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
172e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param listener - The external listener.
173e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
174e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    public void setOnScrollListener(ListView.OnScrollListener listener) {
175e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson        mListener = listener;
17637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
17737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
178c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void setHeaderHeightListener(HeaderHeightListener listener) {
179c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        mHeaderHeightListener = listener;
180c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
181c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
18237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // This code is needed only if dataset changes do not force a call to OnScroll
18337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // protected void createDataListener() {
18437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //    mListDataObserver = new DataSetObserver() {
18537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //        @Override
18637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //        public void onChanged() {
18737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //            onDataChanged();
18837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //        }
18937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    //    };
19037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // }
19137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
192e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
193e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Constructor
194e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
195e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param context - application context.
196e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param attrs - layout attributes.
197e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
19837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public StickyHeaderListView(Context context, AttributeSet attrs) {
19937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        super(context, attrs);
20037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mContext = context;
20137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // This code is needed only if dataset changes do not force a call to OnScroll
20237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // createDataListener();
20337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson     }
20437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
205e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
206e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Scroll status changes listener
207e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
208e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param view - the scrolled view
209e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param scrollState - new scroll state.
210e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
211e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    @Override
21237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public void onScrollStateChanged(AbsListView view, int scrollState) {
21337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (mListener != null) {
21437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            mListener.onScrollStateChanged(view, scrollState);
21537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
21637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
21737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
218e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    /**
219e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * Scroll events listener
220e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *
221e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param view - the scrolled view
222e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param firstVisibleItem - the index (in the list's adapter) of the top
223e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     *            visible item.
224e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param visibleItemCount - the number of visible items in the list
225e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     * @param totalItemCount - the total number items in the list
226e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson     */
227e2ed3678c5fb9434f5e89d3278dea8daff44de58Isaac Katzenelson    @Override
22837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
22937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            int totalItemCount) {
23037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
23137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        updateStickyHeader(firstVisibleItem);
23237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
23337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (mListener != null) {
23437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            mListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
23537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
23637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
23737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
238e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson    /**
239e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson     * Sets a separator below the sticky header, which will be visible while the sticky header
240e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson     * is not scrolling up.
241e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson     * @param color - color of separator
242e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson     * @param width - width in pixels of separator
243e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson     */
244e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson    public void setHeaderSeparator(int color, int width) {
245e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        mSeparatorView = new View(mContext);
246e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        ViewGroup.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
247e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                width, Gravity.TOP);
248e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        mSeparatorView.setLayoutParams(params);
249e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        mSeparatorView.setBackgroundColor(color);
250e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        mSeparatorWidth = width;
251e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson        this.addView(mSeparatorView);
252e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson    }
253e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson
25437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected void updateStickyHeader(int firstVisibleItem) {
25537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
25637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // Try to make sure we have an adapter to work with (may not succeed).
25737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (mAdapter == null && mListView != null) {
25837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            setAdapter(mListView.getAdapter());
25937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
26037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
26137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        firstVisibleItem -= mListViewHeadersCount;
26237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (mAdapter != null && mIndexer != null && mDoHeaderReset) {
26337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
26437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            // Get the section header position
26537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            int sectionSize = 0;
26637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            int sectionPos = mIndexer.getHeaderPositionFromItemPosition(firstVisibleItem);
26737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
26837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            // New section - set it in the header view
26937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            boolean newView = false;
27037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            if (sectionPos != mCurrentSectionPos) {
27137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
272e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                // No header for current position , use the dummy invisible one, hide the separator
27337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                if (sectionPos == -1) {
27437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    sectionSize = 0;
27537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    this.removeView(mStickyHeader);
27637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader = mDummyHeader;
277e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    if (mSeparatorView != null) {
278e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        mSeparatorView.setVisibility(View.GONE);
279e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    }
28037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    newView = true;
28137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                } else {
28237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    // Create a copy of the header view to show on top
28337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    sectionSize = mIndexer.getHeaderItemsNumber(sectionPos);
28437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    View v = mAdapter.getView(sectionPos + mListViewHeadersCount, null, mListView);
28537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    v.measure(MeasureSpec.makeMeasureSpec(mListView.getWidth(),
28637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                            MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mListView.getHeight(),
28737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                                    MeasureSpec.AT_MOST));
28837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    this.removeView(mStickyHeader);
28937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader = v;
29037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    newView = true;
29137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                }
29237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                mCurrentSectionPos = sectionPos;
29337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                mNextSectionPosition = sectionSize + sectionPos + 1;
29437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            }
29537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
29637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
29737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            // Do transitions
29837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            // If position of bottom of last item in a section is smaller than the height of the
29937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            // sticky header - shift drawable of header.
30037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            if (mStickyHeader != null) {
30137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                int sectionLastItemPosition =  mNextSectionPosition - firstVisibleItem - 1;
30237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                int stickyHeaderHeight = mStickyHeader.getHeight();
30337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                if (stickyHeaderHeight == 0) {
30437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    stickyHeaderHeight = mStickyHeader.getMeasuredHeight();
30537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                }
306c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
307c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // Update new header height
308c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                if (mHeaderHeightListener != null &&
309c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        mLastStickyHeaderHeight != stickyHeaderHeight) {
310c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    mLastStickyHeaderHeight = stickyHeaderHeight;
311c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    mHeaderHeightListener.OnHeaderHeightChanged(stickyHeaderHeight);
312c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                }
313c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
31437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                View SectionLastView = mListView.getChildAt(sectionLastItemPosition);
31537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                if (SectionLastView != null && SectionLastView.getBottom() <= stickyHeaderHeight) {
31637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    int lastViewBottom = SectionLastView.getBottom();
31737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader.setTranslationY(lastViewBottom - stickyHeaderHeight);
318e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    if (mSeparatorView != null) {
319e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        mSeparatorView.setVisibility(View.GONE);
320e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    }
32137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                } else if (stickyHeaderHeight != 0) {
32237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader.setTranslationY(0);
32351cd31c8ed558530bab70ac9f7a84b2e456368ebIsaac Katzenelson                    if (mSeparatorView != null && !mStickyHeader.equals(mDummyHeader)) {
324e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        mSeparatorView.setVisibility(View.VISIBLE);
325e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    }
32637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                }
32737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                if (newView) {
32837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader.setVisibility(View.INVISIBLE);
32937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    this.addView(mStickyHeader);
330e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    if (mSeparatorView != null && !mStickyHeader.equals(mDummyHeader)){
331e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        FrameLayout.LayoutParams params =
332e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                                new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
333e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                                        mSeparatorWidth);
334e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        params.setMargins(0, mStickyHeader.getMeasuredHeight(), 0, 0);
335e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        mSeparatorView.setLayoutParams(params);
336e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                        mSeparatorView.setVisibility(View.VISIBLE);
337e0983f72aa6b33e8733699b6f72d67126fc785bdIsaac Katzenelson                    }
33837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                    mStickyHeader.setVisibility(View.VISIBLE);
33937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                }
34037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            }
34137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
34237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
34337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
34437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    @Override
34537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected void onFinishInflate() {
34637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        super.onFinishInflate();
34737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (!mChildViewsCreated) {
34837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            setChildViews();
34937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
35037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mDoHeaderReset = true;
35137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
35237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
35337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    @Override
35437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    protected void onAttachedToWindow() {
35537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        super.onAttachedToWindow();
35637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (!mChildViewsCreated) {
35737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            setChildViews();
35837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
35937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mDoHeaderReset = true;
36037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
36137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
36237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
36337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Resets the sticky header when the adapter data set was changed
36437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // This code is needed only if dataset changes do not force a call to OnScroll
36537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // protected void onDataChanged() {
36637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Should do a call to updateStickyHeader if needed
36737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // }
36837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
36937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    private void setChildViews() {
37037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
37137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // Find a child ListView (if any)
37237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        int iChildNum = getChildCount();
37337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        for (int i = 0; i < iChildNum; i++) {
37437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            Object v = getChildAt(i);
37537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            if (v instanceof ListView) {
37637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                setListView((ListView) v);
37737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            }
37837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
37937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
38037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // No child ListView - add one
38137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (mListView == null) {
38237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            setListView(new ListView(mContext));
38337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
38437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
38537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        // Create a dummy view , it will be used in case a section has no header
38637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mDummyHeader = new View (mContext);
38737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        ViewGroup.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
38837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson                1, Gravity.TOP);
38937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mDummyHeader.setLayoutParams(params);
39037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mDummyHeader.setBackgroundColor(Color.TRANSPARENT);
39137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
39237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        mChildViewsCreated = true;
39337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
39437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
39537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson}
396