Baseflow/PhotoView · error · IllegalArgumentException

Minimum zoom has to be less than Medium zoom. Call setMinimu

Error message

Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value

What it means

Util.checkZoomLevels enforces the invariant minimumScale < mediumScale < maximumScale and throws IllegalArgumentException from setMinimumScale, setMediumScale, setMaximumScale, or setScaleLevels when minZoom >= midZoom. PhotoView's double-tap and zoom gesture logic assumes a strictly increasing ordering, so a flat or inverted range would make double-tap cycles undefined. The exception fires before any state is mutated, so the attacher keeps its previous valid levels.

Source

Thrown at photoview/src/main/java/com/github/chrisbanes/photoview/Util.java:11

package com.github.chrisbanes.photoview;

import android.view.MotionEvent;
import android.widget.ImageView;

class Util {

    static void checkZoomLevels(float minZoom, float midZoom,
                                float maxZoom) {
        if (minZoom >= midZoom) {
            throw new IllegalArgumentException(
                    "Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
        } else if (midZoom >= maxZoom) {
            throw new IllegalArgumentException(
                    "Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
        }
    }

    static boolean hasDrawable(ImageView imageView) {
        return imageView.getDrawable() != null;
    }

    static boolean isSupportedScaleType(final ImageView.ScaleType scaleType) {
        if (scaleType == null) {
            return false;
        }
        switch (scaleType) {
            case MATRIX:
                throw new IllegalStateException("Matrix scale type is not supported");

View on GitHub (pinned to 565505d5cb)

Solutions

  1. Set all three levels atomically with setScaleLevels(min, mid, max) in strictly increasing order, instead of sequencing individual setters.
  2. If levels are computed from image size, clamp/order them before applying: ensure min < mid < max, e.g. min = Math.min(min, mid / 2f).
  3. Reorder initialization so setMinimumScale runs before setMediumScale/setMaximumScale, and make each new value respect the levels already set.

Example fix

// before
photoView.setMinimumScale(fitScale); // throws when fitScale >= midScale

// after
photoView.setScaleLevels(
    Math.min(fitScale, DEFAULT_MID / 2f),
    Math.max(fitScale * 1.5f, DEFAULT_MID),
    Math.max(fitScale * 3f, DEFAULT_MAX));
Defensive patterns

Strategy: validation

Validate before calling

float min = Math.min(minScale, midScale * 0.5f);
float mid = Math.max(midScale, min * 1.5f);
// keep mid < max by construction before any setter runs
photoView.setScaleLevels(min, mid, Math.max(maxScale, mid * 1.5f));

Prevention

When it happens

Trigger: Calling photoView.setMinimumScale(2f) while mediumScale is still 2.0 (default) — 2 >= 2 throws; calling setScaleLevels(1f, 1f, 3f) with min equal to mid; calling setScaleLevels(1.5f, 1.2f, 3f) with min greater than mid; any per-level setter whose new value crosses the adjacent level.

Common situations: Deriving one zoom level from image dimensions (e.g. medium = drawableWidth/viewWidth) while leaving others hardcoded, so medium ends up <= min (a large image in a small view gives medium < 1.0 while min stays 1.0); ordering setMinimumScale/setMediumScale calls wrongly during initialization (setting min after mid); migrating from an older PhotoView version where level checks were looser.

Related errors


AI-assisted analysis of Baseflow/PhotoView@565505d5cb (2026-08-14). Data as JSON: /api/errors/3ef0b237cc03c4b4. Report an issue: GitHub.