material-components/material-components-android · error · IllegalArgumentException

The component's visibility must be one of VISIBLE, INVISIBLE

Error message

The component's visibility must be one of VISIBLE, INVISIBLE, and GONE defined in View.

What it means

setVisibilityAfterHide(int) only accepts View.VISIBLE, View.INVISIBLE, or View.GONE; any other int (including 0-adjacent typos or custom constants) throws IllegalArgumentException. The value determines the indicator's view visibility after the hide animation completes, and arbitrary values have no meaning to View.

Source

Thrown at lib/java/com/google/android/material/progressindicator/BaseProgressIndicator.java:958

    } else {
      // Calls ProgressBar setProgress(int) to update the progress value and level. We don't rely on
      // it to draw or animate the indicator.
      super.setProgress(progress);
      // Fast forward to the final state of the determinate animation.
      if (getProgressDrawable() != null && !animated) {
        getProgressDrawable().jumpToCurrentState();
      }
    }
  }

  /**
   * Sets the visibility which the component will be after hide animation finishes.
   *
   * @param visibility New component's visibility after the hide animation finishes.
   */
  public void setVisibilityAfterHide(int visibility) {
    if (visibility != View.VISIBLE && visibility != View.INVISIBLE && visibility != View.GONE) {
      throw new IllegalArgumentException(
          "The component's visibility must be one of VISIBLE, INVISIBLE, and GONE defined in"
              + " View.");
    }
    visibilityAfterHide = visibility;
  }

  private final OnAnimationEndListener hideAfterMaxProgressListener =
      (animation, canceled, value, velocity) -> {
        if (getProgressDrawable() != null
            && getProgressDrawable().getLevel() == MAX_DRAWABLE_LEVEL) {
          hide();
        }
      };

  public void setHideAfterMaxProgress(boolean hideAfterMaxProgress) {
    if (getProgressDrawable() == null) {
      return;
    }

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Pass only View.VISIBLE, View.INVISIBLE, or View.GONE
  2. Validate/sanitize external int input against the three constants before calling
  3. Prefer relying on the default behavior (GONE) when hide-visibility customization is not needed

Example fix

// before
indicator.setVisibilityAfterHide(if (hidden) 1 else 2)
// after
indicator.setVisibilityAfterHide(if (hidden) View.GONE else View.VISIBLE)
Defensive patterns

Strategy: validation

Validate before calling

fun isValidVisibility(v: Int): Boolean =
    v == View.VISIBLE || v == View.INVISIBLE || v == View.GONE

Try / catch

catch (e: IllegalArgumentException) { Log.e(TAG, "Invalid visibility constant; defaulting to GONE", e); indicator.setVisibilityAfterHide(View.GONE) }

Prevention

When it happens

Trigger: Calling setVisibilityAfterHide(someInt) where someInt is not one of the three View visibility constants; e.g. passing View.SCREEN_STATE_OFF, a resource id, or a raw number.

Common situations: Data-binding expressions feeding an arbitrary int; refactoring that passes visibility from another source (WindowManager flags) unchecked.

Related errors


AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14). Data as JSON: /api/errors/7d9e6a7761c2ea31. Report an issue: GitHub.