1/* 2 * Copyright (C) 2015 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.support.percent; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.support.annotation.NonNull; 22import android.support.v4.view.MarginLayoutParamsCompat; 23import android.support.v4.view.ViewCompat; 24import android.util.AttributeSet; 25import android.util.Log; 26import android.view.View; 27import android.view.ViewGroup; 28 29/** 30 * Helper for layouts that want to support percentage based dimensions. 31 * 32 * <p>This class collects utility methods that are involved in extracting percentage based dimension 33 * attributes and applying them to ViewGroup's children. If you would like to implement a layout 34 * that supports percentage based dimensions, you need to take several steps: 35 * 36 * <ol> 37 * <li> You need a {@link ViewGroup.LayoutParams} subclass in your ViewGroup that implements 38 * {@link android.support.percent.PercentLayoutHelper.PercentLayoutParams}. 39 * <li> In your {@code LayoutParams(Context c, AttributeSet attrs)} constructor create an instance 40 * of {@link PercentLayoutHelper.PercentLayoutInfo} by calling 41 * {@link PercentLayoutHelper#getPercentLayoutInfo(Context, AttributeSet)}. Return this 42 * object from {@code public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo()} 43 * method that you implemented for {@link android.support.percent.PercentLayoutHelper.PercentLayoutParams} interface. 44 * <li> Override 45 * {@link ViewGroup.LayoutParams#setBaseAttributes(TypedArray, int, int)} 46 * with a single line implementation {@code PercentLayoutHelper.fetchWidthAndHeight(this, a, 47 * widthAttr, heightAttr);} 48 * <li> In your ViewGroup override {@link ViewGroup#generateLayoutParams(AttributeSet)} to return 49 * your LayoutParams. 50 * <li> In your {@link ViewGroup#onMeasure(int, int)} override, you need to implement following 51 * pattern: 52 * <pre class="prettyprint"> 53 * protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 54 * mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec); 55 * super.onMeasure(widthMeasureSpec, heightMeasureSpec); 56 * if (mHelper.handleMeasuredStateTooSmall()) { 57 * super.onMeasure(widthMeasureSpec, heightMeasureSpec); 58 * } 59 * } 60 * </pre> 61 * <li>In your {@link ViewGroup#onLayout(boolean, int, int, int, int)} override, you need to 62 * implement following pattern: 63 * <pre class="prettyprint"> 64 * protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 65 * super.onLayout(changed, left, top, right, bottom); 66 * mHelper.restoreOriginalParams(); 67 * } 68 * </pre> 69 * </ol> 70 * @deprecated consider using ConstraintLayout and associated layouts instead. The following shows 71 * how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines 72 * are used to define each percentage break point, and then a Button view is stretched to fill 73 * the gap: 74 * 75 * <pre class="prettyprint"> 76 * <android.support.constraint.ConstraintLayout 77 * xmlns:android="http://schemas.android.com/apk/res/android" 78 * xmlns:app="http://schemas.android.com/apk/res-auto" 79 * android:layout_width="match_parent" 80 * android:layout_height="match_parent"> 81 * 82 * <android.support.constraint.Guideline 83 * android:layout_width="wrap_content" 84 * android:layout_height="wrap_content" 85 * android:id="@+id/left_guideline" 86 * app:layout_constraintGuide_percent=".15" 87 * android:orientation="vertical"/> 88 * 89 * <android.support.constraint.Guideline 90 * android:layout_width="wrap_content" 91 * android:layout_height="wrap_content" 92 * android:id="@+id/right_guideline" 93 * app:layout_constraintGuide_percent=".85" 94 * android:orientation="vertical"/> 95 * 96 * <android.support.constraint.Guideline 97 * android:layout_width="wrap_content" 98 * android:layout_height="wrap_content" 99 * android:id="@+id/top_guideline" 100 * app:layout_constraintGuide_percent=".15" 101 * android:orientation="horizontal"/> 102 * 103 * <android.support.constraint.Guideline 104 * android:layout_width="wrap_content" 105 * android:layout_height="wrap_content" 106 * android:id="@+id/bottom_guideline" 107 * app:layout_constraintGuide_percent=".85" 108 * android:orientation="horizontal"/> 109 * 110 * <Button 111 * android:text="Button" 112 * android:layout_width="0dp" 113 * android:layout_height="0dp" 114 * android:id="@+id/button" 115 * app:layout_constraintLeft_toLeftOf="@+id/left_guideline" 116 * app:layout_constraintRight_toRightOf="@+id/right_guideline" 117 * app:layout_constraintTop_toTopOf="@+id/top_guideline" 118 * app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /> 119 * 120 * </android.support.constraint.ConstraintLayout> 121 */ 122@Deprecated 123public class PercentLayoutHelper { 124 private static final String TAG = "PercentLayout"; 125 126 private static final boolean DEBUG = false; 127 private static final boolean VERBOSE = false; 128 129 private final ViewGroup mHost; 130 131 public PercentLayoutHelper(@NonNull ViewGroup host) { 132 if (host == null) { 133 throw new IllegalArgumentException("host must be non-null"); 134 } 135 mHost = host; 136 } 137 138 /** 139 * Helper method to be called from {@link ViewGroup.LayoutParams#setBaseAttributes} override 140 * that reads layout_width and layout_height attribute values without throwing an exception if 141 * they aren't present. 142 */ 143 public static void fetchWidthAndHeight(ViewGroup.LayoutParams params, TypedArray array, 144 int widthAttr, int heightAttr) { 145 params.width = array.getLayoutDimension(widthAttr, 0); 146 params.height = array.getLayoutDimension(heightAttr, 0); 147 } 148 149 /** 150 * Iterates over children and changes their width and height to one calculated from percentage 151 * values. 152 * @param widthMeasureSpec Width MeasureSpec of the parent ViewGroup. 153 * @param heightMeasureSpec Height MeasureSpec of the parent ViewGroup. 154 */ 155 public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) { 156 if (DEBUG) { 157 Log.d(TAG, "adjustChildren: " + mHost + " widthMeasureSpec: " 158 + View.MeasureSpec.toString(widthMeasureSpec) + " heightMeasureSpec: " 159 + View.MeasureSpec.toString(heightMeasureSpec)); 160 } 161 162 // Calculate available space, accounting for host's paddings 163 int widthHint = View.MeasureSpec.getSize(widthMeasureSpec) - mHost.getPaddingLeft() 164 - mHost.getPaddingRight(); 165 int heightHint = View.MeasureSpec.getSize(heightMeasureSpec) - mHost.getPaddingTop() 166 - mHost.getPaddingBottom(); 167 for (int i = 0, N = mHost.getChildCount(); i < N; i++) { 168 View view = mHost.getChildAt(i); 169 ViewGroup.LayoutParams params = view.getLayoutParams(); 170 if (DEBUG) { 171 Log.d(TAG, "should adjust " + view + " " + params); 172 } 173 if (params instanceof PercentLayoutParams) { 174 PercentLayoutInfo info = 175 ((PercentLayoutParams) params).getPercentLayoutInfo(); 176 if (DEBUG) { 177 Log.d(TAG, "using " + info); 178 } 179 if (info != null) { 180 if (params instanceof ViewGroup.MarginLayoutParams) { 181 info.fillMarginLayoutParams(view, (ViewGroup.MarginLayoutParams) params, 182 widthHint, heightHint); 183 } else { 184 info.fillLayoutParams(params, widthHint, heightHint); 185 } 186 } 187 } 188 } 189 } 190 191 /** 192 * Constructs a PercentLayoutInfo from attributes associated with a View. Call this method from 193 * {@code LayoutParams(Context c, AttributeSet attrs)} constructor. 194 */ 195 public static PercentLayoutInfo getPercentLayoutInfo(Context context, 196 AttributeSet attrs) { 197 PercentLayoutInfo info = null; 198 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout); 199 float value = array.getFraction(R.styleable.PercentLayout_Layout_layout_widthPercent, 1, 1, 200 -1f); 201 if (value != -1f) { 202 if (VERBOSE) { 203 Log.v(TAG, "percent width: " + value); 204 } 205 info = info != null ? info : new PercentLayoutInfo(); 206 info.widthPercent = value; 207 } 208 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_heightPercent, 1, 1, -1f); 209 if (value != -1f) { 210 if (VERBOSE) { 211 Log.v(TAG, "percent height: " + value); 212 } 213 info = info != null ? info : new PercentLayoutInfo(); 214 info.heightPercent = value; 215 } 216 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginPercent, 1, 1, -1f); 217 if (value != -1f) { 218 if (VERBOSE) { 219 Log.v(TAG, "percent margin: " + value); 220 } 221 info = info != null ? info : new PercentLayoutInfo(); 222 info.leftMarginPercent = value; 223 info.topMarginPercent = value; 224 info.rightMarginPercent = value; 225 info.bottomMarginPercent = value; 226 } 227 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginLeftPercent, 1, 1, 228 -1f); 229 if (value != -1f) { 230 if (VERBOSE) { 231 Log.v(TAG, "percent left margin: " + value); 232 } 233 info = info != null ? info : new PercentLayoutInfo(); 234 info.leftMarginPercent = value; 235 } 236 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginTopPercent, 1, 1, 237 -1f); 238 if (value != -1f) { 239 if (VERBOSE) { 240 Log.v(TAG, "percent top margin: " + value); 241 } 242 info = info != null ? info : new PercentLayoutInfo(); 243 info.topMarginPercent = value; 244 } 245 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginRightPercent, 1, 1, 246 -1f); 247 if (value != -1f) { 248 if (VERBOSE) { 249 Log.v(TAG, "percent right margin: " + value); 250 } 251 info = info != null ? info : new PercentLayoutInfo(); 252 info.rightMarginPercent = value; 253 } 254 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginBottomPercent, 1, 1, 255 -1f); 256 if (value != -1f) { 257 if (VERBOSE) { 258 Log.v(TAG, "percent bottom margin: " + value); 259 } 260 info = info != null ? info : new PercentLayoutInfo(); 261 info.bottomMarginPercent = value; 262 } 263 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginStartPercent, 1, 1, 264 -1f); 265 if (value != -1f) { 266 if (VERBOSE) { 267 Log.v(TAG, "percent start margin: " + value); 268 } 269 info = info != null ? info : new PercentLayoutInfo(); 270 info.startMarginPercent = value; 271 } 272 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginEndPercent, 1, 1, 273 -1f); 274 if (value != -1f) { 275 if (VERBOSE) { 276 Log.v(TAG, "percent end margin: " + value); 277 } 278 info = info != null ? info : new PercentLayoutInfo(); 279 info.endMarginPercent = value; 280 } 281 282 value = array.getFraction(R.styleable.PercentLayout_Layout_layout_aspectRatio, 1, 1, -1f); 283 if (value != -1f) { 284 if (VERBOSE) { 285 Log.v(TAG, "aspect ratio: " + value); 286 } 287 info = info != null ? info : new PercentLayoutInfo(); 288 info.aspectRatio = value; 289 } 290 291 array.recycle(); 292 if (DEBUG) { 293 Log.d(TAG, "constructed: " + info); 294 } 295 return info; 296 } 297 298 /** 299 * Iterates over children and restores their original dimensions that were changed for 300 * percentage values. Calling this method only makes sense if you previously called 301 * {@link PercentLayoutHelper#adjustChildren(int, int)}. 302 */ 303 public void restoreOriginalParams() { 304 for (int i = 0, N = mHost.getChildCount(); i < N; i++) { 305 View view = mHost.getChildAt(i); 306 ViewGroup.LayoutParams params = view.getLayoutParams(); 307 if (DEBUG) { 308 Log.d(TAG, "should restore " + view + " " + params); 309 } 310 if (params instanceof PercentLayoutParams) { 311 PercentLayoutInfo info = 312 ((PercentLayoutParams) params).getPercentLayoutInfo(); 313 if (DEBUG) { 314 Log.d(TAG, "using " + info); 315 } 316 if (info != null) { 317 if (params instanceof ViewGroup.MarginLayoutParams) { 318 info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params); 319 } else { 320 info.restoreLayoutParams(params); 321 } 322 } 323 } 324 } 325 } 326 327 /** 328 * Iterates over children and checks if any of them would like to get more space than it 329 * received through the percentage dimension. 330 * 331 * If you are building a layout that supports percentage dimensions you are encouraged to take 332 * advantage of this method. The developer should be able to specify that a child should be 333 * remeasured by adding normal dimension attribute with {@code wrap_content} value. For example 334 * he might specify child's attributes as {@code app:layout_widthPercent="60%p"} and 335 * {@code android:layout_width="wrap_content"}. In this case if the child receives too little 336 * space, it will be remeasured with width set to {@code WRAP_CONTENT}. 337 * 338 * @return True if the measure phase needs to be rerun because one of the children would like 339 * to receive more space. 340 */ 341 public boolean handleMeasuredStateTooSmall() { 342 boolean needsSecondMeasure = false; 343 for (int i = 0, N = mHost.getChildCount(); i < N; i++) { 344 View view = mHost.getChildAt(i); 345 ViewGroup.LayoutParams params = view.getLayoutParams(); 346 if (DEBUG) { 347 Log.d(TAG, "should handle measured state too small " + view + " " + params); 348 } 349 if (params instanceof PercentLayoutParams) { 350 PercentLayoutInfo info = 351 ((PercentLayoutParams) params).getPercentLayoutInfo(); 352 if (info != null) { 353 if (shouldHandleMeasuredWidthTooSmall(view, info)) { 354 needsSecondMeasure = true; 355 params.width = ViewGroup.LayoutParams.WRAP_CONTENT; 356 } 357 if (shouldHandleMeasuredHeightTooSmall(view, info)) { 358 needsSecondMeasure = true; 359 params.height = ViewGroup.LayoutParams.WRAP_CONTENT; 360 } 361 } 362 } 363 } 364 if (DEBUG) { 365 Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure); 366 } 367 return needsSecondMeasure; 368 } 369 370 private static boolean shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info) { 371 int state = view.getMeasuredWidthAndState() & View.MEASURED_STATE_MASK; 372 return state == View.MEASURED_STATE_TOO_SMALL && info.widthPercent >= 0 373 && info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT; 374 } 375 376 private static boolean shouldHandleMeasuredHeightTooSmall(View view, PercentLayoutInfo info) { 377 int state = view.getMeasuredHeightAndState() & View.MEASURED_STATE_MASK; 378 return state == View.MEASURED_STATE_TOO_SMALL && info.heightPercent >= 0 379 && info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT; 380 } 381 382 /* package */ static class PercentMarginLayoutParams extends ViewGroup.MarginLayoutParams { 383 // These two flags keep track of whether we're computing the LayoutParams width and height 384 // in the fill pass based on the aspect ratio. This allows the fill pass to be re-entrant 385 // as the framework code can call onMeasure() multiple times before the onLayout() is 386 // called. Those multiple invocations of onMeasure() are not guaranteed to be called with 387 // the same set of width / height. 388 private boolean mIsHeightComputedFromAspectRatio; 389 private boolean mIsWidthComputedFromAspectRatio; 390 391 public PercentMarginLayoutParams(int width, int height) { 392 super(width, height); 393 } 394 } 395 396 /** 397 * Container for information about percentage dimensions and margins. It acts as an extension 398 * for {@code LayoutParams}. 399 * 400 * @deprecated use ConstraintLayout and Guidelines for layout support. 401 */ 402 @Deprecated 403 public static class PercentLayoutInfo { 404 /** The decimal value of the percentage-based width. */ 405 public float widthPercent; 406 407 /** The decimal value of the percentage-based height. */ 408 public float heightPercent; 409 410 /** The decimal value of the percentage-based left margin. */ 411 public float leftMarginPercent; 412 413 /** The decimal value of the percentage-based top margin. */ 414 public float topMarginPercent; 415 416 /** The decimal value of the percentage-based right margin. */ 417 public float rightMarginPercent; 418 419 /** The decimal value of the percentage-based bottom margin. */ 420 public float bottomMarginPercent; 421 422 /** The decimal value of the percentage-based start margin. */ 423 public float startMarginPercent; 424 425 /** The decimal value of the percentage-based end margin. */ 426 public float endMarginPercent; 427 428 /** The decimal value of the percentage-based aspect ratio. */ 429 public float aspectRatio; 430 431 /* package */ final PercentMarginLayoutParams mPreservedParams; 432 433 public PercentLayoutInfo() { 434 widthPercent = -1f; 435 heightPercent = -1f; 436 leftMarginPercent = -1f; 437 topMarginPercent = -1f; 438 rightMarginPercent = -1f; 439 bottomMarginPercent = -1f; 440 startMarginPercent = -1f; 441 endMarginPercent = -1f; 442 mPreservedParams = new PercentMarginLayoutParams(0, 0); 443 } 444 445 /** 446 * Fills the {@link ViewGroup.LayoutParams#width} and {@link ViewGroup.LayoutParams#height} 447 * fields of the passed {@link ViewGroup.LayoutParams} object based on currently set 448 * percentage values. 449 */ 450 public void fillLayoutParams(ViewGroup.LayoutParams params, int widthHint, 451 int heightHint) { 452 // Preserve the original layout params, so we can restore them after the measure step. 453 mPreservedParams.width = params.width; 454 mPreservedParams.height = params.height; 455 456 // We assume that width/height set to 0 means that value was unset. This might not 457 // necessarily be true, as the user might explicitly set it to 0. However, we use this 458 // information only for the aspect ratio. If the user set the aspect ratio attribute, 459 // it means they accept or soon discover that it will be disregarded. 460 final boolean widthNotSet = 461 (mPreservedParams.mIsWidthComputedFromAspectRatio 462 || mPreservedParams.width == 0) && (widthPercent < 0); 463 final boolean heightNotSet = 464 (mPreservedParams.mIsHeightComputedFromAspectRatio 465 || mPreservedParams.height == 0) && (heightPercent < 0); 466 467 if (widthPercent >= 0) { 468 params.width = Math.round(widthHint * widthPercent); 469 } 470 471 if (heightPercent >= 0) { 472 params.height = Math.round(heightHint * heightPercent); 473 } 474 475 if (aspectRatio >= 0) { 476 if (widthNotSet) { 477 params.width = Math.round(params.height * aspectRatio); 478 // Keep track that we've filled the width based on the height and aspect ratio. 479 mPreservedParams.mIsWidthComputedFromAspectRatio = true; 480 } 481 if (heightNotSet) { 482 params.height = Math.round(params.width / aspectRatio); 483 // Keep track that we've filled the height based on the width and aspect ratio. 484 mPreservedParams.mIsHeightComputedFromAspectRatio = true; 485 } 486 } 487 488 if (DEBUG) { 489 Log.d(TAG, "after fillLayoutParams: (" + params.width + ", " + params.height + ")"); 490 } 491 } 492 493 /** 494 * @deprecated Use 495 * {@link #fillMarginLayoutParams(View, ViewGroup.MarginLayoutParams, int, int)} 496 * for proper RTL support. 497 */ 498 @Deprecated 499 public void fillMarginLayoutParams(ViewGroup.MarginLayoutParams params, 500 int widthHint, int heightHint) { 501 fillMarginLayoutParams(null, params, widthHint, heightHint); 502 } 503 504 /** 505 * Fills the margin fields of the passed {@link ViewGroup.MarginLayoutParams} object based 506 * on currently set percentage values and the current layout direction of the passed 507 * {@link View}. 508 */ 509 public void fillMarginLayoutParams(View view, ViewGroup.MarginLayoutParams params, 510 int widthHint, int heightHint) { 511 fillLayoutParams(params, widthHint, heightHint); 512 513 // Preserve the original margins, so we can restore them after the measure step. 514 mPreservedParams.leftMargin = params.leftMargin; 515 mPreservedParams.topMargin = params.topMargin; 516 mPreservedParams.rightMargin = params.rightMargin; 517 mPreservedParams.bottomMargin = params.bottomMargin; 518 MarginLayoutParamsCompat.setMarginStart(mPreservedParams, 519 MarginLayoutParamsCompat.getMarginStart(params)); 520 MarginLayoutParamsCompat.setMarginEnd(mPreservedParams, 521 MarginLayoutParamsCompat.getMarginEnd(params)); 522 523 if (leftMarginPercent >= 0) { 524 params.leftMargin = Math.round(widthHint * leftMarginPercent); 525 } 526 if (topMarginPercent >= 0) { 527 params.topMargin = Math.round(heightHint * topMarginPercent); 528 } 529 if (rightMarginPercent >= 0) { 530 params.rightMargin = Math.round(widthHint * rightMarginPercent); 531 } 532 if (bottomMarginPercent >= 0) { 533 params.bottomMargin = Math.round(heightHint * bottomMarginPercent); 534 } 535 boolean shouldResolveLayoutDirection = false; 536 if (startMarginPercent >= 0) { 537 MarginLayoutParamsCompat.setMarginStart(params, 538 Math.round(widthHint * startMarginPercent)); 539 shouldResolveLayoutDirection = true; 540 } 541 if (endMarginPercent >= 0) { 542 MarginLayoutParamsCompat.setMarginEnd(params, 543 Math.round(widthHint * endMarginPercent)); 544 shouldResolveLayoutDirection = true; 545 } 546 if (shouldResolveLayoutDirection && (view != null)) { 547 // Force the resolve pass so that start / end margins are propagated to the 548 // matching left / right fields 549 MarginLayoutParamsCompat.resolveLayoutDirection(params, 550 ViewCompat.getLayoutDirection(view)); 551 } 552 if (DEBUG) { 553 Log.d(TAG, "after fillMarginLayoutParams: (" + params.width + ", " + params.height 554 + ")"); 555 } 556 } 557 558 @Override 559 public String toString() { 560 return String.format("PercentLayoutInformation width: %f height %f, margins (%f, %f, " 561 + " %f, %f, %f, %f)", widthPercent, heightPercent, leftMarginPercent, 562 topMarginPercent, rightMarginPercent, bottomMarginPercent, startMarginPercent, 563 endMarginPercent); 564 565 } 566 567 /** 568 * Restores the original dimensions and margins after they were changed for percentage based 569 * values. You should call this method only if you previously called 570 * {@link PercentLayoutHelper.PercentLayoutInfo#fillMarginLayoutParams(View, ViewGroup.MarginLayoutParams, int, int)}. 571 */ 572 public void restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params) { 573 restoreLayoutParams(params); 574 params.leftMargin = mPreservedParams.leftMargin; 575 params.topMargin = mPreservedParams.topMargin; 576 params.rightMargin = mPreservedParams.rightMargin; 577 params.bottomMargin = mPreservedParams.bottomMargin; 578 MarginLayoutParamsCompat.setMarginStart(params, 579 MarginLayoutParamsCompat.getMarginStart(mPreservedParams)); 580 MarginLayoutParamsCompat.setMarginEnd(params, 581 MarginLayoutParamsCompat.getMarginEnd(mPreservedParams)); 582 } 583 584 /** 585 * Restores original dimensions after they were changed for percentage based values. 586 * You should call this method only if you previously called 587 * {@link PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams(ViewGroup.LayoutParams, int, int)}. 588 */ 589 public void restoreLayoutParams(ViewGroup.LayoutParams params) { 590 if (!mPreservedParams.mIsWidthComputedFromAspectRatio) { 591 // Only restore the width if we didn't compute it based on the height and 592 // aspect ratio in the fill pass. 593 params.width = mPreservedParams.width; 594 } 595 if (!mPreservedParams.mIsHeightComputedFromAspectRatio) { 596 // Only restore the height if we didn't compute it based on the width and 597 // aspect ratio in the fill pass. 598 params.height = mPreservedParams.height; 599 } 600 601 // Reset the tracking flags. 602 mPreservedParams.mIsWidthComputedFromAspectRatio = false; 603 mPreservedParams.mIsHeightComputedFromAspectRatio = false; 604 } 605 } 606 607 /** 608 * If a layout wants to support percentage based dimensions and use this helper class, its 609 * {@code LayoutParams} subclass must implement this interface. 610 * 611 * Your {@code LayoutParams} subclass should contain an instance of {@code PercentLayoutInfo} 612 * and the implementation of this interface should be a simple accessor. 613 * 614 * @deprecated this class is deprecated along with its parent class. 615 */ 616 @Deprecated 617 public interface PercentLayoutParams { 618 PercentLayoutInfo getPercentLayoutInfo(); 619 } 620} 621