public abstract class

Parallax<PropertyT extends android.util.Property>

extends java.lang.Object

 java.lang.Object

↳androidx.leanback.widget.Parallax<PropertyT>

Subclasses:

DetailsParallax, RecyclerViewParallax

Gradle dependencies

compile group: 'androidx.leanback', name: 'leanback', version: '1.2.0-alpha02'

  • groupId: androidx.leanback
  • artifactId: leanback
  • version: 1.2.0-alpha02

Artifact androidx.leanback:leanback:1.2.0-alpha02 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.leanback:leanback com.android.support:leanback-v17

Androidx class mapping:

androidx.leanback.widget.Parallax android.support.v17.leanback.widget.Parallax

Overview

Parallax tracks a list of dynamic s typically representing foreground UI element positions on screen. Parallax keeps a list of ParallaxEffect objects which define rules to mapping property values to ParallaxTarget.

Example: // when Property "var1" changes from 15 to max value, perform parallax effect to // change myView's translationY from 0 to 100. Parallax parallax = new Parallax() {...}; p1 = parallax.addProperty("var1"); parallax.addEffect(p1.at(15), p1.atMax()) .target(myView, PropertyValuesHolder.ofFloat("translationY", 0, 100));

To create a ParallaxEffect, user calls Parallax.addEffect(Parallax.PropertyMarkerValue...) with a list of Parallax.PropertyMarkerValue which defines the range of Parallax.IntProperty or Parallax.FloatProperty. Then user adds ParallaxTarget into ParallaxEffect.

App may subclass Parallax.IntProperty or Parallax.FloatProperty to supply additional information about how to retrieve Property value. RecyclerViewParallax is a great example of Parallax implementation tracking child view positions on screen.

Restrictions of properties

  • FloatProperty and IntProperty cannot be mixed in one Parallax
  • Values must be in ascending order.
  • If the UI element is unknown above screen, use UNKNOWN_BEFORE.
  • if the UI element is unknown below screen, use UNKNOWN_AFTER.
  • UNKNOWN_BEFORE and UNKNOWN_AFTER are not allowed to be next to each other.
These rules will be verified at runtime.

Subclass must override Parallax.updateValues() to update property values and perform ParallaxEffects. Subclass may call Parallax.updateValues() automatically e.g. RecyclerViewParallax calls Parallax.updateValues() in RecyclerView scrolling. App might call Parallax.updateValues() manually when Parallax is unaware of the value change. For example, when a slide transition is running, RecyclerViewParallax is unaware of translation value changes; it's the app's responsibility to call Parallax.updateValues() in every frame of animation.

Summary

Constructors
publicParallax()

Methods
public ParallaxEffectaddEffect(Parallax.PropertyMarkerValue ranges[])

Create a ParallaxEffect object that will track source variable changes within a provided set of ranges.

public final android.util.PropertyaddProperty(java.lang.String name)

Add a new IntProperty in the Parallax object.

public abstract android.util.PropertycreateProperty(java.lang.String name, int index)

Create a new Property object.

public java.util.List<ParallaxEffect>getEffects()

Returns a list of ParallaxEffect object which defines rules to perform mapping to multiple ParallaxTargets.

public abstract floatgetMaxValue()

Return the max value which is typically size of parent visible area, e.g.

public final java.util.List<android.util.Property>getProperties()

public voidremoveAllEffects()

Remove all ParallaxEffect objects.

public voidremoveEffect(ParallaxEffect effect)

Remove the ParallaxEffect object.

public voidupdateValues()

Update property values and perform ParallaxEffects.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public Parallax()

Methods

public abstract float getMaxValue()

Return the max value which is typically size of parent visible area, e.g. RecyclerView's height if we are tracking Y position of a child. The size can be used to calculate marker value using the provided fraction of FloatPropertyMarkerValue.

Returns:

Size of parent visible area.

public final android.util.Property addProperty(java.lang.String name)

Add a new IntProperty in the Parallax object. App may override Parallax.createProperty(String, int).

Parameters:

name: Name of the property.

Returns:

Newly created Property object.

See also: Parallax.createProperty(String, int)

public final java.util.List<android.util.Property> getProperties()

Returns:

A unmodifiable list of properties.

public abstract android.util.Property createProperty(java.lang.String name, int index)

Create a new Property object. App does not directly call this method. See Parallax.addProperty(String).

Parameters:

index: Index of the property in this Parallax object.

Returns:

Newly created Property object.

public void updateValues()

Update property values and perform ParallaxEffects. Subclass may override and call super.updateValues() after updated properties values.

