1 /* 2 * Copyright (C) 2019 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 androidx.constraintlayout.core.widgets.analyzer; 18 19 import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.FIXED; 20 import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT; 21 import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.MATCH_PARENT; 22 import static androidx.constraintlayout.core.widgets.ConstraintWidget.HORIZONTAL; 23 import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_PERCENT; 24 import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_RATIO; 25 import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_SPREAD; 26 import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_WRAP; 27 import static androidx.constraintlayout.core.widgets.ConstraintWidget.UNKNOWN; 28 import static androidx.constraintlayout.core.widgets.ConstraintWidget.VERTICAL; 29 import static androidx.constraintlayout.core.widgets.analyzer.WidgetRun.RunType.CENTER; 30 31 import androidx.constraintlayout.core.widgets.ConstraintAnchor; 32 import androidx.constraintlayout.core.widgets.ConstraintWidget; 33 import androidx.constraintlayout.core.widgets.Helper; 34 35 public class HorizontalWidgetRun extends WidgetRun { 36 37 private static int[] sTempDimensions = new int[2]; 38 HorizontalWidgetRun(ConstraintWidget widget)39 public HorizontalWidgetRun(ConstraintWidget widget) { 40 super(widget); 41 start.mType = DependencyNode.Type.LEFT; 42 end.mType = DependencyNode.Type.RIGHT; 43 this.orientation = HORIZONTAL; 44 } 45 46 @Override toString()47 public String toString() { 48 return "HorizontalRun " + mWidget.getDebugName(); 49 } 50 51 @Override clear()52 void clear() { 53 mRunGroup = null; 54 start.clear(); 55 end.clear(); 56 mDimension.clear(); 57 mResolved = false; 58 } 59 60 @Override reset()61 void reset() { 62 mResolved = false; 63 start.clear(); 64 start.resolved = false; 65 end.clear(); 66 end.resolved = false; 67 mDimension.resolved = false; 68 } 69 70 @Override supportsWrapComputation()71 boolean supportsWrapComputation() { 72 if (super.mDimensionBehavior == ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT) { 73 if (super.mWidget.mMatchConstraintDefaultWidth == MATCH_CONSTRAINT_SPREAD) { 74 return true; 75 } 76 return false; 77 } 78 return true; 79 } 80 81 @Override apply()82 void apply() { 83 if (mWidget.measured) { 84 mDimension.resolve(mWidget.getWidth()); 85 } 86 if (!mDimension.resolved) { 87 super.mDimensionBehavior = mWidget.getHorizontalDimensionBehaviour(); 88 if (super.mDimensionBehavior != ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT) { 89 if (mDimensionBehavior == MATCH_PARENT) { 90 ConstraintWidget parent = mWidget.getParent(); 91 if (parent != null 92 && (parent.getHorizontalDimensionBehaviour() == FIXED 93 || parent.getHorizontalDimensionBehaviour() == MATCH_PARENT)) { 94 int resolvedDimension = parent.getWidth() 95 - mWidget.mLeft.getMargin() - mWidget.mRight.getMargin(); 96 addTarget(start, parent.mHorizontalRun.start, mWidget.mLeft.getMargin()); 97 addTarget(end, parent.mHorizontalRun.end, -mWidget.mRight.getMargin()); 98 mDimension.resolve(resolvedDimension); 99 return; 100 } 101 } 102 if (mDimensionBehavior == FIXED) { 103 mDimension.resolve(mWidget.getWidth()); 104 } 105 } 106 } else { 107 if (mDimensionBehavior == MATCH_PARENT) { 108 ConstraintWidget parent = mWidget.getParent(); 109 if (parent != null 110 && (parent.getHorizontalDimensionBehaviour() == FIXED 111 || parent.getHorizontalDimensionBehaviour() == MATCH_PARENT)) { 112 addTarget(start, parent.mHorizontalRun.start, mWidget.mLeft.getMargin()); 113 addTarget(end, parent.mHorizontalRun.end, -mWidget.mRight.getMargin()); 114 return; 115 } 116 } 117 } 118 119 // three basic possibilities: 120 // <-s-e-> 121 // <-s-e 122 // s-e-> 123 // and a variation if the dimension is not yet known: 124 // <-s-d-e-> 125 // <-s<-d<-e 126 // s->d->e-> 127 128 if (mDimension.resolved && mWidget.measured) { 129 if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].mTarget != null 130 && mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].mTarget 131 != null) { // <-s-e-> 132 if (mWidget.isInHorizontalChain()) { 133 start.mMargin = mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin(); 134 end.mMargin = -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].getMargin(); 135 } else { 136 DependencyNode startTarget = 137 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT]); 138 if (startTarget != null) { 139 addTarget(start, startTarget, 140 mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin()); 141 } 142 DependencyNode endTarget = 143 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT]); 144 if (endTarget != null) { 145 addTarget(end, endTarget, 146 -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].getMargin()); 147 } 148 start.delegateToWidgetRun = true; 149 end.delegateToWidgetRun = true; 150 } 151 } else if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].mTarget 152 != null) { // <-s-e 153 DependencyNode target = 154 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT]); 155 if (target != null) { 156 addTarget(start, target, 157 mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin()); 158 addTarget(end, start, mDimension.value); 159 } 160 } else if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].mTarget 161 != null) { // s-e-> 162 DependencyNode target = 163 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT]); 164 if (target != null) { 165 addTarget(end, target, 166 -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].getMargin()); 167 addTarget(start, end, -mDimension.value); 168 } 169 } else { 170 // no connections, nothing to do. 171 if (!(mWidget instanceof Helper) && mWidget.getParent() != null 172 && mWidget.getAnchor(ConstraintAnchor.Type.CENTER).mTarget == null) { 173 DependencyNode left = mWidget.getParent().mHorizontalRun.start; 174 addTarget(start, left, mWidget.getX()); 175 addTarget(end, start, mDimension.value); 176 } 177 } 178 } else { 179 if (mDimensionBehavior == MATCH_CONSTRAINT) { 180 switch (mWidget.mMatchConstraintDefaultWidth) { 181 case MATCH_CONSTRAINT_RATIO: { 182 if (mWidget.mMatchConstraintDefaultHeight == MATCH_CONSTRAINT_RATIO 183 ) { 184 // need to look into both side 185 start.updateDelegate = this; 186 end.updateDelegate = this; 187 mWidget.mVerticalRun.start.updateDelegate = this; 188 mWidget.mVerticalRun.end.updateDelegate = this; 189 mDimension.updateDelegate = this; 190 191 if (mWidget.isInVerticalChain()) { 192 mDimension.mTargets.add(mWidget.mVerticalRun.mDimension); 193 mWidget.mVerticalRun.mDimension.mDependencies.add(mDimension); 194 mWidget.mVerticalRun.mDimension.updateDelegate = this; 195 mDimension.mTargets.add(mWidget.mVerticalRun.start); 196 mDimension.mTargets.add(mWidget.mVerticalRun.end); 197 mWidget.mVerticalRun.start.mDependencies.add(mDimension); 198 mWidget.mVerticalRun.end.mDependencies.add(mDimension); 199 } else if (mWidget.isInHorizontalChain()) { 200 mWidget.mVerticalRun.mDimension.mTargets.add(mDimension); 201 mDimension.mDependencies.add(mWidget.mVerticalRun.mDimension); 202 } else { 203 mWidget.mVerticalRun.mDimension.mTargets.add(mDimension); 204 } 205 break; 206 } 207 // we have a ratio, but we depend on the other side computation 208 DependencyNode targetDimension = mWidget.mVerticalRun.mDimension; 209 mDimension.mTargets.add(targetDimension); 210 targetDimension.mDependencies.add(mDimension); 211 mWidget.mVerticalRun.start.mDependencies.add(mDimension); 212 mWidget.mVerticalRun.end.mDependencies.add(mDimension); 213 mDimension.delegateToWidgetRun = true; 214 mDimension.mDependencies.add(start); 215 mDimension.mDependencies.add(end); 216 start.mTargets.add(mDimension); 217 end.mTargets.add(mDimension); 218 } 219 break; 220 case MATCH_CONSTRAINT_PERCENT: { 221 // we need to look up the parent dimension 222 ConstraintWidget parent = mWidget.getParent(); 223 if (parent == null) { 224 break; 225 } 226 DependencyNode targetDimension = parent.mVerticalRun.mDimension; 227 mDimension.mTargets.add(targetDimension); 228 targetDimension.mDependencies.add(mDimension); 229 mDimension.delegateToWidgetRun = true; 230 mDimension.mDependencies.add(start); 231 mDimension.mDependencies.add(end); 232 } 233 break; 234 case MATCH_CONSTRAINT_SPREAD: { 235 // the work is done in the update() 236 } 237 break; 238 default: 239 break; 240 } 241 } 242 if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].mTarget != null 243 && mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].mTarget 244 != null) { // <-s-d-e-> 245 246 if (mWidget.isInHorizontalChain()) { 247 start.mMargin = mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin(); 248 end.mMargin = -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].getMargin(); 249 } else { 250 DependencyNode startTarget = 251 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT]); 252 DependencyNode endTarget = 253 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT]); 254 if (false) { 255 if (startTarget != null) { 256 addTarget(start, startTarget, 257 mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin()); 258 } 259 if (endTarget != null) { 260 addTarget(end, endTarget, 261 -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT] 262 .getMargin()); 263 } 264 } else { 265 if (startTarget != null) { 266 startTarget.addDependency(this); 267 } 268 if (endTarget != null) { 269 endTarget.addDependency(this); 270 } 271 } 272 mRunType = CENTER; 273 } 274 } else if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].mTarget 275 != null) { // <-s<-d<-e 276 DependencyNode target = 277 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT]); 278 if (target != null) { 279 addTarget(start, target, 280 mWidget.mListAnchors[ConstraintWidget.ANCHOR_LEFT].getMargin()); 281 addTarget(end, start, 1, mDimension); 282 } 283 } else if (mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].mTarget 284 != null) { // s->d->e-> 285 DependencyNode target = 286 getTarget(mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT]); 287 if (target != null) { 288 addTarget(end, target, 289 -mWidget.mListAnchors[ConstraintWidget.ANCHOR_RIGHT].getMargin()); 290 addTarget(start, end, -1, mDimension); 291 } 292 } else { 293 // no connections, nothing to do. 294 if (!(mWidget instanceof Helper) && mWidget.getParent() != null) { 295 DependencyNode left = mWidget.getParent().mHorizontalRun.start; 296 addTarget(start, left, mWidget.getX()); 297 addTarget(end, start, 1, mDimension); 298 } 299 } 300 } 301 } 302 computeInsetRatio(int[] dimensions, int x1, int x2, int y1, int y2, float ratio, int side)303 private void computeInsetRatio(int[] dimensions, 304 int x1, 305 int x2, 306 int y1, 307 int y2, 308 float ratio, 309 int side) { 310 int dx = x2 - x1; 311 int dy = y2 - y1; 312 switch (side) { 313 case UNKNOWN: { 314 int candidateX1 = (int) (0.5f + dy * ratio); 315 int candidateY1 = dy; 316 int candidateX2 = dx; 317 int candidateY2 = (int) (0.5f + dx / ratio); 318 if (candidateX1 <= dx && candidateY1 <= dy) { 319 dimensions[HORIZONTAL] = candidateX1; 320 dimensions[VERTICAL] = candidateY1; 321 } else if (candidateX2 <= dx && candidateY2 <= dy) { 322 dimensions[HORIZONTAL] = candidateX2; 323 dimensions[VERTICAL] = candidateY2; 324 } 325 } 326 break; 327 case HORIZONTAL: { 328 int horizontalSide = (int) (0.5f + dy * ratio); 329 dimensions[HORIZONTAL] = horizontalSide; 330 dimensions[VERTICAL] = dy; 331 } 332 break; 333 case VERTICAL: { 334 int verticalSide = (int) (0.5f + dx * ratio); 335 dimensions[HORIZONTAL] = dx; 336 dimensions[VERTICAL] = verticalSide; 337 } 338 break; 339 default: 340 break; 341 } 342 } 343 344 @Override update(Dependency dependency)345 public void update(Dependency dependency) { 346 switch (mRunType) { 347 case START: { 348 updateRunStart(dependency); 349 } 350 break; 351 case END: { 352 updateRunEnd(dependency); 353 } 354 break; 355 case CENTER: { 356 updateRunCenter(dependency, mWidget.mLeft, mWidget.mRight, HORIZONTAL); 357 return; 358 } 359 default: 360 break; 361 } 362 363 if (!mDimension.resolved) { 364 if (mDimensionBehavior == MATCH_CONSTRAINT) { 365 switch (mWidget.mMatchConstraintDefaultWidth) { 366 case MATCH_CONSTRAINT_RATIO: { 367 if (mWidget.mMatchConstraintDefaultHeight == MATCH_CONSTRAINT_SPREAD 368 || mWidget.mMatchConstraintDefaultHeight 369 == MATCH_CONSTRAINT_RATIO) { 370 DependencyNode secondStart = mWidget.mVerticalRun.start; 371 DependencyNode secondEnd = mWidget.mVerticalRun.end; 372 boolean s1 = mWidget.mLeft.mTarget != null; 373 boolean s2 = mWidget.mTop.mTarget != null; 374 boolean e1 = mWidget.mRight.mTarget != null; 375 boolean e2 = mWidget.mBottom.mTarget != null; 376 377 int definedSide = mWidget.getDimensionRatioSide(); 378 379 if (s1 && s2 && e1 && e2) { 380 float ratio = mWidget.getDimensionRatio(); 381 if (secondStart.resolved && secondEnd.resolved) { 382 if (!(start.readyToSolve && end.readyToSolve)) { 383 return; 384 } 385 int x1 = start.mTargets.get(0).value + start.mMargin; 386 int x2 = end.mTargets.get(0).value - end.mMargin; 387 int y1 = secondStart.value + secondStart.mMargin; 388 int y2 = secondEnd.value - secondEnd.mMargin; 389 computeInsetRatio(sTempDimensions, 390 x1, x2, y1, y2, ratio, definedSide); 391 mDimension.resolve(sTempDimensions[HORIZONTAL]); 392 mWidget.mVerticalRun.mDimension 393 .resolve(sTempDimensions[VERTICAL]); 394 return; 395 } 396 if (start.resolved && end.resolved) { 397 if (!(secondStart.readyToSolve && secondEnd.readyToSolve)) { 398 return; 399 } 400 int x1 = start.value + start.mMargin; 401 int x2 = end.value - end.mMargin; 402 int y1 = secondStart.mTargets.get(0).value 403 + secondStart.mMargin; 404 int y2 = secondEnd.mTargets.get(0).value - secondEnd.mMargin; 405 computeInsetRatio(sTempDimensions, 406 x1, x2, y1, y2, ratio, definedSide); 407 mDimension.resolve(sTempDimensions[HORIZONTAL]); 408 mWidget.mVerticalRun.mDimension 409 .resolve(sTempDimensions[VERTICAL]); 410 } 411 if (!(start.readyToSolve && end.readyToSolve 412 && secondStart.readyToSolve 413 && secondEnd.readyToSolve)) { 414 return; 415 } 416 int x1 = start.mTargets.get(0).value + start.mMargin; 417 int x2 = end.mTargets.get(0).value - end.mMargin; 418 int y1 = secondStart.mTargets.get(0).value + secondStart.mMargin; 419 int y2 = secondEnd.mTargets.get(0).value - secondEnd.mMargin; 420 computeInsetRatio(sTempDimensions, 421 x1, x2, y1, y2, ratio, definedSide); 422 mDimension.resolve(sTempDimensions[HORIZONTAL]); 423 mWidget.mVerticalRun.mDimension.resolve(sTempDimensions[VERTICAL]); 424 } else if (s1 && e1) { 425 if (!(start.readyToSolve && end.readyToSolve)) { 426 return; 427 } 428 float ratio = mWidget.getDimensionRatio(); 429 int x1 = start.mTargets.get(0).value + start.mMargin; 430 int x2 = end.mTargets.get(0).value - end.mMargin; 431 432 switch (definedSide) { 433 case UNKNOWN: 434 case HORIZONTAL: { 435 int dx = x2 - x1; 436 int ldx = getLimitedDimension(dx, HORIZONTAL); 437 int dy = (int) (0.5f + ldx * ratio); 438 int ldy = getLimitedDimension(dy, VERTICAL); 439 if (dy != ldy) { 440 ldx = (int) (0.5f + ldy / ratio); 441 } 442 mDimension.resolve(ldx); 443 mWidget.mVerticalRun.mDimension.resolve(ldy); 444 } 445 break; 446 case VERTICAL: { 447 int dx = x2 - x1; 448 int ldx = getLimitedDimension(dx, HORIZONTAL); 449 int dy = (int) (0.5f + ldx / ratio); 450 int ldy = getLimitedDimension(dy, VERTICAL); 451 if (dy != ldy) { 452 ldx = (int) (0.5f + ldy * ratio); 453 } 454 mDimension.resolve(ldx); 455 mWidget.mVerticalRun.mDimension.resolve(ldy); 456 } 457 break; 458 default: 459 break; 460 } 461 } else if (s2 && e2) { 462 if (!(secondStart.readyToSolve && secondEnd.readyToSolve)) { 463 return; 464 } 465 float ratio = mWidget.getDimensionRatio(); 466 int y1 = secondStart.mTargets.get(0).value + secondStart.mMargin; 467 int y2 = secondEnd.mTargets.get(0).value - secondEnd.mMargin; 468 469 switch (definedSide) { 470 case UNKNOWN: 471 case VERTICAL: { 472 int dy = y2 - y1; 473 int ldy = getLimitedDimension(dy, VERTICAL); 474 int dx = (int) (0.5f + ldy / ratio); 475 int ldx = getLimitedDimension(dx, HORIZONTAL); 476 if (dx != ldx) { 477 ldy = (int) (0.5f + ldx * ratio); 478 } 479 mDimension.resolve(ldx); 480 mWidget.mVerticalRun.mDimension.resolve(ldy); 481 } 482 break; 483 case HORIZONTAL: { 484 int dy = y2 - y1; 485 int ldy = getLimitedDimension(dy, VERTICAL); 486 int dx = (int) (0.5f + ldy * ratio); 487 int ldx = getLimitedDimension(dx, HORIZONTAL); 488 if (dx != ldx) { 489 ldy = (int) (0.5f + ldx / ratio); 490 } 491 mDimension.resolve(ldx); 492 mWidget.mVerticalRun.mDimension.resolve(ldy); 493 } 494 break; 495 default: 496 break; 497 } 498 } 499 } else { 500 int size = 0; 501 int ratioSide = mWidget.getDimensionRatioSide(); 502 switch (ratioSide) { 503 case HORIZONTAL: { 504 size = (int) (0.5f + mWidget.mVerticalRun.mDimension.value 505 / mWidget.getDimensionRatio()); 506 } 507 break; 508 case ConstraintWidget.VERTICAL: { 509 size = (int) (0.5f + mWidget.mVerticalRun.mDimension.value 510 * mWidget.getDimensionRatio()); 511 } 512 break; 513 case ConstraintWidget.UNKNOWN: { 514 size = (int) (0.5f + mWidget.mVerticalRun.mDimension.value 515 * mWidget.getDimensionRatio()); 516 } 517 break; 518 default: 519 break; 520 } 521 mDimension.resolve(size); 522 } 523 } 524 break; 525 case MATCH_CONSTRAINT_PERCENT: { 526 ConstraintWidget parent = mWidget.getParent(); 527 if (parent != null) { 528 if (parent.mHorizontalRun.mDimension.resolved) { 529 float percent = mWidget.mMatchConstraintPercentWidth; 530 int targetDimensionValue = parent.mHorizontalRun.mDimension.value; 531 int size = (int) (0.5f + targetDimensionValue * percent); 532 mDimension.resolve(size); 533 } 534 } 535 } 536 break; 537 default: 538 break; 539 } 540 } 541 } 542 543 if (!(start.readyToSolve && end.readyToSolve)) { 544 return; 545 } 546 547 if (start.resolved && end.resolved && mDimension.resolved) { 548 return; 549 } 550 551 if (!mDimension.resolved 552 && mDimensionBehavior == MATCH_CONSTRAINT 553 && mWidget.mMatchConstraintDefaultWidth == MATCH_CONSTRAINT_SPREAD 554 && !mWidget.isInHorizontalChain()) { 555 556 DependencyNode startTarget = start.mTargets.get(0); 557 DependencyNode endTarget = end.mTargets.get(0); 558 int startPos = startTarget.value + start.mMargin; 559 int endPos = endTarget.value + end.mMargin; 560 561 int distance = endPos - startPos; 562 start.resolve(startPos); 563 end.resolve(endPos); 564 mDimension.resolve(distance); 565 return; 566 } 567 568 if (!mDimension.resolved 569 && mDimensionBehavior == MATCH_CONSTRAINT 570 && matchConstraintsType == MATCH_CONSTRAINT_WRAP) { 571 if (start.mTargets.size() > 0 && end.mTargets.size() > 0) { 572 DependencyNode startTarget = start.mTargets.get(0); 573 DependencyNode endTarget = end.mTargets.get(0); 574 int startPos = startTarget.value + start.mMargin; 575 int endPos = endTarget.value + end.mMargin; 576 int availableSpace = endPos - startPos; 577 int value = Math.min(availableSpace, mDimension.wrapValue); 578 int max = mWidget.mMatchConstraintMaxWidth; 579 int min = mWidget.mMatchConstraintMinWidth; 580 value = Math.max(min, value); 581 if (max > 0) { 582 value = Math.min(max, value); 583 } 584 mDimension.resolve(value); 585 } 586 } 587 588 if (!mDimension.resolved) { 589 return; 590 } 591 // ready to solve, centering. 592 DependencyNode startTarget = start.mTargets.get(0); 593 DependencyNode endTarget = end.mTargets.get(0); 594 int startPos = startTarget.value + start.mMargin; 595 int endPos = endTarget.value + end.mMargin; 596 float bias = mWidget.getHorizontalBiasPercent(); 597 if (startTarget == endTarget) { 598 startPos = startTarget.value; 599 endPos = endTarget.value; 600 // TODO: this might be a nice feature to support, but I guess for now let's stay 601 // compatible with 1.1 602 bias = 0.5f; 603 } 604 int distance = (endPos - startPos - mDimension.value); 605 start.resolve((int) (0.5f + startPos + distance * bias)); 606 end.resolve(start.value + mDimension.value); 607 } 608 609 // @TODO: add description 610 @Override applyToWidget()611 public void applyToWidget() { 612 if (start.resolved) { 613 mWidget.setX(start.value); 614 } 615 } 616 617 } 618