Picker.java revision b19799d69cbbe7f7ca104520e9b07312ab7539af
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;
1871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.R;
1971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.widget.OnChildViewHolderSelectedListener;
2071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
2171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.support.v7.widget.RecyclerView;
2271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.util.AttributeSet;
2371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.util.TypedValue;
242e42db84057616ff5fc755ab55debef731015d3aDake Guimport android.view.KeyEvent;
2571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.LayoutInflater;
2671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.View;
2771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.ViewGroup;
2871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.AccelerateInterpolator;
2971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.DecelerateInterpolator;
3071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.view.animation.Interpolator;
3171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.widget.FrameLayout;
3271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport android.widget.TextView;
3371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport java.util.ArrayList;
3571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Guimport java.util.List;
3671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu/**
38b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * Picker is a widget showing multiple customized {@link PickerColumn}s. The PickerColumns are
39b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * initialized in {@link #setColumns(ArrayList)}. Call {@link #updateAdapter(int)} if the column
40b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * value range or labels change. Call {@link #updateValue(int, int, boolean)} to update the current
41b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * value of PickerColumn.
422e42db84057616ff5fc755ab55debef731015d3aDake Gu * <p>
432e42db84057616ff5fc755ab55debef731015d3aDake Gu * Picker has two states and will change height:
442e42db84057616ff5fc755ab55debef731015d3aDake Gu * <li>{@link #isExpanded()} is true: Picker shows typically three items vertically (see
452e42db84057616ff5fc755ab55debef731015d3aDake Gu * {@link #getVisiblePickerItemsInExpand()}}. Columns other than {@link #getActiveColumn()} still
46b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * shows one item if the Picker is focused. On a touch screen device, the Picker will not get focus
47b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * so it always show three items on all columns. On a non-touch device (a TV), the Picker will show
48b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * three items only on currently activated column. If the Picker has focus, it will intercept DPAD
49b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * directions and select activated column.
502e42db84057616ff5fc755ab55debef731015d3aDake Gu * <li>{@link #isExpanded()} is false: Picker shows one item vertically (see
51b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * {@link #getVisiblePickerItems()}) on all columns. The size of Picker shrinks.
52b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * <li>The expand mode will be toggled if the Picker has focus and {@link #isToggleExpandOnClick()}
53b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * is true. Summarize Typically use cases:
54b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * <li>On a touch screen based device, the Picker focusableInTouchMode=false. It won't get focus, it
55b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * wont toggle expand mode on click or touch, should call {@link #setExpanded(boolean)} with true,
56b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * so that user always sees three items on all columns.
57b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * <li>On a TV: the Picker focusable=true. It will get focus and toggle into expand mode when user
58b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * clicks on it, toggle can be disabled by {@link #setToggleExpandOnClick(boolean)} with false. Only
59b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * the activated column shows multiple items and the activated column is selected by DPAD left or
60b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu * right.
6171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu */
6271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gupublic class Picker extends FrameLayout {
6371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
6471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public interface PickerValueListener {
6571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onValueChanged(Picker picker, int column);
6671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
6771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
6871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private String mSeparator;
6971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ViewGroup mRootView;
702e42db84057616ff5fc755ab55debef731015d3aDake Gu    private ViewGroup mPickerView;
7171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private List<VerticalGridView> mColumnViews = new ArrayList<VerticalGridView>();
7271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ArrayList<PickerColumn> mColumns;
7371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
7471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mUnfocusedAlpha;
7571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mFocusedAlpha;
7671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mVisibleColumnAlpha;
7771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float mInvisibleColumnAlpha;
7871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private int mAlphaAnimDuration;
7971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private Interpolator mDecelerateInterpolator;
8071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private Interpolator mAccelerateInterpolator;
8171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private ArrayList<PickerValueListener> mListeners;
822e42db84057616ff5fc755ab55debef731015d3aDake Gu    private boolean mExpanded;
832e42db84057616ff5fc755ab55debef731015d3aDake Gu    private float mVisibleItemsInExpand = 3;
842e42db84057616ff5fc755ab55debef731015d3aDake Gu    private float mVisibleItems = 1;
852e42db84057616ff5fc755ab55debef731015d3aDake Gu    private int mActivatedColumn = 0;
862e42db84057616ff5fc755ab55debef731015d3aDake Gu    private boolean mToggleExpandOnClick = true;
8771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
8871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
8971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
9071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the separator string
9171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
9271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected String getSeparator() {
9371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return mSeparator;
9471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
9571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
9671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
9771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
9871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the {@link Picker}'s root layout id
9971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
10071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected int getRootLayoutId() {
10171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return R.layout.lb_picker;
10271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
10371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
10471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
10571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
10671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the {@link Picker}'s id from within the layout provided by
10771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * {@link Picker#getRootLayoutId()}
10871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
10971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected int getPickerId() {
11071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return R.id.picker;
11171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
11271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
11371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
11471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
11571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the {@link Picker}'s separator's layout id
11671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
11771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected int getPickerSeparatorLayoutId() {
11871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return R.layout.lb_picker_separator;
11971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
12071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
12171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
12271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
12371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the {@link Picker}'s item's layout id
12471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
12571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected int getPickerItemLayoutId() {
12671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return R.layout.lb_picker_item;
12771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
12871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
12971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
13071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can choose to override this method to
13171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * supply the {@link Picker}'s item's {@link TextView}'s id from within the
13271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} or 0 if the
13371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * layout provided by {@link Picker#getPickerItemLayoutId()} is a {link
13471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * TextView}.
13571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
13671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    protected int getPickerItemTextViewId() {
13771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return 0;
13871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
13971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
14071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
14171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Creates a Picker widget.
14271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param context
14371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param attrs
14471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param defStyleAttr
14571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
14671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public Picker(Context context, AttributeSet attrs, int defStyleAttr) {
14771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        super(context, attrs, defStyleAttr);
1482e42db84057616ff5fc755ab55debef731015d3aDake Gu        // On TV, Picker is focusable and intercept Click / DPAD direction keys.  We dont want any
1492e42db84057616ff5fc755ab55debef731015d3aDake Gu        // child to get focus.  On touch screen, Picker is not focusable.
1502e42db84057616ff5fc755ab55debef731015d3aDake Gu        setFocusable(true);
1512e42db84057616ff5fc755ab55debef731015d3aDake Gu        setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1522e42db84057616ff5fc755ab55debef731015d3aDake Gu        // Make it enabled and clickable to receive Click event.
1532e42db84057616ff5fc755ab55debef731015d3aDake Gu        setEnabled(true);
1542e42db84057616ff5fc755ab55debef731015d3aDake Gu        setClickable(true);
15571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
15671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mFocusedAlpha = 1f; //getFloat(R.dimen.list_item_selected_title_text_alpha);
15771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mUnfocusedAlpha = 1f; //getFloat(R.dimen.list_item_unselected_text_alpha);
15871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mVisibleColumnAlpha = 0.5f; //getFloat(R.dimen.picker_item_visible_column_item_alpha);
15971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mInvisibleColumnAlpha = 0f; //getFloat(R.dimen.picker_item_invisible_column_item_alpha);
16071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
16171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mAlphaAnimDuration = 200; // mContext.getResources().getInteger(R.integer.dialog_animation_duration);
16271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
16371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mDecelerateInterpolator = new DecelerateInterpolator(2.5F);
16471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mAccelerateInterpolator = new AccelerateInterpolator(2.5F);
16571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
16671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        LayoutInflater inflater = LayoutInflater.from(getContext());
16771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mRootView = (ViewGroup) inflater.inflate(getRootLayoutId(), this, true);
1682e42db84057616ff5fc755ab55debef731015d3aDake Gu        mPickerView = (ViewGroup) mRootView.findViewById(getPickerId());
16971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
17071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
17171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
17271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
17371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Get nth PickerColumn.
17471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param colIndex  Index of PickerColumn.
17571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @return PickerColumn at colIndex or null if {@link #setColumns(ArrayList)} is not called yet.
17671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
17771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public PickerColumn getColumnAt(int colIndex) {
17871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns == null) {
17971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return null;
18071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
18171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return mColumns.get(colIndex);
18271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
18371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
18471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
18571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Get number of PickerColumns.
18671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @return Number of PickerColumns or 0 if {@link #setColumns(ArrayList)} is not called yet.
18771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
18871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public int getColumnsCount() {
18971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns == null) {
19071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return 0;
19171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
19271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return mColumns.size();
19371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
19471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
19571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
196b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu     * Set columns and create Views.
19771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columns PickerColumns to be shown in the Picker.
19871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
19971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void setColumns(ArrayList<PickerColumn> columns) {
200b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mColumnViews.clear();
201b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mPickerView.removeAllViews();
202b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        mColumns = new ArrayList<PickerColumn>(columns);
203b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        if (mActivatedColumn > mColumns.size() - 1) {
204b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu            mActivatedColumn = mColumns.size() - 1;
20571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
20671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        LayoutInflater inflater = LayoutInflater.from(getContext());
20771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        int totalCol = getColumnsCount();
20871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        for (int i = 0; i < totalCol; i++) {
20971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            final int colIndex = i;
21071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            final VerticalGridView columnView = (VerticalGridView) inflater.inflate(
21171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    R.layout.lb_picker_column, mPickerView, false);
2122e42db84057616ff5fc755ab55debef731015d3aDake Gu            // we dont want VerticalGridView to receive focus.
2132e42db84057616ff5fc755ab55debef731015d3aDake Gu            columnView.setFocusableInTouchMode(false);
2142e42db84057616ff5fc755ab55debef731015d3aDake Gu            columnView.setFocusable(false);
2152e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize(columnView);
2162e42db84057616ff5fc755ab55debef731015d3aDake Gu            // always center aligned, not aligning selected item on top/bottom edge.
21771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
2182e42db84057616ff5fc755ab55debef731015d3aDake Gu            // Width is dynamic, so has fixed size is false.
21971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setHasFixedSize(false);
22071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mColumnViews.add(columnView);
22171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
22271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // add view to root
22371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mPickerView.addView(columnView);
22471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
22571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // add a separator if not the last element
22671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (i != totalCol - 1 && getSeparator() != null) {
22771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                TextView separator = (TextView) inflater.inflate(
22871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                        getPickerSeparatorLayoutId(), mPickerView, false);
22971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                separator.setText(getSeparator());
23071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                mPickerView.addView(separator);
23171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
23271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
23371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setAdapter(new PickerScrollArrayAdapter(getContext(),
23471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    getPickerItemLayoutId(), getPickerItemTextViewId(), colIndex));
23571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            columnView.setOnChildViewHolderSelectedListener(mColumnChangeListener);
23671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
23771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
23871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
23971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
24071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * When column labels change or column range changes, call this function to re-populate the
24171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * selection list.
24271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex Index of column to update.
24371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
24471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void updateAdapter(int columnIndex) {
24571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        VerticalGridView columnView = mColumnViews.get(columnIndex);
24671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        PickerScrollArrayAdapter adapter = (PickerScrollArrayAdapter) columnView.getAdapter();
247b19799d69cbbe7f7ca104520e9b07312ab7539afDake Gu        if (adapter != null && !columnView.isComputingLayout()) {
24871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            adapter.notifyDataSetChanged();
24971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
25071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
25171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
25271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
25371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Manually set current value of a column.  The function will update UI and notify listeners.
25471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex Index of column to update.
25571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param value New value of the column.
25671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param runAnimation True to scroll to the value or false otherwise.
25771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
25871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void updateValue(int columnIndex, int value, boolean runAnimation) {
25971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns.get(columnIndex).setCurrentValue(value)) {
26071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            notifyValueChanged(columnIndex);
26171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            VerticalGridView columnView = mColumnViews.get(columnIndex);
26271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (columnView != null) {
26371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int position = value - mColumns.get(columnIndex).getMinValue();
26471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                if (runAnimation) {
26571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    columnView.setSelectedPositionSmooth(position);
26671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                } else {
26771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    columnView.setSelectedPosition(position);
26871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                }
26971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
27071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
27171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
27271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
27371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private void notifyValueChanged(int columnIndex) {
27471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners != null) {
27571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            for (int i = mListeners.size() - 1; i >= 0; i--) {
27671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                mListeners.get(i).onValueChanged(this, columnIndex);
27771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
27871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
27971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
28071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
28171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void addPickerValueListener(PickerValueListener listener) {
28271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners == null) {
28371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mListeners = new ArrayList<Picker.PickerValueListener>();
28471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
28571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        mListeners.add(listener);
28671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
28771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
28871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void removePickerValueListener(PickerValueListener listener) {
28971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mListeners != null) {
29071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mListeners.remove(listener);
29171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
29271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
29371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
2942e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnAlpha(int colIndex, boolean animate) {
2952e42db84057616ff5fc755ab55debef731015d3aDake Gu        VerticalGridView column = mColumnViews.get(colIndex);
29671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
29771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        int selected = column.getSelectedPosition();
29871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        View item;
29971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
30071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        for (int i = 0; i < column.getAdapter().getItemCount(); i++) {
30171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            item = column.getLayoutManager().findViewByPosition(i);
30271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (item != null) {
3032e42db84057616ff5fc755ab55debef731015d3aDake Gu                setOrAnimateAlpha(item, (selected == i), colIndex, animate);
30471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
30571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
30671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
30771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
3082e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void setOrAnimateAlpha(View view, boolean selected, int colIndex,
3092e42db84057616ff5fc755ab55debef731015d3aDake Gu            boolean animate) {
3102e42db84057616ff5fc755ab55debef731015d3aDake Gu        boolean columnShownAsActivated = colIndex == mActivatedColumn || !isFocused();
31171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (selected) {
31271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // set alpha for main item (selected) in the column
3132e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (columnShownAsActivated) {
31471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mFocusedAlpha, -1, mDecelerateInterpolator);
31571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
31671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mUnfocusedAlpha, -1,  mDecelerateInterpolator);
31771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
31871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        } else {
31971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            // set alpha for remaining items in the column
3202e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (columnShownAsActivated) {
32171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mVisibleColumnAlpha, -1, mDecelerateInterpolator);
32271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
32371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                setOrAnimateAlpha(view, animate, mInvisibleColumnAlpha, -1,
32471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                        mDecelerateInterpolator);
32571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
32671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
32771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
32871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
32971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private void setOrAnimateAlpha(View view, boolean animate, float destAlpha, float startAlpha,
33071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            Interpolator interpolator) {
33171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        view.animate().cancel();
33271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (!animate) {
33371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            view.setAlpha(destAlpha);
33471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        } else {
33571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (startAlpha >= 0.0f) {
33671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                // set a start alpha
33771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                view.setAlpha(startAlpha);
33871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
33971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            view.animate().alpha(destAlpha)
34071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .setDuration(mAlphaAnimDuration).setInterpolator(interpolator)
34171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .start();
34271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
34371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
34471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
34571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    /**
34671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * Classes extending {@link Picker} can override this function to supply the
34771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * behavior when a list has been scrolled.  Subclass may call {@link #updateValue(int, int,
34871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * boolean)} and or {@link #updateAdapter(int)}.  Subclass should not directly call
34971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * {@link PickerColumn#setCurrentValue(int)} which does not update internal state or notify
35071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * listeners.
35171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param columnIndex index of which column was changed.
35271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     * @param newValue A new value desired to be set on the column.
35371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu     */
35471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    public void onColumnValueChange(int columnIndex, int newValue) {
35571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        if (mColumns.get(columnIndex).setCurrentValue(newValue)) {
35671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            notifyValueChanged(columnIndex);
35771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
35871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
35971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private float getFloat(int resourceId) {
36171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        TypedValue buffer = new TypedValue();
36271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        getContext().getResources().getValue(resourceId, buffer, true);
36371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        return buffer.getFloat();
36471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
36571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    static class ViewHolder extends RecyclerView.ViewHolder {
36771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        final TextView textView;
36871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
36971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        ViewHolder(View v, TextView textView) {
37071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            super(v);
37171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            this.textView = textView;
37271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
37371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
37471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
37571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    class PickerScrollArrayAdapter extends RecyclerView.Adapter<ViewHolder> {
37671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
37771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mResource;
37871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mColIndex;
37971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private final int mTextViewResourceId;
38071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        private PickerColumn mData;
38171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
38271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        PickerScrollArrayAdapter(Context context, int resource, int textViewResourceId,
38371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int colIndex) {
38471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mResource = resource;
38571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mColIndex = colIndex;
38671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mTextViewResourceId = textViewResourceId;
38771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mData = mColumns.get(mColIndex);
38871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
38971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
39071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
39271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            View v = inflater.inflate(mResource, parent, false);
39371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            TextView textView;
39471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (mTextViewResourceId != 0) {
39571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                textView = (TextView) v.findViewById(mTextViewResourceId);
39671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            } else {
39771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                textView = (TextView) v;
39871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
39971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            ViewHolder vh = new ViewHolder(v, textView);
40071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return vh;
40171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
40271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
40371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onBindViewHolder(ViewHolder holder, int position) {
40471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (holder.textView != null && mData != null) {
40571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                holder.textView.setText(mData.getValueLabelAt(mData.getMinValue() + position));
40671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
40771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            setOrAnimateAlpha(holder.itemView,
40871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    (mColumnViews.get(mColIndex).getSelectedPosition() == position),
4092e42db84057616ff5fc755ab55debef731015d3aDake Gu                    mColIndex, false);
41071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
41171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
41271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void setData(PickerColumn data) {
41371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            mData = data;
41471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            notifyDataSetChanged();
41571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
41671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
41771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public int getItemCount() {
41871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return mData == null ? 0 : mData.getItemsCount();
41971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
42071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    }
42171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
42271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    private final OnChildViewHolderSelectedListener mColumnChangeListener = new
42371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            OnChildViewHolderSelectedListener() {
42471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
42571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        @Override
42671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        public void onChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
42771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int position, int subposition) {
42871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            PickerScrollArrayAdapter pickerScrollArrayAdapter = (PickerScrollArrayAdapter) parent
42971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                    .getAdapter();
43071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
43171d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            int colIndex = mColumnViews.indexOf(parent);
4322e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnAlpha(colIndex, true);
43371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            if (child != null) {
43471d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                int newValue = mColumns.get(colIndex).getMinValue() + position;
43571d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu                onColumnValueChange(colIndex, newValue);
43671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
43771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
43871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
43971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu    };
44071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
4412e42db84057616ff5fc755ab55debef731015d3aDake Gu    @Override
4422e42db84057616ff5fc755ab55debef731015d3aDake Gu    public boolean dispatchKeyEvent(android.view.KeyEvent event) {
4432e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (isExpanded()) {
4442e42db84057616ff5fc755ab55debef731015d3aDake Gu            final int keyCode = event.getKeyCode();
4452e42db84057616ff5fc755ab55debef731015d3aDake Gu            switch (keyCode) {
4462e42db84057616ff5fc755ab55debef731015d3aDake Gu            case KeyEvent.KEYCODE_DPAD_LEFT:
4472e42db84057616ff5fc755ab55debef731015d3aDake Gu            case KeyEvent.KEYCODE_DPAD_RIGHT:
4482e42db84057616ff5fc755ab55debef731015d3aDake Gu                if (event.getAction() == KeyEvent.ACTION_DOWN) {
4492e42db84057616ff5fc755ab55debef731015d3aDake Gu                    if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL?
4502e42db84057616ff5fc755ab55debef731015d3aDake Gu                            keyCode == KeyEvent.KEYCODE_DPAD_LEFT :
4512e42db84057616ff5fc755ab55debef731015d3aDake Gu                            keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
4522e42db84057616ff5fc755ab55debef731015d3aDake Gu                        if (mActivatedColumn < getColumnsCount() - 1) {
4532e42db84057616ff5fc755ab55debef731015d3aDake Gu                            setActiveColumn(mActivatedColumn + 1);
4542e42db84057616ff5fc755ab55debef731015d3aDake Gu                        }
4552e42db84057616ff5fc755ab55debef731015d3aDake Gu                    } else {
4562e42db84057616ff5fc755ab55debef731015d3aDake Gu                        if (mActivatedColumn > 0) {
4572e42db84057616ff5fc755ab55debef731015d3aDake Gu                            setActiveColumn(mActivatedColumn - 1);
4582e42db84057616ff5fc755ab55debef731015d3aDake Gu                        }
4592e42db84057616ff5fc755ab55debef731015d3aDake Gu                    }
4602e42db84057616ff5fc755ab55debef731015d3aDake Gu                }
4612e42db84057616ff5fc755ab55debef731015d3aDake Gu                break;
4622e42db84057616ff5fc755ab55debef731015d3aDake Gu            case KeyEvent.KEYCODE_DPAD_UP:
4632e42db84057616ff5fc755ab55debef731015d3aDake Gu            case KeyEvent.KEYCODE_DPAD_DOWN:
4642e42db84057616ff5fc755ab55debef731015d3aDake Gu                if (event.getAction() == KeyEvent.ACTION_DOWN && mActivatedColumn >= 0) {
4652e42db84057616ff5fc755ab55debef731015d3aDake Gu                    VerticalGridView gridView = mColumnViews.get(mActivatedColumn);
4662e42db84057616ff5fc755ab55debef731015d3aDake Gu                    if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
4672e42db84057616ff5fc755ab55debef731015d3aDake Gu                        int newPosition = gridView.getSelectedPosition() - 1;
4682e42db84057616ff5fc755ab55debef731015d3aDake Gu                        if (newPosition >= 0) {
4692e42db84057616ff5fc755ab55debef731015d3aDake Gu                            gridView.setSelectedPositionSmooth(newPosition);
4702e42db84057616ff5fc755ab55debef731015d3aDake Gu                        }
4712e42db84057616ff5fc755ab55debef731015d3aDake Gu                    } else {
4722e42db84057616ff5fc755ab55debef731015d3aDake Gu                        int newPosition = gridView.getSelectedPosition() + 1;
4732e42db84057616ff5fc755ab55debef731015d3aDake Gu                        if (newPosition < gridView.getAdapter().getItemCount()) {
4742e42db84057616ff5fc755ab55debef731015d3aDake Gu                            gridView.setSelectedPositionSmooth(newPosition);
4752e42db84057616ff5fc755ab55debef731015d3aDake Gu                        }
4762e42db84057616ff5fc755ab55debef731015d3aDake Gu                    }
4772e42db84057616ff5fc755ab55debef731015d3aDake Gu                }
4782e42db84057616ff5fc755ab55debef731015d3aDake Gu                break;
4792e42db84057616ff5fc755ab55debef731015d3aDake Gu            default:
4802e42db84057616ff5fc755ab55debef731015d3aDake Gu                return super.dispatchKeyEvent(event);
4812e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
48271d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            return true;
48371d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
4842e42db84057616ff5fc755ab55debef731015d3aDake Gu        return super.dispatchKeyEvent(event);
4852e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
48671d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
4872e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
4882e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Classes extending {@link Picker} can choose to override this method to
4892e42db84057616ff5fc755ab55debef731015d3aDake Gu     * supply the {@link Picker}'s column's single item height in pixels.
4902e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
4912e42db84057616ff5fc755ab55debef731015d3aDake Gu    protected int getPickerItemHeightPixels() {
4922e42db84057616ff5fc755ab55debef731015d3aDake Gu        return getContext().getResources().getDimensionPixelSize(R.dimen.picker_item_height);
4932e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
4942e42db84057616ff5fc755ab55debef731015d3aDake Gu
4952e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnSize() {
4962e42db84057616ff5fc755ab55debef731015d3aDake Gu        for (int i = 0; i < getColumnsCount(); i++) {
4972e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize(mColumnViews.get(i));
4982e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
4992e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5002e42db84057616ff5fc755ab55debef731015d3aDake Gu
5012e42db84057616ff5fc755ab55debef731015d3aDake Gu    private void updateColumnSize(VerticalGridView columnView) {
5022e42db84057616ff5fc755ab55debef731015d3aDake Gu        ViewGroup.LayoutParams lp = columnView.getLayoutParams();
5032e42db84057616ff5fc755ab55debef731015d3aDake Gu        lp.height = (int) (getPickerItemHeightPixels() * (isExpanded() ?
5042e42db84057616ff5fc755ab55debef731015d3aDake Gu                getVisiblePickerItemsInExpand() : getVisiblePickerItems()));
5052e42db84057616ff5fc755ab55debef731015d3aDake Gu        columnView.setLayoutParams(lp);
5062e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5072e42db84057616ff5fc755ab55debef731015d3aDake Gu
5082e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5092e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Returns number of visible items showing in a column when it's expanded, it's 3 by default.
5102e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return Number of visible items showing in a column when it's expanded.
5112e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5122e42db84057616ff5fc755ab55debef731015d3aDake Gu    public float getVisiblePickerItemsInExpand() {
5132e42db84057616ff5fc755ab55debef731015d3aDake Gu        return mVisibleItemsInExpand;
5142e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5152e42db84057616ff5fc755ab55debef731015d3aDake Gu
5162e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5172e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Change number of visible items showing in a column when it's expanded.
5182e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param visiblePickerItems Number of visible items showing in a column when it's expanded.
5192e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5202e42db84057616ff5fc755ab55debef731015d3aDake Gu    public void setVisiblePickerItemsInExpand(float visiblePickerItems) {
5212e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (visiblePickerItems <= 0) {
5222e42db84057616ff5fc755ab55debef731015d3aDake Gu            throw new IllegalArgumentException();
5232e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5242e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (mVisibleItemsInExpand != visiblePickerItems) {
5252e42db84057616ff5fc755ab55debef731015d3aDake Gu            mVisibleItemsInExpand = visiblePickerItems;
5262e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (isExpanded()) {
5272e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnSize();
5282e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
5292e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5302e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5312e42db84057616ff5fc755ab55debef731015d3aDake Gu
5322e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5332e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Returns number of visible items showing in a column when it's not expanded, it's 1 by
5342e42db84057616ff5fc755ab55debef731015d3aDake Gu     * default.
5352e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return Number of visible items showing in a column when it's not expanded.
5362e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5372e42db84057616ff5fc755ab55debef731015d3aDake Gu    public float getVisiblePickerItems() {
5382e42db84057616ff5fc755ab55debef731015d3aDake Gu        return 1;
5392e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5402e42db84057616ff5fc755ab55debef731015d3aDake Gu
5412e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5422e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Change number of visible items showing in a column when it's not expanded, it's 1 by default.
5432e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param pickerItems Number of visible items showing in a column when it's not expanded.
5442e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5452e42db84057616ff5fc755ab55debef731015d3aDake Gu    public void setVisiblePickerItems(float pickerItems) {
5462e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (pickerItems <= 0) {
5472e42db84057616ff5fc755ab55debef731015d3aDake Gu            throw new IllegalArgumentException();
5482e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5492e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (mVisibleItems != pickerItems) {
5502e42db84057616ff5fc755ab55debef731015d3aDake Gu            mVisibleItems = pickerItems;
5512e42db84057616ff5fc755ab55debef731015d3aDake Gu            if (!isExpanded()) {
5522e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnSize();
5532e42db84057616ff5fc755ab55debef731015d3aDake Gu            }
5542e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5552e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5562e42db84057616ff5fc755ab55debef731015d3aDake Gu
5572e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5582e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Change expanded state of Picker, the height LayoutParams will be changed.
5592e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @see #getVisiblePickerItemsInExpand()
5602e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @see #getVisiblePickerItems()
5612e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param expanded New expanded state of Picker.
5622e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5632e42db84057616ff5fc755ab55debef731015d3aDake Gu    public void setExpanded(boolean expanded) {
5642e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (mExpanded != expanded) {
5652e42db84057616ff5fc755ab55debef731015d3aDake Gu            mExpanded = expanded;
5662e42db84057616ff5fc755ab55debef731015d3aDake Gu            updateColumnSize();
5672e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
5682e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5692e42db84057616ff5fc755ab55debef731015d3aDake Gu
5702e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5712e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Returns true if the Picker is currently expanded, false otherwise.
5722e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return True if the Picker is currently expanded, false otherwise.
5732e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5742e42db84057616ff5fc755ab55debef731015d3aDake Gu    public boolean isExpanded() {
5752e42db84057616ff5fc755ab55debef731015d3aDake Gu        return mExpanded;
5762e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5772e42db84057616ff5fc755ab55debef731015d3aDake Gu
5782e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5792e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Change current activated column.  Shows multiple items on activate column if Picker has
5802e42db84057616ff5fc755ab55debef731015d3aDake Gu     * focus. Show multiple items on all column if Picker has no focus (e.g. a Touchscreen
5812e42db84057616ff5fc755ab55debef731015d3aDake Gu     * screen).
5822e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param columnIndex Index of column to activate.
5832e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5842e42db84057616ff5fc755ab55debef731015d3aDake Gu    public void setActiveColumn(int columnIndex) {
5852e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (mActivatedColumn != columnIndex) {
5862e42db84057616ff5fc755ab55debef731015d3aDake Gu            mActivatedColumn = columnIndex;
58771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            for (int i = 0; i < mColumnViews.size(); i++) {
5882e42db84057616ff5fc755ab55debef731015d3aDake Gu                updateColumnAlpha(i, true);
58971d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu            }
59071d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu        }
5912e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
5922e42db84057616ff5fc755ab55debef731015d3aDake Gu
5932e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
5942e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Get current activated column index.
5952e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return Current activated column index.
5962e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
5972e42db84057616ff5fc755ab55debef731015d3aDake Gu    public int getActiveColumn() {
5982e42db84057616ff5fc755ab55debef731015d3aDake Gu        return mActivatedColumn;
5992e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
6002e42db84057616ff5fc755ab55debef731015d3aDake Gu
6012e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
6022e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Enable or disable toggle on click when Picker has focus.
6032e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @param toggleExpandOnClick True to enable toggle on click when Picker has focus, false
6042e42db84057616ff5fc755ab55debef731015d3aDake Gu     * otherwise.
6052e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
6062e42db84057616ff5fc755ab55debef731015d3aDake Gu    public void setToggleExpandOnClick(boolean toggleExpandOnClick) {
6072e42db84057616ff5fc755ab55debef731015d3aDake Gu        mToggleExpandOnClick = toggleExpandOnClick;
6082e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
6092e42db84057616ff5fc755ab55debef731015d3aDake Gu
6102e42db84057616ff5fc755ab55debef731015d3aDake Gu    /**
6112e42db84057616ff5fc755ab55debef731015d3aDake Gu     * Returns true if toggle on click is enabled when Picker has focus, false otherwise.
6122e42db84057616ff5fc755ab55debef731015d3aDake Gu     * @return True if toggle on click is enabled when Picker has focus, false otherwise.
6132e42db84057616ff5fc755ab55debef731015d3aDake Gu     */
6142e42db84057616ff5fc755ab55debef731015d3aDake Gu    public boolean isToggleExpandOnClick() {
6152e42db84057616ff5fc755ab55debef731015d3aDake Gu        return mToggleExpandOnClick;
6162e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
6172e42db84057616ff5fc755ab55debef731015d3aDake Gu
6182e42db84057616ff5fc755ab55debef731015d3aDake Gu    @Override
6192e42db84057616ff5fc755ab55debef731015d3aDake Gu    public boolean performClick() {
6202e42db84057616ff5fc755ab55debef731015d3aDake Gu        if (isFocused() && isToggleExpandOnClick()) {
6212e42db84057616ff5fc755ab55debef731015d3aDake Gu            setExpanded(!isExpanded());
6222e42db84057616ff5fc755ab55debef731015d3aDake Gu            super.performClick();
6232e42db84057616ff5fc755ab55debef731015d3aDake Gu            return true;
6242e42db84057616ff5fc755ab55debef731015d3aDake Gu        }
6252e42db84057616ff5fc755ab55debef731015d3aDake Gu        return super.performClick();
6262e42db84057616ff5fc755ab55debef731015d3aDake Gu    }
62771d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu
62871d30e1cf5514761ba8ad4bd3c8c70540d60dbd3Dake Gu}
629