constraintlayout icon indicating copy to clipboard operation
constraintlayout copied to clipboard

Flow visibility broken since 2.1.0

Open chriswiesner opened this issue 3 years ago • 2 comments

Setting visibility on a Flow using 2.0.4 works fine. As soon as I update to 2.1.0 it breaks.

Most likely be caused by https://github.com/androidx/constraintlayout/pull/258

Note: I update a ConstraintSet (setting bias) during runtime for different views of the container - seems like this update is applying visibility to not affected siblings

chriswiesner avatar Aug 25 '21 12:08 chriswiesner

added a sample project here: https://github.com/chriswiesner/ConstraintLayoutVisibilityBug

chriswiesner avatar Aug 25 '21 14:08 chriswiesner

The issue is still reproducible in the 2.1.4 version.

An explanation:

  1. For example, we have a Flow of views and one of the referenced views is GONE for some reason, then we want to change a constraint of a view that is not referenced in Flow, e.g. vertical bias, but maintain all constraints of the initial state.
ConstraintSet().apply {
    clone(constraintLayot)
    setVerticalBias(viewToChangeId, 0.5f)
    applyTo(constraintLayot)
}
  1. ConstraintSet starts applying constraints, it takes all children and set their params, but at the end of constraintSet.applyToInternal() we have the block that invokes helpers to modify View (see code below). Since Flow is a ConstraintHelper then inside applyLayoutFeatures() visibility of each View is erased by Flow visibility.
// ConstraintSet#applyToInternally
for (int i = 0; i < count; i++) {
        View view = constraintLayout.getChildAt(i);
        if (view instanceof ConstraintHelper) {
            ConstraintHelper constraintHelper = (ConstraintHelper) view;
            constraintHelper.applyLayoutFeaturesInConstraintSet(constraintLayout);
        }
}

// ConstraintHelper#applyLayoutFeatures
int visibility = getVisibility();
float elevation = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        elevation = getElevation();
}
for (int i = 0; i < mCount; i++) {
        int id = mIds[i];
        View view = container.getViewById(id);
        if (view != null) {
            view.setVisibility(visibility); // erasing original visibility
            if (elevation > 0 && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                view.setTranslationZ(view.getTranslationZ() + elevation);
            }
    }
}

In my opinion, this kind of behavior should not be legit because Flow is about positioning and if we want to change the visibility of all referenced View then we should use Group instead.

Genesis0403 avatar Sep 08 '22 10:09 Genesis0403