public abstract class

ViewTimeCycle

extends TimeCycleSplineSet

 java.lang.Object

androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet

↳androidx.constraintlayout.motion.utils.ViewTimeCycle

Subclasses:

ViewTimeCycle.PathRotate, ViewTimeCycle.CustomSet

Gradle dependencies

compile group: 'androidx.constraintlayout', name: 'constraintlayout', version: '2.2.0-beta01'

  • groupId: androidx.constraintlayout
  • artifactId: constraintlayout
  • version: 2.2.0-beta01

Artifact androidx.constraintlayout:constraintlayout:2.2.0-beta01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.constraintlayout:constraintlayout com.android.support.constraint:constraint-layout

Overview

This engine allows manipulation of attributes by wave shapes oscillating in time

Summary

Fields
from TimeCycleSplineSetCURVE_OFFSET, CURVE_PERIOD, CURVE_VALUE, mCache[], mContinue, mCount, mCurveFit, mLastCycle, mLastTime, mTimePoints[], mType, mValues[][], mWaveShape, sVal2PI
Constructors
publicViewTimeCycle()

Methods
public floatget(float pos, long time, View view, KeyCache cache)

get a value from the time cycle

public static ViewTimeCyclemakeCustomSpline(java.lang.String str, <any> attrList)

make a custom time cycle

public static ViewTimeCyclemakeSpline(java.lang.String str, long currentTime)

Make a time cycle spline

public abstract booleansetProperty(View view, float t, long time, KeyCache cache)

Set the time cycle parameters

from TimeCycleSplineSetcalcWave, getCurveFit, setPoint, setStartTime, setType, setup, toString
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Constructors

public ViewTimeCycle()

Methods

public abstract boolean setProperty(View view, float t, long time, KeyCache cache)

Set the time cycle parameters

Parameters:

view:
t:
time:
cache:

Returns:

public float get(float pos, long time, View view, KeyCache cache)

get a value from the time cycle

Parameters:

pos:
time:
view:
cache:

Returns:

public static ViewTimeCycle makeCustomSpline(java.lang.String str, <any> attrList)

make a custom time cycle

Parameters:

str:
attrList:

Returns:

public static ViewTimeCycle makeSpline(java.lang.String str, long currentTime)

Make a time cycle spline

Parameters:

str:
currentTime:

Returns:

Source

/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.constraintlayout.motion.utils;

import android.os.Build;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;

import androidx.constraintlayout.core.motion.utils.CurveFit;
import androidx.constraintlayout.core.motion.utils.KeyCache;
import androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet;
import androidx.constraintlayout.motion.widget.Key;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.widget.ConstraintAttribute;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * This engine allows manipulation of attributes by wave shapes oscillating in time
 *
 *
 */
public abstract class ViewTimeCycle extends TimeCycleSplineSet {
    private static final String TAG = "ViewTimeCycle";

    /**
     * Set the time cycle parameters
     * @param view
     * @param t
     * @param time
     * @param cache
     * @return
     */
    public abstract boolean setProperty(View view, float t, long time, KeyCache cache);

    /**
     * get a value from the time cycle
     * @param pos
     * @param time
     * @param view
     * @param cache
     * @return
     */
    public float get(float pos, long time, View view, KeyCache cache) {
        mCurveFit.getPos(pos, mCache);
        float period = mCache[CURVE_PERIOD];
        if (period == 0) {
            mContinue = false;
            return mCache[CURVE_OFFSET];
        }
        if (Float.isNaN(mLastCycle)) { // it has not been set
            mLastCycle = cache.getFloatValue(view, mType, 0); // check the cache
            if (Float.isNaN(mLastCycle)) {  // not in cache so set to 0 (start)
                mLastCycle = 0;
            }
        }
        long delta_time = time - mLastTime;
        mLastCycle = (float) ((mLastCycle + delta_time * 1E-9 * period) % 1.0);
        cache.setFloatValue(view, mType, 0, mLastCycle);
        mLastTime = time;
        float v = mCache[CURVE_VALUE];
        float wave = calcWave(mLastCycle);
        float offset = mCache[CURVE_OFFSET];
        float value = v * wave + offset;
        mContinue = v != 0.0f || period != 0.0f;
        return value;
    }