public java.util.List<ParallaxEffect> getEffects()

Returns a list of ParallaxEffect object which defines rules to perform mapping to multiple ParallaxTargets.

Returns:

A list of ParallaxEffect object.

public void removeEffect(ParallaxEffect effect)

Remove the ParallaxEffect object.

Parameters:

effect: The ParallaxEffect object to remove.

public void removeAllEffects()

Remove all ParallaxEffect objects.

public ParallaxEffect addEffect(Parallax.PropertyMarkerValue ranges[])

Create a ParallaxEffect object that will track source variable changes within a provided set of ranges.

Parameters:

ranges: A list of marker values that defines the ranges.

Returns:

Newly created ParallaxEffect object.

Source

/*
 * Copyright (C) 2016 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.leanback.widget;

import android.util.Property;

import androidx.annotation.CallSuper;
import androidx.leanback.widget.ParallaxEffect.FloatEffect;
import androidx.leanback.widget.ParallaxEffect.IntEffect;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Parallax tracks a list of dynamic {@link Property}s typically representing foreground UI
 * element positions on screen. Parallax keeps a list of {@link ParallaxEffect} objects which define
 * rules to mapping property values to {@link ParallaxTarget}.
 *
 * <p>
 * Example:
 * <code>
 *     // when Property "var1" changes from 15 to max value, perform parallax effect to
 *     // change myView's translationY from 0 to 100.
 *     Parallax<IntProperty> parallax = new Parallax<IntProperty>() {...};
 *     p1 = parallax.addProperty("var1");
 *     parallax.addEffect(p1.at(15), p1.atMax())
 *             .target(myView, PropertyValuesHolder.ofFloat("translationY", 0, 100));
 * </code>
 * </p>
 *
 * <p>
 * To create a {@link ParallaxEffect}, user calls {@link #addEffect(PropertyMarkerValue[])} with a
 * list of {@link PropertyMarkerValue} which defines the range of {@link Parallax.IntProperty} or
 * {@link Parallax.FloatProperty}. Then user adds {@link ParallaxTarget} into
 * {@link ParallaxEffect}.
 * </p>
 * <p>
 * App may subclass {@link Parallax.IntProperty} or {@link Parallax.FloatProperty} to supply
 * additional information about how to retrieve Property value.  {@link RecyclerViewParallax} is
 * a great example of Parallax implementation tracking child view positions on screen.
 * </p>
 * <p>
 * Restrictions of properties
 * <ul>
 * <li>FloatProperty and IntProperty cannot be mixed in one Parallax</li>
 * <li>Values must be in ascending order.</li>
 * <li>If the UI element is unknown above screen, use UNKNOWN_BEFORE.</li>
 * <li>if the UI element is unknown below screen, use UNKNOWN_AFTER.</li>
 * <li>UNKNOWN_BEFORE and UNKNOWN_AFTER are not allowed to be next to each other.</li>
 * </ul>
 * These rules will be verified at runtime.
 * </p>
 * <p>
 * Subclass must override {@link #updateValues()} to update property values and perform
 * {@link ParallaxEffect}s. Subclass may call {@link #updateValues()} automatically e.g.
 * {@link RecyclerViewParallax} calls {@link #updateValues()} in RecyclerView scrolling. App might
 * call {@link #updateValues()} manually when Parallax is unaware of the value change. For example,
 * when a slide transition is running, {@link RecyclerViewParallax} is unaware of translation value
 * changes; it's the app's responsibility to call {@link #updateValues()} in every frame of
 * animation.
 * </p>
 * @param <PropertyT> Subclass of {@link Parallax.IntProperty} or {@link Parallax.FloatProperty}
 */
public abstract class Parallax<PropertyT extends android.util.Property> {

    /**
     * Class holding a fixed value for a Property in {@link Parallax}.
     * @param <PropertyT> Class of the property, e.g. {@link IntProperty} or {@link FloatProperty}.
     */
    public static class PropertyMarkerValue<PropertyT> {
        private final PropertyT mProperty;

        public PropertyMarkerValue(PropertyT property) {
            mProperty = property;
        }

        /**
         * @return Associated property.
         */
        public PropertyT getProperty() {
            return mProperty;
        }
    }

    /**
     * IntProperty provide access to an index based integer type property inside
     * {@link Parallax}. The IntProperty typically represents UI element position inside
     * {@link Parallax}.
     */
    public static class IntProperty extends Property<Parallax, Integer> {

        /**
         * Property value is unknown and it's smaller than minimal value of Parallax. For
         * example if a child is not created and before the first visible child of RecyclerView.
         */
        public static final int UNKNOWN_BEFORE = Integer.MIN_VALUE;

