RowPresenter.java revision 8b068ddbbf22a246eab49ec25a2f7c3abfbdca51
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.view.View;
17import android.view.ViewGroup;
18
19/**
20 * In addition to {@link Presenter} which defines how to render and bind data to row view,
21 * RowPresenter receives calls from upper level(typically a fragment) when:
22 * <ul>
23 * <li>
24 * Row is selected via {@link #setRowViewSelected(ViewHolder, boolean)}.  The event
25 * is triggered immediately when there is a row selection change before the selection
26 * animation is started.
27 * Subclass of RowPresenter may override and add more works in
28 * {@link #onRowViewSelected(ViewHolder, boolean)}.
29 * </li>
30 * <li>
31 * Row is expanded to full width via {@link #setRowViewExpanded(ViewHolder, boolean)}.
32 * The event is triggered immediately before the expand animation is started.
33 * Subclass of RowPresenter may override and add more works in
34 * {@link #onRowViewExpanded(ViewHolder, boolean)}.
35 * </li>
36 * </ul>
37 * </p>
38 * Subclass of RowPresenter may add more fields in ViewHolder by overriding
39 * {@link #createRowViewHolder(ViewGroup)} and {@link #initializeRowViewHolder(ViewHolder)}.
40 * </p>
41 * <p>
42 * RowPresenter contains an optional and replaceable {@link RowHeaderPresenter} that
43 * renders header.  User can disable default rendering or replace with a new header presenter
44 * by calling {@link #setHeaderPresenter(RowHeaderPresenter)}.
45 * </p>
46 * <p>
47 * Provides {@link OnItemSelectedListener} and {@link OnItemClickedListener}.
48 * </p>
49 */
50public abstract class RowPresenter extends Presenter {
51
52    public static class ViewHolder extends Presenter.ViewHolder {
53        RowHeaderPresenter.ViewHolder mHeaderViewHolder;
54        Row mRow;
55        boolean mSelected;
56        boolean mExpanded;
57        boolean mInitialzed;
58        public ViewHolder(View view) {
59            super(view);
60        }
61        public final Row getRow() {
62            return mRow;
63        }
64        public final boolean isExpanded() {
65            return mExpanded;
66        }
67        public final boolean isSelected() {
68            return mSelected;
69        }
70        public final RowHeaderPresenter.ViewHolder getHeaderViewHolder() {
71            return mHeaderViewHolder;
72        }
73    }
74
75    private RowHeaderPresenter mHeaderPresenter = new RowHeaderPresenter();
76    private OnItemSelectedListener mOnItemSelectedListener;
77    private OnItemClickedListener mOnItemClickedListener;
78
79    @Override
80    public final Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
81        ViewHolder vh = createRowViewHolder(parent);
82        vh.mInitialzed = false;
83        initializeRowViewHolder(vh);
84        if (!vh.mInitialzed) {
85            throw new RuntimeException("super.initializeRowViewHolder() must be called");
86        }
87        return vh;
88    }
89
90    /**
91     * Called to create a ViewHolder object for row,  subclass of {@link RowPresenter}
92     * should override and return a different concrete ViewHolder object.
93     */
94    protected abstract ViewHolder createRowViewHolder(ViewGroup parent);
95
96    /**
97     * Called after a {@link RowPresenter.ViewHolder} is created,
98     * subclass of {@link RowPresenter} may override this method and start with calling
99     * super.initializeRowViewHolder(ViewHolder).
100     */
101    protected void initializeRowViewHolder(ViewHolder vh) {
102        if (mHeaderPresenter != null) {
103            vh.mHeaderViewHolder = (RowHeaderPresenter.ViewHolder)
104                    mHeaderPresenter.onCreateViewHolder((ViewGroup) vh.view);
105            ((ViewGroup) vh.view).addView(vh.mHeaderViewHolder.view, 0);
106        }
107        vh.mInitialzed = true;
108    }
109
110    /**
111     * Change the presenter used for rendering header. Can be null to disable header rendering.
112     * The method must be called before creating any row view.
113     */
114    public final void setHeaderPresenter(RowHeaderPresenter headerPresenter) {
115        mHeaderPresenter = headerPresenter;
116    }
117
118    /**
119     * Get optional presenter used for rendering header.  May return null.
120     */
121    public final RowHeaderPresenter getHeaderPresenter() {
122        return mHeaderPresenter;
123    }
124
125    /**
126     * Change expanded state of row view.
127     */
128    public final void setRowViewExpanded(ViewHolder holder, boolean expanded) {
129        holder.mExpanded = expanded;
130        onRowViewExpanded(holder, expanded);
131    }
132
133    /**
134     * Change select state of row view.
135     */
136    public final void setRowViewSelected(ViewHolder holder, boolean selected) {
137        holder.mSelected = selected;
138        onRowViewSelected(holder, selected);
139    }
140
141    /**
142     * Subclass may override and respond to expanded state change of row in fragment.
143     * Default implementation hide/show header view depending on expanded state.
144     * Subclass may make visual changes to row view but not allowed to create
145     * animation on the row view.
146     */
147    protected void onRowViewExpanded(ViewHolder vh, boolean expanded) {
148        if (mHeaderPresenter != null && vh.mHeaderViewHolder != null) {
149            mHeaderPresenter.setHidden(vh.mHeaderViewHolder, !expanded);
150        }
151    }
152
153    /**
154     * Subclass may override and respond to event Row is selected.
155     * Subclass may make visual changes to row view but not allowed to create
156     * animation on the row view.
157     */
158    protected void onRowViewSelected(ViewHolder vh, boolean selected) {
159        if (selected && mOnItemSelectedListener != null) {
160            mOnItemSelectedListener.onItemSelected(null, vh.getRow());
161        }
162    }
163
164    @Override
165    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
166        ViewHolder vh = (ViewHolder) viewHolder;
167        vh.mRow = (Row) item;
168        if (vh.mHeaderViewHolder != null) {
169            mHeaderPresenter.onBindViewHolder(vh.mHeaderViewHolder, item);
170        }
171        vh.mSelected = false;
172        vh.mExpanded = false;
173        onRowViewExpanded(vh, false);
174        onRowViewSelected(vh, false);
175    }
176
177    @Override
178    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
179        ViewHolder vh = (ViewHolder) viewHolder;
180        if (vh.mHeaderViewHolder != null) {
181            mHeaderPresenter.onUnbindViewHolder(vh.mHeaderViewHolder);
182        }
183        vh.mRow = null;
184    }
185
186    @Override
187    public void onViewAttachedToWindow(Presenter.ViewHolder holder) {
188        ViewHolder vh = (ViewHolder) holder;
189        if (vh.mHeaderViewHolder != null) {
190            mHeaderPresenter.onViewAttachedToWindow(vh.mHeaderViewHolder);
191        }
192    }
193
194    @Override
195    public void onViewDetachedFromWindow(Presenter.ViewHolder holder) {
196        ViewHolder vh = (ViewHolder) holder;
197        if (vh.mHeaderViewHolder != null) {
198            mHeaderPresenter.onViewDetachedFromWindow(vh.mHeaderViewHolder);
199        }
200    }
201
202    /**
203     * Set listener for item or row selection.  RowPresenter fires row selection
204     * event with null item, subclass of RowPresenter e.g. {@link ListRowPresenter} can
205     * fire a selection event with selected item.
206     */
207    public final void setOnItemSelectedListener(OnItemSelectedListener listener) {
208        mOnItemSelectedListener = listener;
209    }
210
211    /**
212     * Get listener for item or row selection.
213     */
214    public final OnItemSelectedListener getOnItemSelectedListener() {
215        return mOnItemSelectedListener;
216    }
217
218    /**
219     * Set listener for item click event.  RowPresenter does nothing but subclass of
220     * RowPresenter may fire item click event if it does have a concept of item.
221     * OnItemClickedListener will override the listener that item presenter sets during
222     * {@link Presenter#onCreateViewHolder(ViewGroup)}.  So in general,  developer should
223     * choose one of the listeners but not both.
224     */
225    public final void setOnItemClickedListener(OnItemClickedListener listener) {
226        mOnItemClickedListener = listener;
227    }
228
229    /**
230     * Set listener for item click event.
231     */
232    public final OnItemClickedListener getOnItemClickedListener() {
233        return mOnItemClickedListener;
234    }
235}
236