• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 import android.graphics.Rect;
19 
20 /**
21  * Standard constants and tools for placing an object within a potentially
22  * larger container.
23  */
24 public class Gravity
25 {
26     /** Constant indicating that no gravity has been set **/
27     public static final int NO_GRAVITY = 0x0000;
28 
29     /** Raw bit indicating the gravity for an axis has been specified. */
30     public static final int AXIS_SPECIFIED = 0x0001;
31 
32     /** Raw bit controlling how the left/top edge is placed. */
33     public static final int AXIS_PULL_BEFORE = 0x0002;
34     /** Raw bit controlling how the right/bottom edge is placed. */
35     public static final int AXIS_PULL_AFTER = 0x0004;
36     /** Raw bit controlling whether the right/bottom edge is clipped to its
37      * container, based on the gravity direction being applied. */
38     public static final int AXIS_CLIP = 0x0008;
39 
40     /** Bits defining the horizontal axis. */
41     public static final int AXIS_X_SHIFT = 0;
42     /** Bits defining the vertical axis. */
43     public static final int AXIS_Y_SHIFT = 4;
44 
45     /** Push object to the top of its container, not changing its size. */
46     public static final int TOP = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_Y_SHIFT;
47     /** Push object to the bottom of its container, not changing its size. */
48     public static final int BOTTOM = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_Y_SHIFT;
49     /** Push object to the left of its container, not changing its size. */
50     public static final int LEFT = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_X_SHIFT;
51     /** Push object to the right of its container, not changing its size. */
52     public static final int RIGHT = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_X_SHIFT;
53 
54     /** Place object in the vertical center of its container, not changing its
55      *  size. */
56     public static final int CENTER_VERTICAL = AXIS_SPECIFIED<<AXIS_Y_SHIFT;
57     /** Grow the vertical size of the object if needed so it completely fills
58      *  its container. */
59     public static final int FILL_VERTICAL = TOP|BOTTOM;
60 
61     /** Place object in the horizontal center of its container, not changing its
62      *  size. */
63     public static final int CENTER_HORIZONTAL = AXIS_SPECIFIED<<AXIS_X_SHIFT;
64     /** Grow the horizontal size of the object if needed so it completely fills
65      *  its container. */
66     public static final int FILL_HORIZONTAL = LEFT|RIGHT;
67 
68     /** Place the object in the center of its container in both the vertical
69      *  and horizontal axis, not changing its size. */
70     public static final int CENTER = CENTER_VERTICAL|CENTER_HORIZONTAL;
71 
72     /** Grow the horizontal and vertical size of the object if needed so it
73      *  completely fills its container. */
74     public static final int FILL = FILL_VERTICAL|FILL_HORIZONTAL;
75 
76     /** Flag to clip the edges of the object to its container along the
77      *  vertical axis. */
78     public static final int CLIP_VERTICAL = AXIS_CLIP<<AXIS_Y_SHIFT;
79 
80     /** Flag to clip the edges of the object to its container along the
81      *  horizontal axis. */
82     public static final int CLIP_HORIZONTAL = AXIS_CLIP<<AXIS_X_SHIFT;
83 
84     /** Raw bit controlling whether the layout direction is relative or not (START/END instead of
85      * absolute LEFT/RIGHT).
86      */
87     public static final int RELATIVE_LAYOUT_DIRECTION = 0x00800000;
88 
89     /**
90      * Binary mask to get the absolute horizontal gravity of a gravity.
91      */
92     public static final int HORIZONTAL_GRAVITY_MASK = (AXIS_SPECIFIED |
93             AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_X_SHIFT;
94     /**
95      * Binary mask to get the vertical gravity of a gravity.
96      */
97     public static final int VERTICAL_GRAVITY_MASK = (AXIS_SPECIFIED |
98             AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_Y_SHIFT;
99 
100     /** Special constant to enable clipping to an overall display along the
101      *  vertical dimension.  This is not applied by default by
102      *  {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so
103      *  yourself by calling {@link #applyDisplay}.
104      */
105     public static final int DISPLAY_CLIP_VERTICAL = 0x10000000;
106 
107     /** Special constant to enable clipping to an overall display along the
108      *  horizontal dimension.  This is not applied by default by
109      *  {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so
110      *  yourself by calling {@link #applyDisplay}.
111      */
112     public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000;
113 
114     /** Push object to x-axis position at the start of its container, not changing its size. */
115     public static final int START = RELATIVE_LAYOUT_DIRECTION | LEFT;
116 
117     /** Push object to x-axis position at the end of its container, not changing its size. */
118     public static final int END = RELATIVE_LAYOUT_DIRECTION | RIGHT;
119 
120     /**
121      * Binary mask for the horizontal gravity and script specific direction bit.
122      */
123     public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
124 
125     /**
126      * Apply a gravity constant to an object. This suppose that the layout direction is LTR.
127      *
128      * @param gravity The desired placement of the object, as defined by the
129      *                constants in this class.
130      * @param w The horizontal size of the object.
131      * @param h The vertical size of the object.
132      * @param container The frame of the containing space, in which the object
133      *                  will be placed.  Should be large enough to contain the
134      *                  width and height of the object.
135      * @param outRect Receives the computed frame of the object in its
136      *                container.
137      */
apply(int gravity, int w, int h, Rect container, Rect outRect)138     public static void apply(int gravity, int w, int h, Rect container, Rect outRect) {
139         apply(gravity, w, h, container, 0, 0, outRect);
140     }
141 
142     /**
143      * Apply a gravity constant to an object and take care if layout direction is RTL or not.
144      *
145      * @param gravity The desired placement of the object, as defined by the
146      *                constants in this class.
147      * @param w The horizontal size of the object.
148      * @param h The vertical size of the object.
149      * @param container The frame of the containing space, in which the object
150      *                  will be placed.  Should be large enough to contain the
151      *                  width and height of the object.
152      * @param outRect Receives the computed frame of the object in its
153      *                container.
154      * @param layoutDirection The layout direction.
155      *
156      * @hide
157      */
apply(int gravity, int w, int h, Rect container, Rect outRect, int layoutDirection)158     public static void apply(int gravity, int w, int h, Rect container,
159             Rect outRect, int layoutDirection) {
160         int absGravity = getAbsoluteGravity(gravity, layoutDirection);
161         apply(absGravity, w, h, container, 0, 0, outRect);
162     }
163 
164     /**
165      * Apply a gravity constant to an object.
166      *
167      * @param gravity The desired placement of the object, as defined by the
168      *                constants in this class.
169      * @param w The horizontal size of the object.
170      * @param h The vertical size of the object.
171      * @param container The frame of the containing space, in which the object
172      *                  will be placed.  Should be large enough to contain the
173      *                  width and height of the object.
174      * @param xAdj Offset to apply to the X axis.  If gravity is LEFT this
175      *             pushes it to the right; if gravity is RIGHT it pushes it to
176      *             the left; if gravity is CENTER_HORIZONTAL it pushes it to the
177      *             right or left; otherwise it is ignored.
178      * @param yAdj Offset to apply to the Y axis.  If gravity is TOP this pushes
179      *             it down; if gravity is BOTTOM it pushes it up; if gravity is
180      *             CENTER_VERTICAL it pushes it down or up; otherwise it is
181      *             ignored.
182      * @param outRect Receives the computed frame of the object in its
183      *                container.
184      */
apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj, Rect outRect)185     public static void apply(int gravity, int w, int h, Rect container,
186             int xAdj, int yAdj, Rect outRect) {
187         switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) {
188             case 0:
189                 outRect.left = container.left
190                         + ((container.right - container.left - w)/2) + xAdj;
191                 outRect.right = outRect.left + w;
192                 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
193                         == (AXIS_CLIP<<AXIS_X_SHIFT)) {
194                     if (outRect.left < container.left) {
195                         outRect.left = container.left;
196                     }
197                     if (outRect.right > container.right) {
198                         outRect.right = container.right;
199                     }
200                 }
201                 break;
202             case AXIS_PULL_BEFORE<<AXIS_X_SHIFT:
203                 outRect.left = container.left + xAdj;
204                 outRect.right = outRect.left + w;
205                 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
206                         == (AXIS_CLIP<<AXIS_X_SHIFT)) {
207                     if (outRect.right > container.right) {
208                         outRect.right = container.right;
209                     }
210                 }
211                 break;
212             case AXIS_PULL_AFTER<<AXIS_X_SHIFT:
213                 outRect.right = container.right - xAdj;
214                 outRect.left = outRect.right - w;
215                 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
216                         == (AXIS_CLIP<<AXIS_X_SHIFT)) {
217                     if (outRect.left < container.left) {
218                         outRect.left = container.left;
219                     }
220                 }
221                 break;
222             default:
223                 outRect.left = container.left + xAdj;
224                 outRect.right = container.right + xAdj;
225                 break;
226         }
227 
228         switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT)) {
229             case 0:
230                 outRect.top = container.top
231                         + ((container.bottom - container.top - h)/2) + yAdj;
232                 outRect.bottom = outRect.top + h;
233                 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
234                         == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
235                     if (outRect.top < container.top) {
236                         outRect.top = container.top;
237                     }
238                     if (outRect.bottom > container.bottom) {
239                         outRect.bottom = container.bottom;
240                     }
241                 }
242                 break;
243             case AXIS_PULL_BEFORE<<AXIS_Y_SHIFT:
244                 outRect.top = container.top + yAdj;
245                 outRect.bottom = outRect.top + h;
246                 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
247                         == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
248                     if (outRect.bottom > container.bottom) {
249                         outRect.bottom = container.bottom;
250                     }
251                 }
252                 break;
253             case AXIS_PULL_AFTER<<AXIS_Y_SHIFT:
254                 outRect.bottom = container.bottom - yAdj;
255                 outRect.top = outRect.bottom - h;
256                 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
257                         == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
258                     if (outRect.top < container.top) {
259                         outRect.top = container.top;
260                     }
261                 }
262                 break;
263             default:
264                 outRect.top = container.top + yAdj;
265                 outRect.bottom = container.bottom + yAdj;
266                 break;
267         }
268     }
269 
270     /**
271      * Apply additional gravity behavior based on the overall "display" that an
272      * object exists in.  This can be used after
273      * {@link #apply(int, int, int, Rect, int, int, Rect)} to place the object
274      * within a visible display.  By default this moves or clips the object
275      * to be visible in the display; the gravity flags
276      * {@link #DISPLAY_CLIP_HORIZONTAL} and {@link #DISPLAY_CLIP_VERTICAL}
277      * can be used to change this behavior.
278      *
279      * @param gravity Gravity constants to modify the placement within the
280      * display.
281      * @param display The rectangle of the display in which the object is
282      * being placed.
283      * @param inoutObj Supplies the current object position; returns with it
284      * modified if needed to fit in the display.
285      */
applyDisplay(int gravity, Rect display, Rect inoutObj)286     public static void applyDisplay(int gravity, Rect display, Rect inoutObj) {
287         if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) {
288             if (inoutObj.top < display.top) inoutObj.top = display.top;
289             if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom;
290         } else {
291             int off = 0;
292             if (inoutObj.top < display.top) off = display.top-inoutObj.top;
293             else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom;
294             if (off != 0) {
295                 if (inoutObj.height() > (display.bottom-display.top)) {
296                     inoutObj.top = display.top;
297                     inoutObj.bottom = display.bottom;
298                 } else {
299                     inoutObj.top += off;
300                     inoutObj.bottom += off;
301                 }
302             }
303         }
304 
305         if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) {
306             if (inoutObj.left < display.left) inoutObj.left = display.left;
307             if (inoutObj.right > display.right) inoutObj.right = display.right;
308         } else {
309             int off = 0;
310             if (inoutObj.left < display.left) off = display.left-inoutObj.left;
311             else if (inoutObj.right > display.right) off = display.right-inoutObj.right;
312             if (off != 0) {
313                 if (inoutObj.width() > (display.right-display.left)) {
314                     inoutObj.left = display.left;
315                     inoutObj.right = display.right;
316                 } else {
317                     inoutObj.left += off;
318                     inoutObj.right += off;
319                 }
320             }
321         }
322     }
323 
324     /**
325      * <p>Indicate whether the supplied gravity has a vertical pull.</p>
326      *
327      * @param gravity the gravity to check for vertical pull
328      * @return true if the supplied gravity has a vertical pull
329      */
isVertical(int gravity)330     public static boolean isVertical(int gravity) {
331         return gravity > 0 && (gravity & VERTICAL_GRAVITY_MASK) != 0;
332     }
333 
334     /**
335      * <p>Indicate whether the supplied gravity has an horizontal pull.</p>
336      *
337      * @param gravity the gravity to check for horizontal pull
338      * @return true if the supplied gravity has an horizontal pull
339      */
isHorizontal(int gravity)340     public static boolean isHorizontal(int gravity) {
341         return gravity > 0 && (gravity & RELATIVE_HORIZONTAL_GRAVITY_MASK) != 0;
342     }
343 
344     /**
345      * <p>Convert script specific gravity to absolute horizontal value.</p>
346      *
347      * if horizontal direction is LTR, then START will set LEFT and END will set RIGHT.
348      * if horizontal direction is RTL, then START will set RIGHT and END will set LEFT.
349      *
350      *
351      * @param gravity The gravity to convert to absolute (horizontal) values.
352      * @param layoutDirection The layout direction.
353      * @return gravity converted to absolute (horizontal) values.
354      */
getAbsoluteGravity(int gravity, int layoutDirection)355     public static int getAbsoluteGravity(int gravity, int layoutDirection) {
356         int result = gravity;
357         // If layout is script specific and gravity is horizontal relative (START or END)
358         if ((result & RELATIVE_LAYOUT_DIRECTION) > 0) {
359             if ((result & Gravity.START) == Gravity.START) {
360                 // Remove the START bit
361                 result &= ~START;
362                 if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
363                     // Set the RIGHT bit
364                     result |= RIGHT;
365                 } else {
366                     // Set the LEFT bit
367                     result |= LEFT;
368                 }
369             } else if ((result & Gravity.END) == Gravity.END) {
370                 // Remove the END bit
371                 result &= ~END;
372                 if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
373                     // Set the LEFT bit
374                     result |= LEFT;
375                 } else {
376                     // Set the RIGHT bit
377                     result |= RIGHT;
378                 }
379             }
380             // Don't need the script specific bit any more, so remove it as we are converting to
381             // absolute values (LEFT or RIGHT)
382             result &= ~RELATIVE_LAYOUT_DIRECTION;
383         }
384         return result;
385     }
386 }
387