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.support.v7.widget.RecyclerView;
17 import android.view.View;
18 
19 /**
20  * Optional facet provided by {@link RecyclerView.Adapter} or {@link RecyclerView.ViewHolder} for
21  * use in {@link HorizontalGridView} and {@link VerticalGridView}. Apps using {@link Presenter} may
22  * set facet using {@link Presenter#setFacet(Class, Object)} or
23  * {@link Presenter.ViewHolder#setFacet(Class, Object)}. Facet on ViewHolder has a higher priority
24  * than Presenter or Adapter.
25  * <p>
26  * ItemAlignmentFacet contains single or multiple {@link ItemAlignmentDef}s. First
27  * {@link ItemAlignmentDef} describes the default alignment position for ViewHolder, it also
28  * overrides the default item alignment settings on {@link VerticalGridView} and
29  * {@link HorizontalGridView} (see {@link BaseGridView#setItemAlignmentOffset(int)} etc). One
30  * ItemAlignmentFacet can have multiple {@link ItemAlignmentDef}s, e.g. having two aligned positions
31  * when child1 gets focus or child2 gets focus. Grid view will visit focused view and its
32  * ancestors till the root of ViewHolder to match {@link ItemAlignmentDef}s'
33  * {@link ItemAlignmentDef#getItemAlignmentFocusViewId()}. Once a match found, the
34  * {@link ItemAlignmentDef} is used to calculate alignment position.
35  */
36 public final class ItemAlignmentFacet {
37 
38     /**
39      * Value indicates that percent is not used. Equivalent to 0.
40      */
41     public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1;
42 
43     /**
44      * Definition of an alignment position under a view.
45      */
46     public static class ItemAlignmentDef {
47         int mViewId = View.NO_ID;
48         int mFocusViewId = View.NO_ID;
49         int mOffset = 0;
50         float mOffsetPercent = 50f;
51         boolean mOffsetWithPadding = false;
52         private boolean mAlignToBaseline;
53 
54         /**
55          * Sets number of pixels to the end of low edge. Supports right to left layout direction.
56          * @param offset In left to right or vertical case, it's the offset added to left/top edge.
57          *               In right to left case, it's the offset subtracted from right edge.
58          */
setItemAlignmentOffset(int offset)59         public final void setItemAlignmentOffset(int offset) {
60             mOffset = offset;
61         }
62 
63         /**
64          * Returns number of pixels to the end of low edge. Supports right to left layout direction.
65          * In left to right or vertical case, it's the offset added to left/top edge. In right to
66          * left case, it's the offset subtracted from right edge.
67          * @return Number of pixels to the end of low edge.
68          */
getItemAlignmentOffset()69         public final int getItemAlignmentOffset() {
70             return mOffset;
71         }
72 
73         /**
74          * Sets whether applies padding to item alignment when
75          * {@link #getItemAlignmentOffsetPercent()} is 0 or 100.
76          * <p>When true:
77          * Applies start/top padding if {@link #getItemAlignmentOffsetPercent()} is 0.
78          * Applies end/bottom padding if {@link #getItemAlignmentOffsetPercent()} is 100.
79          * Does not apply padding if {@link #getItemAlignmentOffsetPercent()} is neither 0 nor 100.
80          * </p>
81          * <p>When false: does not apply padding</p>
82          */
setItemAlignmentOffsetWithPadding(boolean withPadding)83         public final void setItemAlignmentOffsetWithPadding(boolean withPadding) {
84             mOffsetWithPadding = withPadding;
85         }
86 
87         /**
88          * Returns true if applies padding to item alignment when
89          * {@link #getItemAlignmentOffsetPercent()} is 0 or 100; returns false otherwise.
90          * <p>When true:
91          * Applies start/top padding when {@link #getItemAlignmentOffsetPercent()} is 0.
92          * Applies end/bottom padding when {@link #getItemAlignmentOffsetPercent()} is 100.
93          * Does not apply padding if {@link #getItemAlignmentOffsetPercent()} is neither 0 nor 100.
94          * </p>
95          * <p>When false: does not apply padding</p>
96          */
isItemAlignmentOffsetWithPadding()97         public final boolean isItemAlignmentOffsetWithPadding() {
98             return mOffsetWithPadding;
99         }
100 
101         /**
102          * Sets the offset percent for item alignment in addition to offset.  E.g., 40
103          * means 40% of width/height from the low edge. In the right to left case, it's the 40%
104          * width from right edge. Use {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable.
105          */
setItemAlignmentOffsetPercent(float percent)106         public final void setItemAlignmentOffsetPercent(float percent) {
107             if ((percent < 0 || percent > 100)
108                     && percent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
109                 throw new IllegalArgumentException();
110             }
111             mOffsetPercent = percent;
112         }
113 
114         /**
115          * Gets the offset percent for item alignment in addition to offset. E.g., 40
116          * means 40% of the width from the low edge. In the right to left case, it's the 40% from
117          * right edge. Use {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable.
118          */
getItemAlignmentOffsetPercent()119         public final float getItemAlignmentOffsetPercent() {
120             return mOffsetPercent;
121         }
122 
123         /**
124          * Sets Id of which child view to be aligned.  View.NO_ID refers to root view and should
125          * be only used in first one.  Different view ids of {@link ItemAlignmentFacet
126          * #getAlignmentDefs()} define multiple alignment steps within one itemView, e.g. there are
127          * two child views R.id.child1 and R.id.child2. App may allocated two
128          * {@link ItemAlignmentDef}s, one with view id R.id.child1, the other with view id
129          * R.id.child2. Note this id may or may not be same as the child view that takes focus.
130          *
131          * @param viewId The id of child view that will be aligned to.
132          * @see #setItemAlignmentFocusViewId(int)
133          */
setItemAlignmentViewId(int viewId)134         public final void setItemAlignmentViewId(int viewId) {
135             mViewId = viewId;
136         }
137 
138         /**
139          * Returns Id of which child view to be aligned.  View.NO_ID refers to root view and should
140          * be only used in first one.  Different view ids of {@link ItemAlignmentFacet
141          * #getAlignmentDefs()} define multiple alignment steps within one itemView, e.g. there are
142          * two child views R.id.child1 and R.id.child2. App may allocated two
143          * {@link ItemAlignmentDef}s, one with view id R.id.child1, the other with view id
144          * R.id.child2. Note this id may or may not be same as the child view that takes focus.
145          *
146          * @see #setItemAlignmentFocusViewId(int)
147          */
getItemAlignmentViewId()148         public final int getItemAlignmentViewId() {
149             return mViewId;
150         }
151 
152         /**
153          * Sets Id of which child view take focus for alignment.  When not set, it will use
154          * use same id of {@link #getItemAlignmentViewId()}.
155          * @param viewId The id of child view that will be focused to.
156          */
setItemAlignmentFocusViewId(int viewId)157         public final void setItemAlignmentFocusViewId(int viewId) {
158             mFocusViewId = viewId;
159         }
160 
161         /**
162          * Returns Id of which child view take focus for alignment.  When not set, it will use
163          * use same id of {@link #getItemAlignmentViewId()}
164          */
getItemAlignmentFocusViewId()165         public final int getItemAlignmentFocusViewId() {
166             return mFocusViewId != View.NO_ID ? mFocusViewId : mViewId;
167         }
168 
169         /**
170          * When true, align to {@link View#getBaseline()} for the view of with id equals
171          * {@link #getItemAlignmentViewId()}; false otherwise.
172          * @param alignToBaseline Boolean indicating whether to align to view baseline.
173          */
setAlignedToTextViewBaseline(boolean alignToBaseline)174         public final void setAlignedToTextViewBaseline(boolean alignToBaseline) {
175             this.mAlignToBaseline = alignToBaseline;
176         }
177 
178         /**
179          * Returns true when View should be aligned to {@link View#getBaseline()}
180          */
isAlignedToTextViewBaseLine()181         public boolean isAlignedToTextViewBaseLine() {
182             return mAlignToBaseline;
183         }
184     }
185 
186     private ItemAlignmentDef[] mAlignmentDefs = new ItemAlignmentDef[]{new ItemAlignmentDef()};
187 
isMultiAlignment()188     public boolean isMultiAlignment() {
189         return mAlignmentDefs.length > 1;
190     }
191 
192     /**
193      * Sets definitions of alignment positions.
194      */
setAlignmentDefs(ItemAlignmentDef[] defs)195     public void setAlignmentDefs(ItemAlignmentDef[] defs) {
196         if (defs == null || defs.length < 1) {
197             throw new IllegalArgumentException();
198         }
199         mAlignmentDefs = defs;
200     }
201 
202     /**
203      * Returns read only definitions of alignment positions.
204      */
getAlignmentDefs()205     public ItemAlignmentDef[] getAlignmentDefs() {
206         return mAlignmentDefs;
207     }
208 
209 }
210