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.design.widget; 18 19import android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.animation.ValueAnimator; 22import android.util.StateSet; 23 24import java.util.ArrayList; 25 26final class StateListAnimator { 27 28 private final ArrayList<Tuple> mTuples = new ArrayList<>(); 29 30 private Tuple mLastMatch = null; 31 ValueAnimator mRunningAnimator = null; 32 33 private final ValueAnimator.AnimatorListener mAnimationListener = 34 new AnimatorListenerAdapter() { 35 @Override 36 public void onAnimationEnd(Animator animator) { 37 if (mRunningAnimator == animator) { 38 mRunningAnimator = null; 39 } 40 } 41 }; 42 43 /** 44 * Associates the given Animation with the provided drawable state specs so that it will be run 45 * when the View's drawable state matches the specs. 46 * 47 * @param specs The drawable state specs to match against 48 * @param animator The animator to run when the specs match 49 */ 50 public void addState(int[] specs, ValueAnimator animator) { 51 Tuple tuple = new Tuple(specs, animator); 52 animator.addListener(mAnimationListener); 53 mTuples.add(tuple); 54 } 55 56 /** 57 * Called by View 58 */ 59 void setState(int[] state) { 60 Tuple match = null; 61 final int count = mTuples.size(); 62 for (int i = 0; i < count; i++) { 63 final Tuple tuple = mTuples.get(i); 64 if (StateSet.stateSetMatches(tuple.mSpecs, state)) { 65 match = tuple; 66 break; 67 } 68 } 69 if (match == mLastMatch) { 70 return; 71 } 72 if (mLastMatch != null) { 73 cancel(); 74 } 75 76 mLastMatch = match; 77 78 if (match != null) { 79 start(match); 80 } 81 } 82 83 private void start(Tuple match) { 84 mRunningAnimator = match.mAnimator; 85 mRunningAnimator.start(); 86 } 87 88 private void cancel() { 89 if (mRunningAnimator != null) { 90 mRunningAnimator.cancel(); 91 mRunningAnimator = null; 92 } 93 } 94 95 /** 96 * If there is an animation running for a recent state change, ends it. 97 * 98 * <p>This causes the animation to assign the end value(s) to the View.</p> 99 */ 100 public void jumpToCurrentState() { 101 if (mRunningAnimator != null) { 102 mRunningAnimator.end(); 103 mRunningAnimator = null; 104 } 105 } 106 107 static class Tuple { 108 final int[] mSpecs; 109 final ValueAnimator mAnimator; 110 111 Tuple(int[] specs, ValueAnimator animator) { 112 mSpecs = specs; 113 mAnimator = animator; 114 } 115 } 116}