RowHeaderPresenter.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
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.graphics.Paint;
17import android.support.annotation.RestrictTo;
18import android.support.v17.leanback.R;
19import android.view.LayoutInflater;
20import android.view.View;
21import android.view.ViewGroup;
22import android.widget.TextView;
23
24import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
25
26/**
27 * RowHeaderPresenter provides a default presentation for {@link HeaderItem} using a
28 * {@link RowHeaderView}. If a subclass creates its own view, the subclass must also override
29 * {@link #onSelectLevelChanged(ViewHolder)}.
30 */
31public class RowHeaderPresenter extends Presenter {
32
33    private final int mLayoutResourceId;
34    private final Paint mFontMeasurePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
35    private boolean mNullItemVisibilityGone;
36    private final boolean mAnimateSelect;
37
38    public RowHeaderPresenter() {
39        this(R.layout.lb_row_header);
40    }
41
42    /**
43     * @hide
44     */
45    @RestrictTo(GROUP_ID)
46    public RowHeaderPresenter(int layoutResourceId) {
47        this(layoutResourceId, true);
48    }
49
50    /**
51     * @hide
52     */
53    @RestrictTo(GROUP_ID)
54    public RowHeaderPresenter(int layoutResourceId, boolean animateSelect) {
55        mLayoutResourceId = layoutResourceId;
56        mAnimateSelect = animateSelect;
57    }
58
59    /**
60     * Optionally sets the view visibility to {@link View#GONE} when bound to null.
61     */
62    public void setNullItemVisibilityGone(boolean nullItemVisibilityGone) {
63        mNullItemVisibilityGone = nullItemVisibilityGone;
64    }
65
66    /**
67     * Returns true if the view visibility is set to {@link View#GONE} when bound to null.
68     */
69    public boolean isNullItemVisibilityGone() {
70        return mNullItemVisibilityGone;
71    }
72
73    /**
74     * A ViewHolder for the RowHeaderPresenter.
75     */
76    public static class ViewHolder extends Presenter.ViewHolder {
77        float mSelectLevel;
78        int mOriginalTextColor;
79        float mUnselectAlpha;
80
81        public ViewHolder(View view) {
82            super(view);
83        }
84        public final float getSelectLevel() {
85            return mSelectLevel;
86        }
87    }
88
89    @Override
90    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
91        RowHeaderView headerView = (RowHeaderView) LayoutInflater.from(parent.getContext())
92                .inflate(mLayoutResourceId, parent, false);
93
94        ViewHolder viewHolder = new ViewHolder(headerView);
95        viewHolder.mOriginalTextColor = headerView.getCurrentTextColor();
96        viewHolder.mUnselectAlpha = parent.getResources().getFraction(
97                R.fraction.lb_browse_header_unselect_alpha, 1, 1);
98        if (mAnimateSelect) {
99            setSelectLevel(viewHolder, 0);
100        }
101        return viewHolder;
102    }
103
104    @Override
105    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
106        HeaderItem headerItem = item == null ? null : ((Row) item).getHeaderItem();
107        if (headerItem == null) {
108            ((RowHeaderView) viewHolder.view).setText(null);
109            viewHolder.view.setContentDescription(null);
110            if (mNullItemVisibilityGone) {
111                viewHolder.view.setVisibility(View.GONE);
112            }
113        } else {
114            viewHolder.view.setVisibility(View.VISIBLE);
115            ((RowHeaderView) viewHolder.view).setText(headerItem.getName());
116            viewHolder.view.setContentDescription(headerItem.getContentDescription());
117        }
118    }
119
120    @Override
121    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
122        ((RowHeaderView) viewHolder.view).setText(null);
123        if (mAnimateSelect) {
124            setSelectLevel((ViewHolder) viewHolder, 0);
125        }
126    }
127
128    /**
129     * Sets the select level.
130     */
131    public final void setSelectLevel(ViewHolder holder, float selectLevel) {
132        holder.mSelectLevel = selectLevel;
133        onSelectLevelChanged(holder);
134    }
135
136    /**
137     * Called when the select level changes.  The default implementation sets the alpha on the view.
138     */
139    protected void onSelectLevelChanged(ViewHolder holder) {
140        if (mAnimateSelect) {
141            holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel *
142                    (1f - holder.mUnselectAlpha));
143        }
144    }
145
146    /**
147     * Returns the space (distance in pixels) below the baseline of the
148     * text view, if one exists; otherwise, returns 0.
149     */
150    public int getSpaceUnderBaseline(ViewHolder holder) {
151        int space = holder.view.getPaddingBottom();
152        if (holder.view instanceof TextView) {
153            space += (int) getFontDescent((TextView) holder.view, mFontMeasurePaint);
154        }
155        return space;
156    }
157
158    protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) {
159        if (fontMeasurePaint.getTextSize() != textView.getTextSize()) {
160            fontMeasurePaint.setTextSize(textView.getTextSize());
161        }
162        if (fontMeasurePaint.getTypeface() != textView.getTypeface()) {
163            fontMeasurePaint.setTypeface(textView.getTypeface());
164        }
165        return fontMeasurePaint.descent();
166    }
167}
168