public abstract class

WidgetRun

extends java.lang.Object

implements Dependency

 java.lang.Object

↳androidx.constraintlayout.core.widgets.analyzer.WidgetRun

Subclasses:

VerticalWidgetRun, HorizontalWidgetRun, ChainRun

Gradle dependencies

compile group: 'androidx.constraintlayout', name: 'constraintlayout-core', version: '1.1.0-alpha01'

  • groupId: androidx.constraintlayout
  • artifactId: constraintlayout-core
  • version: 1.1.0-alpha01

Artifact androidx.constraintlayout:constraintlayout-core:1.1.0-alpha01 it located at Google repository (https://maven.google.com/)

Summary

Fields
public DependencyNodeend

public intmatchConstraintsType

protected ConstraintWidget.DimensionBehaviourmDimensionBehavior

protected androidx.constraintlayout.core.widgets.analyzer.WidgetRun.RunTypemRunType

public intorientation

public DependencyNodestart

Constructors
publicWidgetRun(ConstraintWidget widget)

Methods
protected final voidaddTarget(DependencyNode node, DependencyNode target, int margin)

protected final voidaddTarget(DependencyNode node, DependencyNode target, int marginFactor, androidx.constraintlayout.core.widgets.analyzer.DimensionDependency dimensionDependency)

protected final intgetLimitedDimension(int dimension, int orientation)

protected final DependencyNodegetTarget(ConstraintAnchor anchor)

protected final DependencyNodegetTarget(ConstraintAnchor anchor, int orientation)

public longgetWrapDimension()

public booleanisCenterConnection()

public booleanisDimensionResolved()

public booleanisResolved()

public voidupdate(Dependency dependency)

protected voidupdateRunCenter(Dependency dependency, ConstraintAnchor startAnchor, ConstraintAnchor endAnchor, int orientation)

protected voidupdateRunEnd(Dependency dependency)

protected voidupdateRunStart(Dependency dependency)

public longwrapSize(int direction)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public int matchConstraintsType

protected ConstraintWidget.DimensionBehaviour mDimensionBehavior

public int orientation

public DependencyNode start

public DependencyNode end

protected androidx.constraintlayout.core.widgets.analyzer.WidgetRun.RunType mRunType

Constructors

public WidgetRun(ConstraintWidget widget)

Methods

public boolean isDimensionResolved()

public boolean isCenterConnection()

public long wrapSize(int direction)

protected final DependencyNode getTarget(ConstraintAnchor anchor)

protected void updateRunCenter(Dependency dependency, ConstraintAnchor startAnchor, ConstraintAnchor endAnchor, int orientation)

protected void updateRunStart(Dependency dependency)

protected void updateRunEnd(Dependency dependency)

public void update(Dependency dependency)

protected final int getLimitedDimension(int dimension, int orientation)

protected final DependencyNode getTarget(ConstraintAnchor anchor, int orientation)

protected final void addTarget(DependencyNode node, DependencyNode target, int margin)

protected final void addTarget(DependencyNode node, DependencyNode target, int marginFactor, androidx.constraintlayout.core.widgets.analyzer.DimensionDependency dimensionDependency)

public long getWrapDimension()

public boolean isResolved()

Source

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.constraintlayout.core.widgets.analyzer;

import static androidx.constraintlayout.core.widgets.ConstraintWidget.HORIZONTAL;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_PERCENT;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_RATIO;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_SPREAD;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.MATCH_CONSTRAINT_WRAP;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.VERTICAL;

import androidx.constraintlayout.core.widgets.ConstraintAnchor;
import androidx.constraintlayout.core.widgets.ConstraintWidget;

public abstract class WidgetRun implements Dependency {
    public int matchConstraintsType;
    ConstraintWidget mWidget;
    RunGroup mRunGroup;
    protected ConstraintWidget.DimensionBehaviour mDimensionBehavior;
    DimensionDependency mDimension = new DimensionDependency(this);

    public int orientation = HORIZONTAL;
    boolean mResolved = false;
    public DependencyNode start = new DependencyNode(this);
    public DependencyNode end = new DependencyNode(this);

    @SuppressWarnings("HiddenTypeParameter")
    protected RunType mRunType = RunType.NONE;

    public WidgetRun(ConstraintWidget widget) {
        this.mWidget = widget;
    }

    @SuppressWarnings("HiddenAbstractMethod")
    abstract void clear();

    @SuppressWarnings("HiddenAbstractMethod")
    abstract void apply();

    @SuppressWarnings("HiddenAbstractMethod")
    abstract void applyToWidget();

    @SuppressWarnings("HiddenAbstractMethod")
    abstract void reset();

    @SuppressWarnings("HiddenAbstractMethod")
    abstract boolean supportsWrapComputation();

    public boolean isDimensionResolved() {
        return mDimension.resolved;
    }

    /**
     * @TODO: add description
     */
    public boolean isCenterConnection() {
        int connections = 0;
        int count = start.mTargets.size();
        for (int i = 0; i < count; i++) {
            DependencyNode dependency = start.mTargets.get(i);
            if (dependency.mRun != this) {
                connections++;
            }
        }
        count = end.mTargets.size();
        for (int i = 0; i < count; i++) {
            DependencyNode dependency = end.mTargets.get(i);
            if (dependency.mRun != this) {
                connections++;
            }
        }
        return connections >= 2;
    }

    /**
     * @TODO: add description
     */
    public long wrapSize(int direction) {
        if (mDimension.resolved) {
            long size = mDimension.value;
            if (isCenterConnection()) { //start.targets.size() > 0 && end.targets.size() > 0) {
                size += start.mMargin - end.mMargin;
            } else {
                if (direction == RunGroup.START) {
                    size += start.mMargin;
                } else {
                    size -= end.mMargin;
                }
            }
            return size;
        }
        return 0;
    }

    protected final DependencyNode getTarget(ConstraintAnchor anchor) {
        if (anchor.mTarget == null) {
            return null;
        }
        DependencyNode target = null;
        ConstraintWidget targetWidget = anchor.mTarget.mOwner;
        ConstraintAnchor.Type targetType = anchor.mTarget.mType;
        switch (targetType) {
            case LEFT: {
                HorizontalWidgetRun run = targetWidget.mHorizontalRun;
                target = run.start;
            }
            break;
            case RIGHT: {
                HorizontalWidgetRun run = targetWidget.mHorizontalRun;
                target = run.end;
            }
            break;
            case TOP: {
                VerticalWidgetRun run = targetWidget.mVerticalRun;
                target = run.start;
            }
            break;
            case BASELINE: {
                VerticalWidgetRun run = targetWidget.mVerticalRun;
                target = run.baseline;
            }
            break;
            case BOTTOM: {
                VerticalWidgetRun run = targetWidget.mVerticalRun;
                target = run.end;
            }
            break;
            default:
                break;
        }
        return target;
    }

    protected void updateRunCenter(Dependency dependency,
            ConstraintAnchor startAnchor,
            ConstraintAnchor endAnchor,
            int orientation) {
        DependencyNode startTarget = getTarget(startAnchor);
        DependencyNode endTarget = getTarget(endAnchor);

        if (!(startTarget.resolved && endTarget.resolved)) {
            return;
        }

        int startPos = startTarget.value + startAnchor.getMargin();
        int endPos = endTarget.value - endAnchor.getMargin();
        int distance = endPos - startPos;

        if (!mDimension.resolved
                && mDimensionBehavior == ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT) {
            resolveDimension(orientation, distance);
        }

        if (!mDimension.resolved) {
            return;
        }

        if (mDimension.value == distance) {
            start.resolve(startPos);
            end.resolve(endPos);
            return;
        }

        // Otherwise, we have to center
        float bias = orientation == HORIZONTAL ? mWidget.getHorizontalBiasPercent()
                : mWidget.getVerticalBiasPercent();

        if (startTarget == endTarget) {
            startPos = startTarget.value;
            endPos = endTarget.value;
            // TODO: taking advantage of bias here would be a nice feature to support,
            // but for now let's stay compatible with 1.1
            bias = 0.5f;
        }

        int availableDistance = (endPos - startPos - mDimension.value);
        start.resolve((int) (0.5f + startPos + availableDistance * bias));
        end.resolve(start.value + mDimension.value);
    }

    private void resolveDimension(int orientation, int distance) {
        switch (matchConstraintsType) {
            case MATCH_CONSTRAINT_SPREAD: {
                mDimension.resolve(getLimitedDimension(distance, orientation));
            }
            break;
            case MATCH_CONSTRAINT_PERCENT: {
                ConstraintWidget parent = mWidget.getParent();
                if (parent != null) {
                    WidgetRun run = orientation == HORIZONTAL
                            ? parent.mHorizontalRun
                            : parent.mVerticalRun;
                    if (run.mDimension.resolved) {
                        float percent = orientation == HORIZONTAL
                                ? mWidget.mMatchConstraintPercentWidth
                                : mWidget.mMatchConstraintPercentHeight;
                        int targetDimensionValue = run.mDimension.value;
                        int size = (int) (0.5f + targetDimensionValue * percent);
                        mDimension.resolve(getLimitedDimension(size, orientation));
                    }
                }
            }
            break;
            case MATCH_CONSTRAINT_WRAP: {
                int wrapValue = getLimitedDimension(mDimension.wrapValue, orientation);
                mDimension.resolve(Math.min(wrapValue, distance));
            }
            break;
            case MATCH_CONSTRAINT_RATIO: {
                if (mWidget.mHorizontalRun.mDimensionBehavior
                        == ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT
                        && mWidget.mHorizontalRun.matchConstraintsType == MATCH_CONSTRAINT_RATIO
                        && mWidget.mVerticalRun.mDimensionBehavior
                        == ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT
                        && mWidget.mVerticalRun.matchConstraintsType == MATCH_CONSTRAINT_RATIO) {
                    // pof
                } else {
                    WidgetRun run = (orientation == HORIZONTAL)
                            ? mWidget.mVerticalRun : mWidget.mHorizontalRun;
                    if (run.mDimension.resolved) {
                        float ratio = mWidget.getDimensionRatio();
                        int value;
                        if (orientation == VERTICAL) {
                            value = (int) (0.5f + run.mDimension.value / ratio);
                        } else {
                            value = (int) (0.5f + ratio * run.mDimension.value);
                        }
                        mDimension.resolve(value);
                    }
                }
            }
            break;
            default:
                break;
        }
    }

    protected void updateRunStart(Dependency dependency) {

    }

    protected void updateRunEnd(Dependency dependency) {

    }

    /**
     * @TODO: add description
     */
    public void update(Dependency dependency) {
    }

    protected final int getLimitedDimension(int dimension, int orientation) {
        if (orientation == HORIZONTAL) {
            int max = mWidget.mMatchConstraintMaxWidth;
            int min = mWidget.mMatchConstraintMinWidth;
            int value = Math.max(min, dimension);
            if (max > 0) {
                value = Math.min(max, dimension);
            }
            if (value != dimension) {
                dimension = value;
            }
        } else {
            int max = mWidget.mMatchConstraintMaxHeight;
            int min = mWidget.mMatchConstraintMinHeight;
            int value = Math.max(min, dimension);
            if (max > 0) {
                value = Math.min(max, dimension);
            }
            if (value != dimension) {
                dimension = value;
            }
        }
        return dimension;
    }

    protected final DependencyNode getTarget(ConstraintAnchor anchor, int orientation) {
        if (anchor.mTarget == null) {
            return null;
        }
        DependencyNode target = null;
        ConstraintWidget targetWidget = anchor.mTarget.mOwner;
        WidgetRun run = (orientation == ConstraintWidget.HORIZONTAL)
                ? targetWidget.mHorizontalRun : targetWidget.mVerticalRun;
        ConstraintAnchor.Type targetType = anchor.mTarget.mType;
        switch (targetType) {
            case TOP:
            case LEFT: {
                target = run.start;
            }
            break;
            case BOTTOM:
            case RIGHT: {
                target = run.end;
            }
            break;
            default:
                break;
        }
        return target;
    }

    protected final void addTarget(DependencyNode node,
            DependencyNode target,
            int margin) {
        node.mTargets.add(target);
        node.mMargin = margin;
        target.mDependencies.add(node);
    }

    protected final void addTarget(DependencyNode node,
            DependencyNode target,
            int marginFactor,
            @SuppressWarnings("HiddenTypeParameter") DimensionDependency
                    dimensionDependency) {
        node.mTargets.add(target);
        node.mTargets.add(mDimension);
        node.mMarginFactor = marginFactor;
        node.mMarginDependency = dimensionDependency;
        target.mDependencies.add(node);
        dimensionDependency.mDependencies.add(node);
    }

    /**
     * @TODO: add description
     */
    public long getWrapDimension() {
        if (mDimension.resolved) {
            return mDimension.value;
        }
        return 0;
    }

    public boolean isResolved() {
        return mResolved;
    }

    enum RunType {NONE, START, END, CENTER}
}