{"record":{"id":"1c7300f368ee32a1","repo":"Baseflow/PhotoView","slug":"scale-must-be-within-the-range-of-minscale-and-max","errorCode":null,"errorMessage":"Scale must be within the range of minScale and maxScale","messagePattern":"Scale must be within the range of minScale and maxScale","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java","lineNumber":462,"sourceCode":"        mOnViewDragListener = listener;\n    }\n\n    public void setScale(float scale) {\n        setScale(scale, false);\n    }\n\n    public void setScale(float scale, boolean animate) {\n        setScale(scale,\n            (mImageView.getRight()) / 2,\n            (mImageView.getBottom()) / 2,\n            animate);\n    }\n\n    public void setScale(float scale, float focalX, float focalY,\n        boolean animate) {\n        // Check to see if the scale is within bounds\n        if (scale < mMinScale || scale > mMaxScale) {\n            throw new IllegalArgumentException(\"Scale must be within the range of minScale and maxScale\");\n        }\n        if (animate) {\n            mImageView.post(new AnimatedZoomRunnable(getScale(), scale,\n                focalX, focalY));\n        } else {\n            mSuppMatrix.setScale(scale, scale, focalX, focalY);\n            checkAndDisplayMatrix();\n        }\n    }\n\n    /**\n     * Set the zoom interpolator\n     *\n     * @param interpolator the zoom interpolator\n     */\n    public void setZoomInterpolator(Interpolator interpolator) {\n        mInterpolator = interpolator;\n    }","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/Baseflow/PhotoView/blob/565505d5cb84f5977771b5d2ccb7726338e77224/photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java#L444-L480","documentation":"PhotoView.setScale throws IllegalArgumentException when the requested scale falls outside the [minimumScale, maximumScale] range configured on the attacher. The bounds exist so zoom gestures and cleanup logic stay consistent; a scale outside them would leave the view in a state the internal cleanup()/checkMatrixBounds() code would immediately fight against. Defaults are typically 1.0 / 2.0 / 3.0 unless changed via setScaleLevels/setMinimumScale/setMaximumScale.","triggerScenarios":"Calling photoView.setScale(4f) while maxScale is still 3.0; calling setScale with a computed value (e.g. screenWidth / drawableWidth) that exceeds max or is below min; calling setScale(randomScale) where the random range was generated against stale or custom min/max levels; calling setScale before custom levels set via setScaleLevels() have been applied.","commonSituations":"Apps that compute a 'fit width' or 'fit height' zoom factor from bitmap dimensions (often >1 after setScaleLevels(1f, 1.75f)); the official sample's random-scale menu action; state restoration that reapplies a persisted scale after levels were narrowed; unit tests that assume default levels while the production code changed them.","solutions":["Clamp the requested scale to the configured range: float s = Math.max(photoView.getMinimumScale(), Math.min(scale, photoView.getMaximumScale()));","If the out-of-range scale is intentional, widen the range first with setScaleLevels(min, mid, max) (or setMaximumScale/setMinimumScale) so it satisfies Util.checkZoomLevels, then call setScale.","Compute the desired zoom from drawable dimensions and derive min/max levels from it instead of hardcoding 3.0 as max."],"exampleFix":"// before\nfloat fitZoom = (float) viewWidth / (float) drawableWidth;\nphotoView.setScale(fitZoom); // throws if fitZoom > maxScale\n\n// after\nfloat clamped = Math.max(photoView.getMinimumScale(),\n    Math.min(fitZoom, photoView.getMaximumScale()));\nphotoView.setScale(clamped);","handlingStrategy":"validation","validationCode":"float safeScale = Math.max(photoView.getMinimumScale(),\n    Math.min(desiredScale, photoView.getMaximumScale()));\nphotoView.setScale(safeScale, animate);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize every setScale call behind one helper that clamps to getMinimumScale()/getMaximumScale().","When zoom levels are configurable (settings screen, per-image levels), recompute and clamp stored scales right after calling setScaleLevels.","Treat min/mid/max levels and requested scales as one configuration unit — never set a scale derived from image dimensions against default levels."],"tags":["photoview","android","zoom","bounds-check","illegalargumentexception"],"backgroundTag":null,"analyzedSha":"565505d5cb84f5977771b5d2ccb7726338e77224","analyzedAt":"2026-08-14T14:25:26.552Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}