public class

FadeAndShortSlide

extends Visibility

 java.lang.Object

↳Visibility

↳androidx.leanback.transition.FadeAndShortSlide

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.transition.FadeAndShortSlide android.support.v17.leanback.transition.FadeAndShortSlide

Overview

Execute horizontal slide of 1/4 width and fade (to workaround bug 23718734)

Summary

Constructors
publicFadeAndShortSlide()

publicFadeAndShortSlide(Context context, AttributeSet attrs)

publicFadeAndShortSlide(int slideEdge)

Methods
public TransitionaddListener(TransitionListener listener)

public voidcaptureEndValues(TransitionValues transitionValues)

public voidcaptureStartValues(TransitionValues transitionValues)

public Transitionclone()

public floatgetDistance()

Returns distance to slide.

public AnimatoronAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)

public AnimatoronDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)

public TransitionremoveListener(TransitionListener listener)

public voidsetDistance(float distance)

Set distance to slide, default value is -1.

public voidsetEpicenterCallback(EpicenterCallback epicenterCallback)

public voidsetSlideEdge(int slideEdge)

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

Constructors

public FadeAndShortSlide()

public FadeAndShortSlide(int slideEdge)

public FadeAndShortSlide(Context context, AttributeSet attrs)

Methods

public void setEpicenterCallback(EpicenterCallback epicenterCallback)

public void captureStartValues(TransitionValues transitionValues)

public void captureEndValues(TransitionValues transitionValues)

public void setSlideEdge(int slideEdge)

public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)

public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)

public Transition addListener(TransitionListener listener)

public Transition removeListener(TransitionListener listener)

public float getDistance()

Returns distance to slide. When negative value is returned, it will use 1/4 of sceneRoot dimension.

public void setDistance(float distance)

Set distance to slide, default value is -1. when negative value is set, it will use 1/4 of sceneRoot dimension.

Parameters:

distance: Pixels to slide.

public Transition clone()

Source

/*
 * Copyright (C) 2015 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.transition;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.transition.Fade;
import android.transition.Transition;
import android.transition.TransitionValues;
import android.transition.Visibility;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.leanback.R;

/**
 * Execute horizontal slide of 1/4 width and fade (to workaround bug 23718734)
 * @hide
 */
@RequiresApi(21)
@RestrictTo(LIBRARY_GROUP_PREFIX)
public class FadeAndShortSlide extends Visibility {

    private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
    // private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
    private static final String PROPNAME_SCREEN_POSITION =
            "android:fadeAndShortSlideTransition:screenPosition";

    private CalculateSlide mSlideCalculator;
    private Visibility mFade = new Fade();
    private float mDistance = -1;

    private static abstract class CalculateSlide {

        CalculateSlide() {
        }

        /** Returns the translation X value for view when it goes out of the scene */
        float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            return view.getTranslationX();
        }

