1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.view.animation; 18 19import android.graphics.Path; 20import android.graphics.PathMeasure; 21import android.view.animation.Interpolator; 22 23/** 24 * A path interpolator implementation compatible with API 9+. 25 */ 26class PathInterpolatorGingerbread implements Interpolator { 27 28 /** 29 * Governs the accuracy of the approximation of the {@link Path}. 30 */ 31 private static final float PRECISION = 0.002f; 32 33 private final float[] mX; 34 private final float[] mY; 35 36 public PathInterpolatorGingerbread(Path path) { 37 final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); 38 39 final float pathLength = pathMeasure.getLength(); 40 final int numPoints = (int) (pathLength / PRECISION) + 1; 41 42 mX = new float[numPoints]; 43 mY = new float[numPoints]; 44 45 final float[] position = new float[2]; 46 for (int i = 0; i < numPoints; ++i) { 47 final float distance = (i * pathLength) / (numPoints - 1); 48 pathMeasure.getPosTan(distance, position, null /* tangent */); 49 50 mX[i] = position[0]; 51 mY[i] = position[1]; 52 } 53 } 54 55 public PathInterpolatorGingerbread(float controlX, float controlY) { 56 this(createQuad(controlX, controlY)); 57 } 58 59 public PathInterpolatorGingerbread(float controlX1, float controlY1, 60 float controlX2, float controlY2) { 61 this(createCubic(controlX1, controlY1, controlX2, controlY2)); 62 } 63 64 @Override 65 public float getInterpolation(float t) { 66 if (t <= 0.0f) { 67 return 0.0f; 68 } else if (t >= 1.0f) { 69 return 1.0f; 70 } 71 72 // Do a binary search for the correct x to interpolate between. 73 int startIndex = 0; 74 int endIndex = mX.length - 1; 75 while (endIndex - startIndex > 1) { 76 int midIndex = (startIndex + endIndex) / 2; 77 if (t < mX[midIndex]) { 78 endIndex = midIndex; 79 } else { 80 startIndex = midIndex; 81 } 82 } 83 84 final float xRange = mX[endIndex] - mX[startIndex]; 85 if (xRange == 0) { 86 return mY[startIndex]; 87 } 88 89 final float tInRange = t - mX[startIndex]; 90 final float fraction = tInRange / xRange; 91 92 final float startY = mY[startIndex]; 93 final float endY = mY[endIndex]; 94 95 return startY + (fraction * (endY - startY)); 96 } 97 98 private static Path createQuad(float controlX, float controlY) { 99 final Path path = new Path(); 100 path.moveTo(0.0f, 0.0f); 101 path.quadTo(controlX, controlY, 1.0f, 1.0f); 102 return path; 103 } 104 105 private static Path createCubic(float controlX1, float controlY1, 106 float controlX2, float controlY2) { 107 final Path path = new Path(); 108 path.moveTo(0.0f, 0.0f); 109 path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f); 110 return path; 111 } 112} 113