/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.animation; import java.util.concurrent.CopyOnWriteArrayList; import android.support.annotation.VisibleForTesting; import android.support.v4.util.SimpleArrayMap; import com.facebook.litho.dataflow.BindingListener; import com.facebook.litho.dataflow.GraphBinding; import com.facebook.litho.dataflow.ValueNode; /** * Base class for defining animations for transitions between states of the component hierarchy. * Subclasses should define their animation by creating a {@link GraphBinding} in * {@link #setupBinding}. */ public abstract class TransitionAnimationBinding implements AnimationBinding { private final GraphBinding mGraphBinding; private final CopyOnWriteArrayList<AnimationBindingListener> mListeners = new CopyOnWriteArrayList<>(); private final SimpleArrayMap<ComponentProperty, RuntimeValue> mAppearFromValues = new SimpleArrayMap<>(); private final SimpleArrayMap<ComponentProperty, RuntimeValue> mDisappearToValues = new SimpleArrayMap<>(); public TransitionAnimationBinding() { this(GraphBinding.create()); } @VisibleForTesting TransitionAnimationBinding(GraphBinding graphBinding) { mGraphBinding = graphBinding; mGraphBinding.setListener(new BindingListener() { @Override public void onAllNodesFinished(GraphBinding binding) { TransitionAnimationBinding.this.onAllNodesFinished(); } }); } /** * @see GraphBinding#addBinding(ValueNode, ValueNode, String) */ public void addBinding(ValueNode fromNode, ValueNode toNode, String inputName) { mGraphBinding.addBinding(fromNode, toNode, inputName); } /** * @see GraphBinding#addBinding(ValueNode, ValueNode) */ public void addBinding(ValueNode fromNode, ValueNode toNode) { mGraphBinding.addBinding(fromNode, toNode); } /** * For appear animations, sets the value that the property should have before the animation * starts. See {@link RuntimeValue} for more info. */ public void addAppearFromValue(ComponentProperty property, RuntimeValue value) { mAppearFromValues.put(property, value); } /** * For disappear animations, sets the value that the property should end at by the time the * animation ends and before the item is unmounted. See {@link RuntimeValue} for more info. */ public void addDisappearToValue(ComponentProperty property, RuntimeValue value) { mDisappearToValues.put(property, value); } @Override public void start(Resolver resolver) { setupBinding(resolver); mGraphBinding.activate(); } /** * Subclasses should set up their animation by creating a graph that defines how data will flow * to relevant {@link AnimatedPropertyNode}s. */ protected abstract void setupBinding(Resolver resolver); @Override public void stop() { mGraphBinding.deactivate(); } @Override public boolean isActive() { return mGraphBinding.isActive(); } private void onAllNodesFinished() { for (AnimationBindingListener listener : mListeners) { listener.onFinish(this); } stop(); } @Override public void collectAppearFromValues(SimpleArrayMap<ComponentProperty, RuntimeValue> outMap) { outMap.putAll(mAppearFromValues); } @Override public void collectDisappearToValues(SimpleArrayMap<ComponentProperty, RuntimeValue> outMap) { outMap.putAll(mDisappearToValues); } @Override public void addListener(AnimationBindingListener bindingListener) { mListeners.add(bindingListener); } @Override public void removeListener(AnimationBindingListener animationBindingListener) { mListeners.remove(animationBindingListener); } }