Gravity.java revision 935ae463d495d41155e27feb849768ad2b8b16db
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 17package android.view; 18import android.graphics.Rect; 19 20/** 21 * Standard constants and tools for placing an object within a potentially 22 * larger container. 23 */ 24public 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 /** 85 * Binary mask to get the horizontal gravity of a gravity. 86 */ 87 public static final int HORIZONTAL_GRAVITY_MASK = (AXIS_SPECIFIED | 88 AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_X_SHIFT; 89 /** 90 * Binary mask to get the vertical gravity of a gravity. 91 */ 92 public static final int VERTICAL_GRAVITY_MASK = (AXIS_SPECIFIED | 93 AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_Y_SHIFT; 94 95 /** Special constant to enable clipping to an overall display along the 96 * vertical dimension. This is not applied by default by 97 * {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so 98 * yourself by calling {@link #applyDisplay}. 99 */ 100 public static final int DISPLAY_CLIP_VERTICAL = 0x10000000; 101 102 /** Special constant to enable clipping to an overall display along the 103 * horizontal dimension. This is not applied by default by 104 * {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so 105 * yourself by calling {@link #applyDisplay}. 106 */ 107 public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000; 108 109 /** 110 * Apply a gravity constant to an object. 111 * 112 * @param gravity The desired placement of the object, as defined by the 113 * constants in this class. 114 * @param w The horizontal size of the object. 115 * @param h The vertical size of the object. 116 * @param container The frame of the containing space, in which the object 117 * will be placed. Should be large enough to contain the 118 * width and height of the object. 119 * @param outRect Receives the computed frame of the object in its 120 * container. 121 */ 122 public static void apply(int gravity, int w, int h, Rect container, 123 Rect outRect) { 124 apply(gravity, w, h, container, 0, 0, outRect); 125 } 126 127 /** 128 * Apply a gravity constant to an object. 129 * 130 * @param gravity The desired placement of the object, as defined by the 131 * constants in this class. 132 * @param w The horizontal size of the object. 133 * @param h The vertical size of the object. 134 * @param container The frame of the containing space, in which the object 135 * will be placed. Should be large enough to contain the 136 * width and height of the object. 137 * @param xAdj Offset to apply to the X axis. If gravity is LEFT this 138 * pushes it to the right; if gravity is RIGHT it pushes it to 139 * the left; if gravity is CENTER_HORIZONTAL it pushes it to the 140 * right or left; otherwise it is ignored. 141 * @param yAdj Offset to apply to the Y axis. If gravity is TOP this pushes 142 * it down; if gravity is BOTTOM it pushes it up; if gravity is 143 * CENTER_VERTICAL it pushes it down or up; otherwise it is 144 * ignored. 145 * @param outRect Receives the computed frame of the object in its 146 * container. 147 */ 148 public static void apply(int gravity, int w, int h, Rect container, 149 int xAdj, int yAdj, Rect outRect) { 150 switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) { 151 case 0: 152 outRect.left = container.left 153 + ((container.right - container.left - w)/2) + xAdj; 154 outRect.right = outRect.left + w; 155 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 156 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 157 if (outRect.left < container.left) { 158 outRect.left = container.left; 159 } 160 if (outRect.right > container.right) { 161 outRect.right = container.right; 162 } 163 } 164 break; 165 case AXIS_PULL_BEFORE<<AXIS_X_SHIFT: 166 outRect.left = container.left + xAdj; 167 outRect.right = outRect.left + w; 168 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 169 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 170 if (outRect.right > container.right) { 171 outRect.right = container.right; 172 } 173 } 174 break; 175 case AXIS_PULL_AFTER<<AXIS_X_SHIFT: 176 outRect.right = container.right - xAdj; 177 outRect.left = outRect.right - w; 178 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 179 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 180 if (outRect.left < container.left) { 181 outRect.left = container.left; 182 } 183 } 184 break; 185 default: 186 outRect.left = container.left + xAdj; 187 outRect.right = container.right + xAdj; 188 break; 189 } 190 191 switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT)) { 192 case 0: 193 outRect.top = container.top 194 + ((container.bottom - container.top - h)/2) + yAdj; 195 outRect.bottom = outRect.top + h; 196 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 197 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 198 if (outRect.top < container.top) { 199 outRect.top = container.top; 200 } 201 if (outRect.bottom > container.bottom) { 202 outRect.bottom = container.bottom; 203 } 204 } 205 break; 206 case AXIS_PULL_BEFORE<<AXIS_Y_SHIFT: 207 outRect.top = container.top + yAdj; 208 outRect.bottom = outRect.top + h; 209 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 210 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 211 if (outRect.bottom > container.bottom) { 212 outRect.bottom = container.bottom; 213 } 214 } 215 break; 216 case AXIS_PULL_AFTER<<AXIS_Y_SHIFT: 217 outRect.bottom = container.bottom - yAdj; 218 outRect.top = outRect.bottom - h; 219 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 220 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 221 if (outRect.top < container.top) { 222 outRect.top = container.top; 223 } 224 } 225 break; 226 default: 227 outRect.top = container.top + yAdj; 228 outRect.bottom = container.bottom + yAdj; 229 break; 230 } 231 } 232 233 /** 234 * Apply additional gravity behavior based on the overall "display" that an 235 * object exists in. This can be used after 236 * {@link #apply(int, int, int, Rect, int, int, Rect)} to place the object 237 * within a visible display. By default this moves or clips the object 238 * to be visible in the display; the gravity flags 239 * {@link #DISPLAY_CLIP_HORIZONTAL} and {@link #DISPLAY_CLIP_VERTICAL} 240 * can be used to change this behavior. 241 * 242 * @param gravity Gravity constants to modify the placement within the 243 * display. 244 * @param display The rectangle of the display in which the object is 245 * being placed. 246 * @param inoutObj Supplies the current object position; returns with it 247 * modified if needed to fit in the display. 248 */ 249 public static void applyDisplay(int gravity, Rect display, Rect inoutObj) { 250 if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) { 251 if (inoutObj.top < display.top) inoutObj.top = display.top; 252 if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom; 253 } else { 254 int off = 0; 255 if (inoutObj.top < display.top) off = display.top-inoutObj.top; 256 else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom; 257 if (off != 0) { 258 if (inoutObj.height() > (display.bottom-display.top)) { 259 inoutObj.top = display.top; 260 inoutObj.bottom = display.bottom; 261 } else { 262 inoutObj.top += off; 263 inoutObj.bottom += off; 264 } 265 } 266 } 267 268 if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) { 269 if (inoutObj.left < display.left) inoutObj.left = display.left; 270 if (inoutObj.right > display.right) inoutObj.right = display.right; 271 } else { 272 int off = 0; 273 if (inoutObj.left < display.left) off = display.left-inoutObj.left; 274 else if (inoutObj.right > display.right) off = display.right-inoutObj.right; 275 if (off != 0) { 276 if (inoutObj.width() > (display.right-display.left)) { 277 inoutObj.left = display.left; 278 inoutObj.right = display.right; 279 } else { 280 inoutObj.left += off; 281 inoutObj.right += off; 282 } 283 } 284 } 285 } 286 287 /** 288 * <p>Indicate whether the supplied gravity has a vertical pull.</p> 289 * 290 * @param gravity the gravity to check for vertical pull 291 * @return true if the supplied gravity has a vertical pull 292 */ 293 public static boolean isVertical(int gravity) { 294 return gravity > 0 && (gravity & VERTICAL_GRAVITY_MASK) != 0; 295 } 296 297 /** 298 * <p>Indicate whether the supplied gravity has an horizontal pull.</p> 299 * 300 * @param gravity the gravity to check for horizontal pull 301 * @return true if the supplied gravity has an horizontal pull 302 */ 303 public static boolean isHorizontal(int gravity) { 304 return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0; 305 } 306} 307