        /**
         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
         * example if a child is not created and after the last visible child of RecyclerView.
         */
        public static final int UNKNOWN_AFTER = Integer.MAX_VALUE;

        private final int mIndex;

        /**
         * Constructor.
         *
         * @param name Name of this Property.
         * @param index Index of this Property inside {@link Parallax}.
         */
        public IntProperty(String name, int index) {
            super(Integer.class, name);
            mIndex = index;
        }

        @Override
        public final Integer get(Parallax object) {
            return object.getIntPropertyValue(mIndex);
        }

        @Override
        public final void set(Parallax object, Integer value) {
            object.setIntPropertyValue(mIndex, value);
        }

        /**
         * @return Index of this Property in {@link Parallax}.
         */
        public final int getIndex() {
            return mIndex;
        }

        /**
         * Fast version of get() method that returns a primitive int value of the Property.
         * @param object The Parallax object that owns this Property.
         * @return Int value of the Property.
         */
        public final int getValue(Parallax object) {
            return object.getIntPropertyValue(mIndex);
        }

        /**
         * Fast version of set() method that takes a primitive int value into the Property.
         *
         * @param object The Parallax object that owns this Property.
         * @param value Int value of the Property.
         */
        public final void setValue(Parallax object, int value) {
            object.setIntPropertyValue(mIndex, value);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
         *
         * @param absoluteValue The integer marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atAbsolute(int absoluteValue) {
            return new IntPropertyMarkerValue(this, absoluteValue, 0f);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the marker value representing
         * {@link Parallax#getMaxValue()}.
         *
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atMax() {
            return new IntPropertyMarkerValue(this, 0, 1f);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
         *
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atMin() {
            return new IntPropertyMarkerValue(this, 0);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for a fraction of
         * {@link Parallax#getMaxValue()}.
         *
         * @param fractionOfMaxValue 0 to 1 fraction to multiply with
         *                                       {@link Parallax#getMaxValue()} for
         *                                       the marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atFraction(float fractionOfMaxValue) {
            return new IntPropertyMarkerValue(this, 0, fractionOfMaxValue);
        }

        /**
         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
         *
         * @param offsetValue                    An offset integer value to be added to marker
         *                                       value.
         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
         *                                       {@link Parallax#getMaxValue()} for
         *                                       the marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue at(int offsetValue,
                float fractionOfMaxParentVisibleSize) {
            return new IntPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
        }
    }

    /**
     * Implementation of {@link PropertyMarkerValue} for {@link IntProperty}.
     */
    static class IntPropertyMarkerValue extends PropertyMarkerValue<IntProperty> {
        private final int mValue;
        private final float mFactionOfMax;

        IntPropertyMarkerValue(IntProperty property, int value) {
            this(property, value, 0f);
        }

        IntPropertyMarkerValue(IntProperty property, int value, float fractionOfMax) {
            super(property);
            mValue = value;
            mFactionOfMax = fractionOfMax;
        }

        /**
         * @return The marker value of integer type.
         */
        final int getMarkerValue(Parallax source) {
            return mFactionOfMax == 0 ? mValue : mValue + Math.round(source
                    .getMaxValue() * mFactionOfMax);
        }
    }

    /**
     * FloatProperty provide access to an index based integer type property inside
     * {@link Parallax}. The FloatProperty typically represents UI element position inside
     * {@link Parallax}.
     */
    public static class FloatProperty extends Property<Parallax, Float> {

        /**
         * Property value is unknown and it's smaller than minimal value of Parallax. For
         * example if a child is not created and before the first visible child of RecyclerView.
         */
        public static final float UNKNOWN_BEFORE = -Float.MAX_VALUE;

        /**
         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
         * example if a child is not created and after the last visible child of RecyclerView.
         */
        public static final float UNKNOWN_AFTER = Float.MAX_VALUE;

        private final int mIndex;

        /**
         * Constructor.
         *
         * @param name Name of this Property.
         * @param index Index of this Property inside {@link Parallax}.
         */
        public FloatProperty(String name, int index) {
            super(Float.class, name);
            mIndex = index;
        }

        @Override
        public final Float get(Parallax object) {
            return object.getFloatPropertyValue(mIndex);
        }

        @Override
        public final void set(Parallax object, Float value) {
            object.setFloatPropertyValue(mIndex, value);
        }

        /**
         * @return Index of this Property in {@link Parallax}.
         */
        public final int getIndex() {
            return mIndex;
        }

        /**
         * Fast version of get() method that returns a primitive int value of the Property.
         * @param object The Parallax object that owns this Property.
         * @return Float value of the Property.
         */
        public final float getValue(Parallax object) {
            return object.getFloatPropertyValue(mIndex);
        }

        /**
         * Fast version of set() method that takes a primitive float value into the Property.
         *
         * @param object The Parallax object that owns this Property.
         * @param value Float value of the Property.
         */
        public final void setValue(Parallax object, float value) {
            object.setFloatPropertyValue(mIndex, value);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
         *
         * @param markerValue The float marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atAbsolute(float markerValue) {
            return new FloatPropertyMarkerValue(this, markerValue, 0f);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the marker value representing
         * {@link Parallax#getMaxValue()}.
         *
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atMax() {
            return new FloatPropertyMarkerValue(this, 0, 1f);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
         *
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atMin() {
            return new FloatPropertyMarkerValue(this, 0);
        }

        /**
         * Creates an {@link PropertyMarkerValue} object for a fraction of
         * {@link Parallax#getMaxValue()}.
         *
         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
         *                                       {@link Parallax#getMaxValue()} for
         *                                       the marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue atFraction(float fractionOfMaxParentVisibleSize) {
            return new FloatPropertyMarkerValue(this, 0, fractionOfMaxParentVisibleSize);
        }

        /**
         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
         *
         * @param offsetValue                    An offset float value to be added to marker value.
         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
         *                                       {@link Parallax#getMaxValue()} for
         *                                       the marker value.
         * @return A new {@link PropertyMarkerValue} object.
         */
        public final PropertyMarkerValue at(float offsetValue,
                float fractionOfMaxParentVisibleSize) {
            return new FloatPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
        }
    }

    /**
     * Implementation of {@link PropertyMarkerValue} for {@link FloatProperty}.
     */
    static class FloatPropertyMarkerValue extends PropertyMarkerValue<FloatProperty> {
        private final float mValue;
        private final float mFactionOfMax;

        FloatPropertyMarkerValue(FloatProperty property, float value) {
            this(property, value, 0f);
        }

        FloatPropertyMarkerValue(FloatProperty property, float value, float fractionOfMax) {
            super(property);
            mValue = value;
            mFactionOfMax = fractionOfMax;
        }

        /**
         * @return The marker value.
         */
        final float getMarkerValue(Parallax source) {
            return mFactionOfMax == 0 ? mValue : mValue + source.getMaxValue()
                    * mFactionOfMax;
        }
    }

    final List<PropertyT> mProperties = new ArrayList<PropertyT>();
    final List<PropertyT> mPropertiesReadOnly = Collections.unmodifiableList(mProperties);

    private int[] mValues = new int[4];
    private float[] mFloatValues = new float[4];

    private final List<ParallaxEffect> mEffects = new ArrayList<ParallaxEffect>(4);

    /**
     * Return the max value which is typically size of parent visible area, e.g. RecyclerView's
     * height if we are tracking Y position of a child. The size can be used to calculate marker
     * value using the provided fraction of FloatPropertyMarkerValue.
     *
     * @return Size of parent visible area.
     */
    public abstract float getMaxValue();

    /**
     * Get index based property value.
     *
     * @param index Index of the property.
     * @return Value of the property.
     */
    final int getIntPropertyValue(int index) {
        return mValues[index];
    }

    /**
     * Set index based property value.
     *
     * @param index Index of the property.
     * @param value Value of the property.
     */
    final void setIntPropertyValue(int index, int value) {
        if (index >= mProperties.size()) {
            throw new ArrayIndexOutOfBoundsException();
        }
        mValues[index] = value;
    }

    /**
     * Add a new IntProperty in the Parallax object. App may override
     * {@link #createProperty(String, int)}.
     *
     * @param name Name of the property.
     * @return Newly created Property object.
     * @see #createProperty(String, int)
     */
    public final PropertyT addProperty(String name) {
        int newPropertyIndex = mProperties.size();
        PropertyT property = createProperty(name, newPropertyIndex);
        if (property instanceof IntProperty) {
            int size = mValues.length;
            if (size == newPropertyIndex) {
                int[] newValues = new int[size * 2];
                for (int i = 0; i < size; i++) {
                    newValues[i] = mValues[i];
                }
                mValues = newValues;
            }
            mValues[newPropertyIndex] = IntProperty.UNKNOWN_AFTER;
        } else if (property instanceof FloatProperty) {
            int size = mFloatValues.length;
            if (size == newPropertyIndex) {
                float[] newValues = new float[size * 2];
                for (int i = 0; i < size; i++) {
                    newValues[i] = mFloatValues[i];
                }
                mFloatValues = newValues;
            }
            mFloatValues[newPropertyIndex] = FloatProperty.UNKNOWN_AFTER;
        } else {
            throw new IllegalArgumentException("Invalid Property type");
        }
        mProperties.add(property);
        return property;
    }

    /**
     * Verify sanity of property values, throws RuntimeException if fails. The property values
     * must be in ascending order. UNKNOW_BEFORE and UNKNOWN_AFTER are not allowed to be next to
     * each other.
     */
    void verifyIntProperties() throws IllegalStateException {
        if (mProperties.size() < 2) {
            return;
        }
        int last = getIntPropertyValue(0);
        for (int i = 1; i < mProperties.size(); i++) {
            int v = getIntPropertyValue(i);
            if (v < last) {
                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
                                + " smaller than Property[%d]\"%s\"",
                        i, mProperties.get(i).getName(),
                        i - 1, mProperties.get(i - 1).getName()));
            } else if (last == IntProperty.UNKNOWN_BEFORE && v == IntProperty.UNKNOWN_AFTER) {
                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
                        i - 1, mProperties.get(i - 1).getName(),
                        i, mProperties.get(i).getName()));
            }
            last = v;
        }
    }

    final void verifyFloatProperties() throws IllegalStateException {
        if (mProperties.size() < 2) {
            return;
        }
        float last = getFloatPropertyValue(0);
        for (int i = 1; i < mProperties.size(); i++) {
            float v = getFloatPropertyValue(i);
            if (v < last) {
                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
                                + " smaller than Property[%d]\"%s\"",
                        i, mProperties.get(i).getName(),
                        i - 1, mProperties.get(i - 1).getName()));
            } else if (last == FloatProperty.UNKNOWN_BEFORE && v
                    == FloatProperty.UNKNOWN_AFTER) {
                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
                        i - 1, mProperties.get(i - 1).getName(),
                        i, mProperties.get(i).getName()));
            }
            last = v;
        }
    }

    /**
     * Get index based property value.
     *
     * @param index Index of the property.
     * @return Value of the property.
     */
    final float getFloatPropertyValue(int index) {
        return mFloatValues[index];
    }

    /**
     * Set index based property value.
     *
     * @param index Index of the property.
     * @param value Value of the property.
     */
    final void setFloatPropertyValue(int index, float value) {
        if (index >= mProperties.size()) {
            throw new ArrayIndexOutOfBoundsException();
        }
        mFloatValues[index] = value;
    }

    /**
     * @return A unmodifiable list of properties.
     */
    public final List<PropertyT> getProperties() {
        return mPropertiesReadOnly;
    }

    /**
     * Create a new Property object. App does not directly call this method.  See
     * {@link #addProperty(String)}.
     *
     * @param index  Index of the property in this Parallax object.
     * @return Newly created Property object.
     */
    public abstract PropertyT createProperty(String name, int index);

    /**
     * Update property values and perform {@link ParallaxEffect}s. Subclass may override and call
     * super.updateValues() after updated properties values.
     */
    @CallSuper
    public void updateValues() {
        for (int i = 0; i < mEffects.size(); i++) {
            mEffects.get(i).performMapping(this);
        }
    }

    /**
     * Returns a list of {@link ParallaxEffect} object which defines rules to perform mapping to
     * multiple {@link ParallaxTarget}s.
     *
     * @return A list of {@link ParallaxEffect} object.
     */
    public List<ParallaxEffect> getEffects() {
        return mEffects;
    }

    /**
     * Remove the {@link ParallaxEffect} object.
     *
     * @param effect The {@link ParallaxEffect} object to remove.
     */
    public void removeEffect(ParallaxEffect effect) {
        mEffects.remove(effect);
    }

    /**
     * Remove all {@link ParallaxEffect} objects.
     */
    public void removeAllEffects() {
        mEffects.clear();
    }

    /**
     * Create a {@link ParallaxEffect} object that will track source variable changes within a
     * provided set of ranges.
     *
     * @param ranges A list of marker values that defines the ranges.
     * @return Newly created ParallaxEffect object.
     */
    public ParallaxEffect addEffect(PropertyMarkerValue... ranges) {
        ParallaxEffect effect;
        if (ranges[0].getProperty() instanceof IntProperty) {
            effect = new IntEffect();
        } else {
            effect = new FloatEffect();
        }
        effect.setPropertyRanges(ranges);
        mEffects.add(effect);
        return effect;
    }

}