1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package android.support.v17.leanback.widget;
15 
16 import android.view.View;
17 
18 import static android.support.v17.leanback.widget.BaseGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
19 
20 import android.support.v7.widget.RecyclerView;
21 
22 /**
23  * Optional facet provided by {@link RecyclerView.Adapter} or {@link RecyclerView.ViewHolder} for
24  * use in {@link HorizontalGridView} and {@link VerticalGridView}. Apps using {@link Presenter} may
25  * set facet using {@link Presenter#setFacet(Class, Object)} or
26  * {@link Presenter.ViewHolder#setFacet(Class, Object)}. Facet on ViewHolder has a higher priority
27  * than Presenter or Adapter.
28  * <p>
29  * ItemAlignmentFacet contains single or multiple {@link ItemAlignmentDef}s. First
30  * {@link ItemAlignmentDef} describes the default alignment position for ViewHolder, it also
31  * overrides the default item alignment settings on {@link VerticalGridView} and
32  * {@link HorizontalGridView}. When there are multiple {@link ItemAlignmentDef}s, the extra
33  * {@link ItemAlignmentDef}s are used to calculate deltas from first alignment position. When a
34  * descendant view is focused within the ViewHolder, grid view will visit focused view and its
35  * ancestors till the root of ViewHolder to match extra {@link ItemAlignmentDef}s'
36  * {@link ItemAlignmentDef#getItemAlignmentViewId()}. Once a match found, the
37  * {@link ItemAlignmentDef} is used to adjust a scroll delta from default alignment position.
38  */
39 public final class ItemAlignmentFacet {
40 
41     /**
42      * Value indicates that percent is not used.
43      */
44     public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1;
45 
46     /**
47      * Definition of an alignment position under a view.
48      */
49     public static class ItemAlignmentDef {
50         int mViewId = View.NO_ID;
51         int mFocusViewId = View.NO_ID;
52         int mOffset = 0;
53         float mOffsetPercent = 50f;
54         boolean mOffsetWithPadding = false;
55 
56         /**
57          * Sets number of pixels to offset. Can be negative for alignment from the high edge, or
58          * positive for alignment from the low edge.
59          */
setItemAlignmentOffset(int offset)60         public final void setItemAlignmentOffset(int offset) {
61             mOffset = offset;
62         }
63 
64         /**
65          * Gets number of pixels to offset. Can be negative for alignment from the high edge, or
66          * positive for alignment from the low edge.
67          */
getItemAlignmentOffset()68         public final int getItemAlignmentOffset() {
69             return mOffset;
70         }
71 
72         /**
73          * Sets whether to include left/top padding for positive item offset, include
74          * right/bottom padding for negative item offset.
75          */
setItemAlignmentOffsetWithPadding(boolean withPadding)76         public final void setItemAlignmentOffsetWithPadding(boolean withPadding) {
77             mOffsetWithPadding = withPadding;
78         }
79 
80         /**
81          * When it is true: we include left/top padding for positive item offset, include
82          * right/bottom padding for negative item offset.
83          */
isItemAlignmentOffsetWithPadding()84         public final boolean isItemAlignmentOffsetWithPadding() {
85             return mOffsetWithPadding;
86         }
87 
88         /**
89          * Sets the offset percent for item alignment in addition to offset.  E.g., 40
90          * means 40% of the width from the low edge. Use {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED}
91          * to disable.
92          */
setItemAlignmentOffsetPercent(float percent)93         public final void setItemAlignmentOffsetPercent(float percent) {
94             if ( (percent < 0 || percent > 100) &&
95                     percent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
96                 throw new IllegalArgumentException();
97             }
98             mOffsetPercent = percent;
99         }
100 
101         /**
102          * Gets the offset percent for item alignment in addition to offset. E.g., 40
103          * means 40% of the width from the low edge. Use {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED}
104          * to disable.
105          */
getItemAlignmentOffsetPercent()106         public final float getItemAlignmentOffsetPercent() {
107             return mOffsetPercent;
108         }
109 
110         /**
111          * Sets Id of which child view to be aligned.  View.NO_ID refers to root view and should
112          * be only used in first one.  Extra ItemAlignmentDefs should provide view id to match
113          * currently focused view.
114          */
setItemAlignmentViewId(int viewId)115         public final void setItemAlignmentViewId(int viewId) {
116             mViewId = viewId;
117         }
118 
119         /**
120          * Gets Id of which child view to be aligned.  View.NO_ID refers to root view and should
121          * be only used in first one.  Extra ItemAlignmentDefs should provide view id to match
122          * currently focused view.
123          */
getItemAlignmentViewId()124         public final int getItemAlignmentViewId() {
125             return mViewId;
126         }
127 
128         /**
129          * Sets Id of which child view take focus for alignment.  When not set, it will use
130          * use same id of {@link #getItemAlignmentViewId()}
131          */
setItemAlignmentFocusViewId(int viewId)132         public final void setItemAlignmentFocusViewId(int viewId) {
133             mFocusViewId = viewId;
134         }
135 
136         /**
137          * Returns Id of which child view take focus for alignment.  When not set, it will use
138          * use same id of {@link #getItemAlignmentViewId()}
139          */
getItemAlignmentFocusViewId()140         public final int getItemAlignmentFocusViewId() {
141             return mFocusViewId != View.NO_ID ? mFocusViewId : mViewId;
142         }
143     }
144 
145     private ItemAlignmentDef[] mAlignmentDefs = new ItemAlignmentDef[]{new ItemAlignmentDef()};
146 
isMultiAlignment()147     public boolean isMultiAlignment() {
148         return mAlignmentDefs.length > 1;
149     }
150 
151     /**
152      * Sets definitions of alignment positions.
153      */
setAlignmentDefs(ItemAlignmentDef[] defs)154     public void setAlignmentDefs(ItemAlignmentDef[] defs) {
155         if (defs == null || defs.length < 1) {
156             throw new IllegalArgumentException();
157         }
158         mAlignmentDefs = defs;
159     }
160 
161     /**
162      * Returns read only definitions of alignment positions.
163      */
getAlignmentDefs()164     public ItemAlignmentDef[] getAlignmentDefs() {
165         return mAlignmentDefs;
166     }
167 
168 }
169