    /**
     * make a custom time cycle
     * @param str
     * @param attrList
     * @return
     */
    public static ViewTimeCycle makeCustomSpline(String str,
                                                 SparseArray<ConstraintAttribute> attrList) {
        return new CustomSet(str, attrList);
    }

    /**
     * Make a time cycle spline
     * @param str
     * @param currentTime
     * @return
     */
    public static ViewTimeCycle makeSpline(String str, long currentTime) {
        ViewTimeCycle timeCycle;
        switch (str) {
            case Key.ALPHA:
                timeCycle = new AlphaSet();
                break;
            case Key.ELEVATION:
                timeCycle = new ElevationSet();
                break;
            case Key.ROTATION:
                timeCycle = new RotationSet();
                break;
            case Key.ROTATION_X:
                timeCycle = new RotationXset();
                break;
            case Key.ROTATION_Y:
                timeCycle = new RotationYset();
                break;
            case Key.TRANSITION_PATH_ROTATE:
                timeCycle = new PathRotate();
                break;
            case Key.SCALE_X:
                timeCycle = new ScaleXset();
                break;
            case Key.SCALE_Y:
                timeCycle = new ScaleYset();
                break;
            case Key.TRANSLATION_X:
                timeCycle = new TranslationXset();
                break;
            case Key.TRANSLATION_Y:
                timeCycle = new TranslationYset();
                break;
            case Key.TRANSLATION_Z:
                timeCycle = new TranslationZset();
                break;
            case Key.PROGRESS:
                timeCycle = new ProgressSet();
                break;
            default:
                return null;
        }
        timeCycle.setStartTime(currentTime);
        return timeCycle;
    }