        /** Returns the translation Y value for view when it goes out of the scene */
        float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            return view.getTranslationY();
        }
    }

    float getHorizontalDistance(ViewGroup sceneRoot) {
        return mDistance >= 0 ? mDistance : (sceneRoot.getWidth() / 4);
    }

    float getVerticalDistance(ViewGroup sceneRoot) {
        return mDistance >= 0 ? mDistance : (sceneRoot.getHeight() / 4);
    }

    final static CalculateSlide sCalculateStart = new CalculateSlide() {
        @Override
        public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
            final float x;
            if (isRtl) {
                x = view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
            } else {
                x = view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
            }
            return x;
        }
    };

    final static CalculateSlide sCalculateEnd = new CalculateSlide() {
        @Override
        public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
            final float x;
            if (isRtl) {
                x = view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
            } else {
                x = view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
            }
            return x;
        }
    };

    final static CalculateSlide sCalculateStartEnd = new CalculateSlide() {
        @Override
        public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            final int viewCenter = position[0] + view.getWidth() / 2;
            sceneRoot.getLocationOnScreen(position);
            Rect center = t.getEpicenter();
            final int sceneRootCenter = center == null ? (position[0] + sceneRoot.getWidth() / 2)
                    : center.centerX();
            if (viewCenter < sceneRootCenter) {
                return view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
            } else {
                return view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
            }
        }
    };

    final static CalculateSlide sCalculateBottom = new CalculateSlide() {
        @Override
        public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            return view.getTranslationY() + t.getVerticalDistance(sceneRoot);
        }
    };

    final static CalculateSlide sCalculateTop = new CalculateSlide() {
        @Override
        public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            return view.getTranslationY() - t.getVerticalDistance(sceneRoot);
        }
    };

    final CalculateSlide sCalculateTopBottom = new CalculateSlide() {
        @Override
        public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
            final int viewCenter = position[1] + view.getHeight() / 2;
            sceneRoot.getLocationOnScreen(position);
            Rect center = getEpicenter();
            final int sceneRootCenter = center == null ? (position[1] + sceneRoot.getHeight() / 2)
                    : center.centerY();
            if (viewCenter < sceneRootCenter) {
                return view.getTranslationY() - t.getVerticalDistance(sceneRoot);
            } else {
                return view.getTranslationY() + t.getVerticalDistance(sceneRoot);
            }
        }
    };

    public FadeAndShortSlide() {
        this(Gravity.START);
    }

    public FadeAndShortSlide(int slideEdge) {
        setSlideEdge(slideEdge);
    }

    public FadeAndShortSlide(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSlide);
        int edge = a.getInt(R.styleable.lbSlide_lb_slideEdge, Gravity.START);
        setSlideEdge(edge);
        a.recycle();
    }

    @Override
    public void setEpicenterCallback(EpicenterCallback epicenterCallback) {
        mFade.setEpicenterCallback(epicenterCallback);
        super.setEpicenterCallback(epicenterCallback);
    }

    private void captureValues(TransitionValues transitionValues) {
        View view = transitionValues.view;
        int[] position = new int[2];
        view.getLocationOnScreen(position);
        transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
    }

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        mFade.captureStartValues(transitionValues);
        super.captureStartValues(transitionValues);
        captureValues(transitionValues);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        mFade.captureEndValues(transitionValues);
        super.captureEndValues(transitionValues);
        captureValues(transitionValues);
    }

    public void setSlideEdge(int slideEdge) {
        switch (slideEdge) {
            case Gravity.START:
                mSlideCalculator = sCalculateStart;
                break;
            case Gravity.END:
                mSlideCalculator = sCalculateEnd;
                break;
            case Gravity.START | Gravity.END:
                mSlideCalculator = sCalculateStartEnd;
                break;
            case Gravity.TOP:
                mSlideCalculator = sCalculateTop;
                break;
            case Gravity.BOTTOM:
                mSlideCalculator = sCalculateBottom;
                break;
            case Gravity.TOP | Gravity.BOTTOM:
                mSlideCalculator = sCalculateTopBottom;
                break;
            default:
                throw new IllegalArgumentException("Invalid slide direction");
        }
    }

    @Override
    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
            TransitionValues endValues) {
        if (endValues == null) {
            return null;
        }
        if (sceneRoot == view) {
            // workaround b/25375640, avoid run animation on sceneRoot
            return null;
        }
        int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
        int left = position[0];
        int top = position[1];
        float endX = view.getTranslationX();
        float startX = mSlideCalculator.getGoneX(this, sceneRoot, view, position);
        float endY = view.getTranslationY();
        float startY = mSlideCalculator.getGoneY(this, sceneRoot, view, position);
        final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view, endValues,
                left, top, startX, startY, endX, endY, sDecelerate, this);
        final Animator fadeAnimator = mFade.onAppear(sceneRoot, view, startValues, endValues);
        if (slideAnimator == null) {
            return fadeAnimator;
        } else if (fadeAnimator == null) {
            return slideAnimator;
        }
        final AnimatorSet set = new AnimatorSet();
        set.play(slideAnimator).with(fadeAnimator);

        return set;
    }

    @Override
    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
            TransitionValues endValues) {
        if (startValues == null) {
            return null;
        }
        if (sceneRoot == view) {
            // workaround b/25375640, avoid run animation on sceneRoot
            return null;
        }
        int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
        int left = position[0];
        int top = position[1];
        float startX = view.getTranslationX();
        float endX = mSlideCalculator.getGoneX(this, sceneRoot, view, position);
        float startY = view.getTranslationY();
        float endY = mSlideCalculator.getGoneY(this, sceneRoot, view, position);
        final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view,
                startValues, left, top, startX, startY, endX, endY, sDecelerate /* sAccelerate */,
                this);
        final Animator fadeAnimator = mFade.onDisappear(sceneRoot, view, startValues, endValues);
        if (slideAnimator == null) {
            return fadeAnimator;
        } else if (fadeAnimator == null) {
            return slideAnimator;
        }
        final AnimatorSet set = new AnimatorSet();
        set.play(slideAnimator).with(fadeAnimator);

        return set;
    }

    @Override
    public Transition addListener(TransitionListener listener) {
        mFade.addListener(listener);
        return super.addListener(listener);
    }

    @Override
    public Transition removeListener(TransitionListener listener) {
        mFade.removeListener(listener);
        return super.removeListener(listener);
    }

    /**
     * Returns distance to slide.  When negative value is returned, it will use 1/4 of
     * sceneRoot dimension.
     */
    public float getDistance() {
        return mDistance;
    }

    /**
     * Set distance to slide, default value is -1.  when negative value is set, it will use 1/4 of
     * sceneRoot dimension.
     * @param distance Pixels to slide.
     */
    public void setDistance(float distance) {
        mDistance = distance;
    }

    @Override
    public Transition clone() {
        FadeAndShortSlide clone = (FadeAndShortSlide) super.clone();
        clone.mFade = (Visibility) mFade.clone();
        return clone;
    }
}