package org.itsnat.droid.impl.xmlinflater.animator; import android.animation.Animator; import android.animation.AnimatorSet; import org.itsnat.droid.AttrResourceInflaterListener; import org.itsnat.droid.ItsNatDroidException; import org.itsnat.droid.impl.dom.DOMElement; import org.itsnat.droid.impl.dom.animator.DOMElemAnimator; import org.itsnat.droid.impl.dom.animator.DOMElemAnimatorSet; import org.itsnat.droid.impl.dom.animator.XMLDOMAnimator; import org.itsnat.droid.impl.xmlinflated.animator.InflatedXMLAnimator; import org.itsnat.droid.impl.xmlinflater.XMLInflaterResource; import org.itsnat.droid.impl.xmlinflater.animator.classtree.ClassDescAnimatorBased; import org.itsnat.droid.impl.xmlinflater.animator.classtree.ClassDescAnimatorSet; import java.util.List; /** * Created by jmarranz on 4/11/14. */ public class XMLInflaterAnimator extends XMLInflaterResource<Animator> { protected XMLInflaterAnimator(InflatedXMLAnimator inflatedXML, int bitmapDensityReference, AttrResourceInflaterListener attrResourceInflaterListener) { super(inflatedXML, bitmapDensityReference, attrResourceInflaterListener); } public static XMLInflaterAnimator createXMLInflaterAnimator(InflatedXMLAnimator inflatedAnimator, int bitmapDensityReference, AttrResourceInflaterListener attrResourceInflaterListener) { return new XMLInflaterAnimator(inflatedAnimator,bitmapDensityReference,attrResourceInflaterListener); } @SuppressWarnings("unchecked") public ClassDescAnimatorBased<Animator> getClassDescAnimatorBased(DOMElemAnimator domElemAnimator) { ClassDescAnimatorMgr classDescMgr = getInflatedXMLAnimator().getXMLInflaterRegistry().getClassDescAnimatorMgr(); return classDescMgr.get(domElemAnimator.getTagName()); } public InflatedXMLAnimator getInflatedXMLAnimator() { return (InflatedXMLAnimator)inflatedXML; } public Animator inflateAnimator() { return inflateRoot(getInflatedXMLAnimator().getXMLDOMAnimator()); } private Animator inflateRoot(XMLDOMAnimator xmlDOMAnimator) { DOMElemAnimator rootDOMElem = (DOMElemAnimator)xmlDOMAnimator.getRootDOMElement(); AttrAnimatorContext attrCtx = new AttrAnimatorContext(this); ClassDescAnimatorBased<Animator> classDesc = getClassDescAnimatorBased(rootDOMElem); Animator animatorRoot = classDesc.createRootResourceAndFillAttributes(rootDOMElem, attrCtx); if (animatorRoot instanceof AnimatorSet) processChildElements((DOMElemAnimatorSet)rootDOMElem, (AnimatorSet)animatorRoot,attrCtx); // En teoría <objectAnimator> y <animator> podrían tener elementos hijo tal y como // <objectAnimator> // <propertyValuesHolder android:propertyName="x" android:valueTo="400"/> // <propertyValuesHolder android:propertyName="y" android:valueTo="200"/> // <animator> // <keyframe android:fraction="0" android:value="1"/> // <keyframe android:fraction=".2" android:value=".4"/> // <keyframe android:fraction="1" android:value="0"/> // pudiéndose declarar varias propiedades a la vez y animarlas a la vez. // Sin embargo este XML fue introducido en Android 5.0 Lollipop, aunque es posible hacerlo de forma programática usando // ValueAnimator.setValues(PropertyValuesHolder... values) // http://developer.android.com/reference/android/animation/ObjectAnimator.html // http://developer.android.com/reference/android/animation/ValueAnimator.html // http://stackoverflow.com/questions/32885324/propertyvaluesholder-causes-crash-when-used-in-xml-defined-animation return animatorRoot; } private void processChildElements(DOMElemAnimatorSet domElemParent, AnimatorSet parentAnimator,AttrAnimatorContext attrCtx) { List<DOMElement> childDOMElemList = domElemParent.getChildDOMElementList(); if (childDOMElemList == null || childDOMElemList.size() == 0) return; String ordering = ClassDescAnimatorSet.getOrderingAttribute(domElemParent); Animator[] childAnimators = new Animator[childDOMElemList.size()]; int i = 0; for (DOMElement childDOMElem : childDOMElemList) { Animator animator = inflateNextElement((DOMElemAnimator)childDOMElem,attrCtx); childAnimators[i] = animator; i++; } if ("together".equals(ordering)) parentAnimator.playTogether(childAnimators); else if ("sequentially".equals(ordering)) parentAnimator.playSequentially(childAnimators); else throw new ItsNatDroidException("Unknown ordering attribute value: " + ordering); } protected Animator inflateNextElement(DOMElemAnimator domElement,AttrAnimatorContext attrCtx) { ClassDescAnimatorBased<Animator> classDesc = getClassDescAnimatorBased(domElement); Animator animator = classDesc.createResourceAndFillAttributes(domElement, attrCtx); if (animator instanceof AnimatorSet) processChildElements((DOMElemAnimatorSet)domElement, (AnimatorSet)animator,attrCtx); return animator; } }