171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu/*
271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * Copyright (C) 2015 The Android Open Source Project
371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu *
471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * in compliance with the License. You may obtain a copy of the License at
671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu *
771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu *
971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
1071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
1271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu * the License.
1371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu */
1471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
1571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gupackage android.support.v17.leanback.widget.picker;
1671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
1771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.content.Context;
180f96ae4965103bade4bebe7776b2ee35cd603112Dake Guimport android.graphics.Rect;
1971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.R;
2071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.widget.OnChildViewHolderSelectedListener;
2171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
2271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v7.widget.RecyclerView;
2371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.util.AttributeSet;
2471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.util.TypedValue;
252e42db84057616ff5fc755ab55debef731015d3aDake Guimport android.view.KeyEvent;
2671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.LayoutInflater;
2771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.View;
2871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.ViewGroup;
2971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.AccelerateInterpolator;
3071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.DecelerateInterpolator;
3171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.Interpolator;
3271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.widget.FrameLayout;
3371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.widget.TextView;
3471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport java.util.ArrayList;
3671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport java.util.List;
3771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu/**
39b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * Picker is a widget showing multiple customized {@link PickerColumn}s. The PickerColumns are
40b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * initialized in {@link #setColumns(List)}. Call {@link #setColumnAt(int, PickerColumn)} if the
41b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * column value range or labels change. Call {@link #setColumnValue(int, int, boolean)} to update
42b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * the current value of PickerColumn.
432e42db84057616ff5fc755ab55debef731015d3aDake Gu * <p>
442e42db84057616ff5fc755ab55debef731015d3aDake Gu * Picker has two states and will change height:
45b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * <li>{@link #isActivated()} is true: Picker shows typically three items vertically (see
46b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * {@link #getActivatedVisibleItemCount()}}. Columns other than {@link #getSelectedColumn()} still
47b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * shows one item if the Picker is focused. On a touch screen device, the Picker will not get focus
48b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * so it always show three items on all columns. On a non-touch device (a TV), the Picker will show
49b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * three items only on currently activated column. If the Picker has focus, it will intercept DPAD
50b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * directions and select activated column.
51b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * <li>{@link #isActivated()} is false: Picker shows one item vertically (see
52b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu * {@link #getVisibleItemCount()}) on all columns. The size of Picker shrinks.
5371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu */
5471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gupublic class Picker extends FrameLayout {
5571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
5671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public interface PickerValueListener {
5771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onValueChanged(Picker picker, int column);
5871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
5971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
6071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ViewGroup mRootView;
612e42db84057616ff5fc755ab55debef731015d3aDake Gu    private ViewGroup mPickerView;
620f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    private final List<VerticalGridView> mColumnViews = new ArrayList<VerticalGridView>();
6371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ArrayList<PickerColumn> mColumns;
6471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
6571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mUnfocusedAlpha;
6671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mFocusedAlpha;
6771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mVisibleColumnAlpha;
6871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mInvisibleColumnAlpha;
6971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private int mAlphaAnimDuration;
7071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private Interpolator mDecelerateInterpolator;
7171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private Interpolator mAccelerateInterpolator;
7271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ArrayList<PickerValueListener> mListeners;
73b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    private float mVisibleItemsActivated = 3;
742e42db84057616ff5fc755ab55debef731015d3aDake Gu    private float mVisibleItems = 1;
75b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    private int mSelectedColumn = 0;
7671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
77b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    private CharSequence mSeparator;
78b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    private int mPickerItemLayoutId = R.layout.lb_picker_item;
79b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    private int mPickerItemTextViewId = 0;
8071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
8171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
82b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Gets separator string between columns.
8371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
84b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public final CharSequence getSeparator() {
85b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        return mSeparator;
8671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
8771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
8871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
89b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Sets separator String between Picker columns.
90b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param seperator Separator String between Picker columns.
9171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
92b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public final void setSeparator(CharSequence seperator) {
93b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mSeparator = seperator;
9471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
9571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
9671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
9771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
98b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * supply the {@link Picker}'s item's layout id
9971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
100b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public final int getPickerItemLayoutId() {
101b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        return mPickerItemLayoutId;
10271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
10371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
10471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
105b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Returns the {@link Picker}'s item's {@link TextView}'s id from within the
106b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} or 0 if the
107b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} is a {link
108b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * TextView}.
10971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
110b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public final int getPickerItemTextViewId() {
111b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        return mPickerItemTextViewId;
11271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
11371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
11471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
115b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Sets the {@link Picker}'s item's {@link TextView}'s id from within the
11671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} or 0 if the
11771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} is a {link
11871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * TextView}.
119b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param textViewId View id of TextView inside a Picker item, or 0 if the Picker item is a
120b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     *                   TextView.
12171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
122b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public final void setPickerItemTextViewId(int textViewId) {
123b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mPickerItemTextViewId = textViewId;
12471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
12571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
12671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
12771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Creates a Picker widget.
12871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param context
12971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param attrs
13071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param defStyleAttr
13171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
13271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public Picker(Context context, AttributeSet attrs, int defStyleAttr) {
13371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        super(context, attrs, defStyleAttr);
1342e42db84057616ff5fc755ab55debef731015d3aDake Gu        // Make it enabled and clickable to receive Click event.
1352e42db84057616ff5fc755ab55debef731015d3aDake Gu        setEnabled(true);
13671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
13771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mFocusedAlpha = 1f; //getFloat(R.dimen.list_item_selected_title_text_alpha);
13871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mUnfocusedAlpha = 1f; //getFloat(R.dimen.list_item_unselected_text_alpha);
13971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mVisibleColumnAlpha = 0.5f; //getFloat(R.dimen.picker_item_visible_column_item_alpha);
14071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mInvisibleColumnAlpha = 0f; //getFloat(R.dimen.picker_item_invisible_column_item_alpha);
14171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
14271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mAlphaAnimDuration = 200; // mContext.getResources().getInteger(R.integer.dialog_animation_duration);
14371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
14471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mDecelerateInterpolator = new DecelerateInterpolator(2.5F);
14571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mAccelerateInterpolator = new AccelerateInterpolator(2.5F);
14671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
14771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        LayoutInflater inflater = LayoutInflater.from(getContext());
148b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mRootView = (ViewGroup) inflater.inflate(R.layout.lb_picker, this, true);
149b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mPickerView = (ViewGroup) mRootView.findViewById(R.id.picker);
15071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
15171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
15271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
15371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
15471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Get nth PickerColumn.
15571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param colIndex  Index of PickerColumn.
156b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @return PickerColumn at colIndex or null if {@link #setColumns(List)} is not called yet.
15771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
15871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public PickerColumn getColumnAt(int colIndex) {
15971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns == null) {
16071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return null;
16171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
16271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return mColumns.get(colIndex);
16371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
16471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
16571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
16671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Get number of PickerColumns.
167b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @return Number of PickerColumns or 0 if {@link #setColumns(List)} is not called yet.
16871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
16971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public int getColumnsCount() {
17071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns == null) {
17171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return 0;
17271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
17371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return mColumns.size();
17471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
17571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
17671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
177b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu     * Set columns and create Views.
17871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columns PickerColumns to be shown in the Picker.
17971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
180b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setColumns(List<PickerColumn> columns) {
181b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mColumnViews.clear();
182b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mPickerView.removeAllViews();
183b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mColumns = new ArrayList<PickerColumn>(columns);
184b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (mSelectedColumn > mColumns.size() - 1) {
185b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            mSelectedColumn = mColumns.size() - 1;
18671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
18771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        LayoutInflater inflater = LayoutInflater.from(getContext());
18871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        int totalCol = getColumnsCount();
18971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        for (int i = 0; i < totalCol; i++) {
19071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            final int colIndex = i;
19171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            final VerticalGridView columnView = (VerticalGridView) inflater.inflate(
19271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    R.layout.lb_picker_column, mPickerView, false);
1932e42db84057616ff5fc755ab55debef731015d3aDake Gu            // we dont want VerticalGridView to receive focus.
1942e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize(columnView);
1952e42db84057616ff5fc755ab55debef731015d3aDake Gu            // always center aligned, not aligning selected item on top/bottom edge.
19671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
1972e42db84057616ff5fc755ab55debef731015d3aDake Gu            // Width is dynamic, so has fixed size is false.
19871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setHasFixedSize(false);
19971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mColumnViews.add(columnView);
20071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
20171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // add view to root
20271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mPickerView.addView(columnView);
20371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
20471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // add a separator if not the last element
20571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (i != totalCol - 1 && getSeparator() != null) {
20671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                TextView separator = (TextView) inflater.inflate(
207b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu                        R.layout.lb_picker_separator, mPickerView, false);
20871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                separator.setText(getSeparator());
20971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                mPickerView.addView(separator);
21071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
21171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
21271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setAdapter(new PickerScrollArrayAdapter(getContext(),
21371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    getPickerItemLayoutId(), getPickerItemTextViewId(), colIndex));
21471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setOnChildViewHolderSelectedListener(mColumnChangeListener);
21571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
21671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
21771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
21871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
21971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * When column labels change or column range changes, call this function to re-populate the
22034914fd296a56b55c3c6c3183c7b58c4f16ca775Dake Gu     * selection list.  Note this function cannot be called from RecyclerView layout/scroll pass.
22171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex Index of column to update.
222b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param column New column to update.
22371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
224b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setColumnAt(int columnIndex, PickerColumn column) {
225b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mColumns.set(columnIndex, column);
22671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        VerticalGridView columnView = mColumnViews.get(columnIndex);
22771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        PickerScrollArrayAdapter adapter = (PickerScrollArrayAdapter) columnView.getAdapter();
22834914fd296a56b55c3c6c3183c7b58c4f16ca775Dake Gu        if (adapter != null) {
22971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            adapter.notifyDataSetChanged();
23071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
231942f79291db75ccf6ecd0351d23a444a43dd0501Dake Gu        columnView.setSelectedPosition(column.getCurrentValue() - column.getMinValue());
23271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
23371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
23471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
23571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Manually set current value of a column.  The function will update UI and notify listeners.
23671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex Index of column to update.
23771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param value New value of the column.
23871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param runAnimation True to scroll to the value or false otherwise.
23971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
240b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setColumnValue(int columnIndex, int value, boolean runAnimation) {
241b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        PickerColumn column = mColumns.get(columnIndex);
242b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (column.getCurrentValue() != value) {
243b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            column.setCurrentValue(value);
24471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            notifyValueChanged(columnIndex);
24571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            VerticalGridView columnView = mColumnViews.get(columnIndex);
24671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (columnView != null) {
24771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int position = value - mColumns.get(columnIndex).getMinValue();
24871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                if (runAnimation) {
24971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    columnView.setSelectedPositionSmooth(position);
25071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                } else {
25171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    columnView.setSelectedPosition(position);
25271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                }
25371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
25471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
25571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
25671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
25771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private void notifyValueChanged(int columnIndex) {
25871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners != null) {
25971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            for (int i = mListeners.size() - 1; i >= 0; i--) {
26071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                mListeners.get(i).onValueChanged(this, columnIndex);
26171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
26271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
26371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
26471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
265b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    /**
266b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Register a callback to be invoked when the picker's value has changed.
267b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param listener The callback to ad
268b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     */
269b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void addOnValueChangedListener(PickerValueListener listener) {
27071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners == null) {
27171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mListeners = new ArrayList<Picker.PickerValueListener>();
27271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
27371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mListeners.add(listener);
27471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
27571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
276b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    /**
277b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Remove a previously installed value changed callback
278b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param listener The callback to remove.
279b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     */
280b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void removeOnValueChangedListener(PickerValueListener listener) {
28171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners != null) {
28271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mListeners.remove(listener);
28371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
28471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
28571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
2862e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnAlpha(int colIndex, boolean animate) {
2872e42db84057616ff5fc755ab55debef731015d3aDake Gu        VerticalGridView column = mColumnViews.get(colIndex);
28871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
28971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        int selected = column.getSelectedPosition();
29071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        View item;
29171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
29271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        for (int i = 0; i < column.getAdapter().getItemCount(); i++) {
29371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            item = column.getLayoutManager().findViewByPosition(i);
29471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (item != null) {
2952e42db84057616ff5fc755ab55debef731015d3aDake Gu                setOrAnimateAlpha(item, (selected == i), colIndex, animate);
29671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
29771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
29871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
29971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3002e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void setOrAnimateAlpha(View view, boolean selected, int colIndex,
3012e42db84057616ff5fc755ab55debef731015d3aDake Gu            boolean animate) {
3020f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        boolean columnShownAsActivated = colIndex == mSelectedColumn || !hasFocus();
30371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (selected) {
30471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // set alpha for main item (selected) in the column
3052e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (columnShownAsActivated) {
30671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mFocusedAlpha, -1, mDecelerateInterpolator);
30771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
30871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mUnfocusedAlpha, -1,  mDecelerateInterpolator);
30971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
31071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        } else {
31171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // set alpha for remaining items in the column
3122e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (columnShownAsActivated) {
31371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mVisibleColumnAlpha, -1, mDecelerateInterpolator);
31471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
31571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mInvisibleColumnAlpha, -1,
31671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                        mDecelerateInterpolator);
31771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
31871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
31971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
32071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
32171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private void setOrAnimateAlpha(View view, boolean animate, float destAlpha, float startAlpha,
32271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            Interpolator interpolator) {
32371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        view.animate().cancel();
32471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (!animate) {
32571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            view.setAlpha(destAlpha);
32671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        } else {
32771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (startAlpha >= 0.0f) {
32871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                // set a start alpha
32971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                view.setAlpha(startAlpha);
33071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
33171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            view.animate().alpha(destAlpha)
33271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .setDuration(mAlphaAnimDuration).setInterpolator(interpolator)
33371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .start();
33471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
33571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
33671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
33771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
33871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can override this function to supply the
339b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * behavior when a list has been scrolled.  Subclass may call {@link #setColumnValue(int, int,
340b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * boolean)} and or {@link #setColumnAt(int,PickerColumn)}.  Subclass should not directly call
34171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * {@link PickerColumn#setCurrentValue(int)} which does not update internal state or notify
34271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * listeners.
34371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex index of which column was changed.
34471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param newValue A new value desired to be set on the column.
34571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
346b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void onColumnValueChanged(int columnIndex, int newValue) {
347b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        PickerColumn column = mColumns.get(columnIndex);
348b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (column.getCurrentValue() != newValue) {
349b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            column.setCurrentValue(newValue);
35071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            notifyValueChanged(columnIndex);
35171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
35271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
35371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
35471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float getFloat(int resourceId) {
35571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        TypedValue buffer = new TypedValue();
35671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        getContext().getResources().getValue(resourceId, buffer, true);
35771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return buffer.getFloat();
35871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
35971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    static class ViewHolder extends RecyclerView.ViewHolder {
36171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        final TextView textView;
36271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        ViewHolder(View v, TextView textView) {
36471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            super(v);
36571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            this.textView = textView;
36671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
36771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
36871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    class PickerScrollArrayAdapter extends RecyclerView.Adapter<ViewHolder> {
37071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
37171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mResource;
37271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mColIndex;
37371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mTextViewResourceId;
37471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private PickerColumn mData;
37571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
37671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        PickerScrollArrayAdapter(Context context, int resource, int textViewResourceId,
37771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int colIndex) {
37871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mResource = resource;
37971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mColIndex = colIndex;
38071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mTextViewResourceId = textViewResourceId;
38171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mData = mColumns.get(mColIndex);
38271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
38371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3840f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        @Override
38571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
38671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
38771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            View v = inflater.inflate(mResource, parent, false);
38871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            TextView textView;
38971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (mTextViewResourceId != 0) {
39071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                textView = (TextView) v.findViewById(mTextViewResourceId);
39171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
39271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                textView = (TextView) v;
39371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
39471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            ViewHolder vh = new ViewHolder(v, textView);
39571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return vh;
39671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
39771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3980f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        @Override
39971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onBindViewHolder(ViewHolder holder, int position) {
40071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (holder.textView != null && mData != null) {
401942f79291db75ccf6ecd0351d23a444a43dd0501Dake Gu                holder.textView.setText(mData.getLabelFor(mData.getMinValue() + position));
40271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
40371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            setOrAnimateAlpha(holder.itemView,
40471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    (mColumnViews.get(mColIndex).getSelectedPosition() == position),
4052e42db84057616ff5fc755ab55debef731015d3aDake Gu                    mColIndex, false);
40671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
40771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
4080f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        @Override
4090f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        public void onViewAttachedToWindow(ViewHolder holder) {
4100f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            holder.itemView.setFocusable(isActivated());
4110f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        }
4120f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu
4130f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        @Override
41471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public int getItemCount() {
415942f79291db75ccf6ecd0351d23a444a43dd0501Dake Gu            return mData == null ? 0 : mData.getCount();
41671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
41771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
41871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
41971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private final OnChildViewHolderSelectedListener mColumnChangeListener = new
42071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            OnChildViewHolderSelectedListener() {
42171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
42271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        @Override
42371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
42471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int position, int subposition) {
42571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            PickerScrollArrayAdapter pickerScrollArrayAdapter = (PickerScrollArrayAdapter) parent
42671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .getAdapter();
42771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
42871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            int colIndex = mColumnViews.indexOf(parent);
4292e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnAlpha(colIndex, true);
43071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (child != null) {
43171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int newValue = mColumns.get(colIndex).getMinValue() + position;
432b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu                onColumnValueChanged(colIndex, newValue);
43371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
43471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
43571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
43671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    };
43771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
4382e42db84057616ff5fc755ab55debef731015d3aDake Gu    @Override
4392e42db84057616ff5fc755ab55debef731015d3aDake Gu    public boolean dispatchKeyEvent(android.view.KeyEvent event) {
440b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (isActivated()) {
4412e42db84057616ff5fc755ab55debef731015d3aDake Gu            final int keyCode = event.getKeyCode();
4422e42db84057616ff5fc755ab55debef731015d3aDake Gu            switch (keyCode) {
4430f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            case KeyEvent.KEYCODE_DPAD_CENTER:
4440f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            case KeyEvent.KEYCODE_ENTER:
4450f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu                if (event.getAction() == KeyEvent.ACTION_UP) {
4460f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu                    performClick();
4472e42db84057616ff5fc755ab55debef731015d3aDake Gu                }
4482e42db84057616ff5fc755ab55debef731015d3aDake Gu                break;
4492e42db84057616ff5fc755ab55debef731015d3aDake Gu            default:
4502e42db84057616ff5fc755ab55debef731015d3aDake Gu                return super.dispatchKeyEvent(event);
4512e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
45271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return true;
45371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
4542e42db84057616ff5fc755ab55debef731015d3aDake Gu        return super.dispatchKeyEvent(event);
4552e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
45671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
4570f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    @Override
4580f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
4590f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        int column = getSelectedColumn();
4600f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        if (column < mColumnViews.size()) {
4610f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            return mColumnViews.get(column).requestFocus(direction, previouslyFocusedRect);
4620f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        }
4630f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        return false;
4640f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    }
4650f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu
4662e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
4672e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Classes extending {@link Picker} can choose to override this method to
4682e42db84057616ff5fc755ab55debef731015d3aDake Gu     * supply the {@link Picker}'s column's single item height in pixels.
4692e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
4702e42db84057616ff5fc755ab55debef731015d3aDake Gu    protected int getPickerItemHeightPixels() {
4712e42db84057616ff5fc755ab55debef731015d3aDake Gu        return getContext().getResources().getDimensionPixelSize(R.dimen.picker_item_height);
4722e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
4732e42db84057616ff5fc755ab55debef731015d3aDake Gu
4742e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnSize() {
4752e42db84057616ff5fc755ab55debef731015d3aDake Gu        for (int i = 0; i < getColumnsCount(); i++) {
4762e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize(mColumnViews.get(i));
4772e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
4782e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
4792e42db84057616ff5fc755ab55debef731015d3aDake Gu
4802e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnSize(VerticalGridView columnView) {
4812e42db84057616ff5fc755ab55debef731015d3aDake Gu        ViewGroup.LayoutParams lp = columnView.getLayoutParams();
482b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        lp.height = (int) (getPickerItemHeightPixels() * (isActivated() ?
483b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu                getActivatedVisibleItemCount() : getVisibleItemCount()));
4842e42db84057616ff5fc755ab55debef731015d3aDake Gu        columnView.setLayoutParams(lp);
4852e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
4862e42db84057616ff5fc755ab55debef731015d3aDake Gu
4870f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    private void updateItemFocusable() {
4880f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        final boolean activated = isActivated();
4890f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        for (int i = 0; i < getColumnsCount(); i++) {
4900f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            VerticalGridView grid = mColumnViews.get(i);
4910f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            for (int j = 0; j < grid.getChildCount(); j++) {
4920f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu                View view = grid.getChildAt(j);
4930f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu                view.setFocusable(activated);
4940f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            }
4950f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        }
4960f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    }
4972e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
498b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Returns number of visible items showing in a column when it's activated.  The default value
499b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * is 3.
500b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @return Number of visible items showing in a column when it's activated.
5012e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
502b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public float getActivatedVisibleItemCount() {
503b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        return mVisibleItemsActivated;
5042e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5052e42db84057616ff5fc755ab55debef731015d3aDake Gu
5062e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
507b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Changes number of visible items showing in a column when it's activated.  The default value
508b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * is 3.
509b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param visiblePickerItems Number of visible items showing in a column when it's activated.
5102e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
511b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setActivatedVisibleItemCount(float visiblePickerItems) {
5122e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (visiblePickerItems <= 0) {
5132e42db84057616ff5fc755ab55debef731015d3aDake Gu            throw new IllegalArgumentException();
5142e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
515b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (mVisibleItemsActivated != visiblePickerItems) {
516b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            mVisibleItemsActivated = visiblePickerItems;
517b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            if (isActivated()) {
5182e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnSize();
5192e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
5202e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5212e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5222e42db84057616ff5fc755ab55debef731015d3aDake Gu
5232e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
524b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Returns number of visible items showing in a column when it's not activated.  The default
525b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * value is 1.
526b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @return Number of visible items showing in a column when it's not activated.
5272e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
528b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public float getVisibleItemCount() {
5292e42db84057616ff5fc755ab55debef731015d3aDake Gu        return 1;
5302e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5312e42db84057616ff5fc755ab55debef731015d3aDake Gu
5322e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
533b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Changes number of visible items showing in a column when it's not activated.  The default
534b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * value is 1.
535b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * @param pickerItems Number of visible items showing in a column when it's not activated.
5362e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
537b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setVisibleItemCount(float pickerItems) {
5382e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (pickerItems <= 0) {
5392e42db84057616ff5fc755ab55debef731015d3aDake Gu            throw new IllegalArgumentException();
5402e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5412e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (mVisibleItems != pickerItems) {
5422e42db84057616ff5fc755ab55debef731015d3aDake Gu            mVisibleItems = pickerItems;
543b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            if (!isActivated()) {
5442e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnSize();
5452e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
5462e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5472e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5482e42db84057616ff5fc755ab55debef731015d3aDake Gu
549b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    @Override
550b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setActivated(boolean activated) {
551b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (activated != isActivated()) {
552b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            super.setActivated(activated);
5532e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize();
5540f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            updateItemFocusable();
555b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        } else {
556b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            super.setActivated(activated);
5572e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5582e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5592e42db84057616ff5fc755ab55debef731015d3aDake Gu
5600f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    @Override
5610f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    public void requestChildFocus(View child, View focused) {
5620f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        super.requestChildFocus(child, focused);
5630f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        for (int i = 0; i < mColumnViews.size(); i++) {
5640f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            if (mColumnViews.get(i).hasFocus()) {
5650f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu                setSelectedColumn(i);
5660f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu            }
5670f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu        }
5680f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu    }
5690f96ae4965103bade4bebe7776b2ee35cd603112Dake Gu
5702e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
571b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * Change current selected column.  Picker shows multiple items on selected column if Picker has
572b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu     * focus.  Picker shows multiple items on all column if Picker has no focus (e.g. a Touchscreen
5732e42db84057616ff5fc755ab55debef731015d3aDake Gu     * screen).
5742e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param columnIndex Index of column to activate.
5752e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
576b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public void setSelectedColumn(int columnIndex) {
577b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        if (mSelectedColumn != columnIndex) {
578b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu            mSelectedColumn = columnIndex;
57971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            for (int i = 0; i < mColumnViews.size(); i++) {
5802e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnAlpha(i, true);
58171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
58271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
5832e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5842e42db84057616ff5fc755ab55debef731015d3aDake Gu
5852e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5862e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Get current activated column index.
5872e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return Current activated column index.
5882e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
589b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu    public int getSelectedColumn() {
590b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        return mSelectedColumn;
5912e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
59271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
59371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu}
594