    static class ElevationSet extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                view.setElevation(get(t, time, view, cache));
            }
            return mContinue;
        }
    }

    static class AlphaSet extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setAlpha(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class RotationSet extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setRotation(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class RotationXset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setRotationX(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class RotationYset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setRotationY(get(t, time, view, cache));
            return mContinue;
        }
    }

    public static class PathRotate extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            return mContinue;
        }

        /**
         *  DO NOT CALL
         * @param view
         * @param cache
         * @param t
         * @param time
         * @param dx
         * @param dy
         * @return
         */
        public boolean setPathRotate(View view,
                                     KeyCache cache,
                                     float t,
                                     long time,
                                     double dx,
                                     double dy) {
            view.setRotation(get(t, time, view, cache)
                    + (float) Math.toDegrees(Math.atan2(dy, dx)));
            return mContinue;
        }
    }

    static class ScaleXset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setScaleX(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class ScaleYset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setScaleY(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class TranslationXset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setTranslationX(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class TranslationYset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            view.setTranslationY(get(t, time, view, cache));
            return mContinue;
        }
    }

    static class TranslationZset extends ViewTimeCycle {
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                view.setTranslationZ(get(t, time, view, cache));
            }
            return mContinue;
        }
    }

    public static class CustomSet extends ViewTimeCycle {
        String mAttributeName;
        SparseArray<ConstraintAttribute> mConstraintAttributeList;
        SparseArray<float[]> mWaveProperties = new SparseArray<>();
        float[] mTempValues;

        @SuppressWarnings("StringSplitter")
        public CustomSet(String attribute, SparseArray<ConstraintAttribute> attrList) {
            mAttributeName = attribute.split(",")[1];
            mConstraintAttributeList = attrList;
        }

        /**
         * Setup the curve
         * @param curveType
         */
        @Override
        public void setup(int curveType) {
            int size = mConstraintAttributeList.size();
            int dimensionality =
                    mConstraintAttributeList.valueAt(0).numberOfInterpolatedValues();
            double[] time = new double[size];
            mTempValues = new float[dimensionality + 2];
            mCache = new float[dimensionality];
            double[][] values = new double[size][dimensionality + 2];
            for (int i = 0; i < size; i++) {
                int key = mConstraintAttributeList.keyAt(i);
                ConstraintAttribute ca = mConstraintAttributeList.valueAt(i);
                float[] waveProp = mWaveProperties.valueAt(i);
                time[i] = key * 1E-2;
                ca.getValuesToInterpolate(mTempValues);
                for (int k = 0; k < mTempValues.length; k++) {
                    values[i][k] = mTempValues[k];
                }
                values[i][dimensionality] = waveProp[0];
                values[i][dimensionality + 1] = waveProp[1];
            }
            mCurveFit = CurveFit.get(curveType, time, values);
        }

        // @TODO: add description

        /**
         * @param position
         * @param value
         * @param period
         * @param shape
         * @param offset
         */
        @Override
        public void setPoint(int position, float value, float period, int shape, float offset) {
            throw new RuntimeException("Wrong call for custom attribute");
        }

        /**
         * set the keyTimePoint
         * @param position
         * @param value
         * @param period
         * @param shape
         * @param offset
         */
        public void setPoint(int position, ConstraintAttribute value,
                             float period,
                             int shape,
                             float offset) {
            mConstraintAttributeList.append(position, value);
            mWaveProperties.append(position, new float[]{period, offset});
            mWaveShape = Math.max(mWaveShape, shape); // the highest value shape is chosen
        }

        /**
         * Set the property of the view given the position the current time
         * @param view the view to set the property of
         * @param t the position on the curve
         * @param time the current time
         * @param cache the cache used to keep the previous position
         * @return true if it will need repaint
         */
        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            mCurveFit.getPos(t, mTempValues);
            float period = mTempValues[mTempValues.length - 2];
            float offset = mTempValues[mTempValues.length - 1];
            long delta_time = time - mLastTime;

            if (Float.isNaN(mLastCycle)) { // it has not been set
                mLastCycle = cache.getFloatValue(view, mAttributeName, 0); // check the cache
                if (Float.isNaN(mLastCycle)) {  // not in cache so set to 0 (start)
                    mLastCycle = 0;
                }
            }

            mLastCycle = (float) ((mLastCycle + delta_time * 1E-9 * period) % 1.0);
            mLastTime = time;
            float wave = calcWave(mLastCycle);
            mContinue = false;
            for (int i = 0; i < mCache.length; i++) {
                mContinue |= mTempValues[i] != 0.0;
                mCache[i] = mTempValues[i] * wave + offset;
            }
            CustomSupport.setInterpolatedValue(mConstraintAttributeList.valueAt(0),
                        view, mCache);
            if (period != 0.0f) {
                mContinue = true;
            }
            return mContinue;
        }
    }

    static class ProgressSet extends ViewTimeCycle {
        boolean mNoMethod = false;

        @Override
        public boolean setProperty(View view, float t, long time, KeyCache cache) {
            if (view instanceof MotionLayout) {
                ((MotionLayout) view).setProgress(get(t, time, view, cache));
            } else {
                if (mNoMethod) {
                    return false;
                }
                Method method = null;
                try {
                    method = view.getClass().getMethod("setProgress", Float.TYPE);
                } catch (NoSuchMethodException e) {
                    mNoMethod = true;
                }
                if (method != null) {
                    try {
                        method.invoke(view, get(t, time, view, cache));
                    } catch (IllegalAccessException e) {
                        Log.e(TAG, "unable to setProgress", e);
                    } catch (InvocationTargetException e) {
                        Log.e(TAG, "unable to setProgress", e);
                    }
                }
            }
            return mContinue;
        }
    }
}