1 overridePendingTransiton

Android2.0 introduces transition animation for the entire Activity interface.

1.1 the use of

Called immediately after startActivity

startActivity(new Intent(this,MainActivity2.class));
// Pass in the animation resource ID, where the animation is the tween in the view animation
// Parameter 1: the animation of the incoming Activity
// Parameter 2: The animation of the exiting Activity
overridePendingTransition(R.anim.up,R.anim.down);
Copy the code

#R.anim.up


      
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:toYDelta="0"
        android:fromYDelta="100%"
        android:duration="2000"/>
</set>
Copy the code

#R.anim.down

<? xml version="1.0" encoding="utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:toYDelta="100%"
        android:fromYDelta="0"
        android:duration="2000"/>
</set>
Copy the code

2 ActivityOptions

ActivityOptions is a helper class for starting an Activity that sets options about how to start the Activity. When used, it is converted to a Bundle object and passed into the startActivities method.

#Context.java

public abstract void startActivities(@RequiresPermission Intent[] intents, Bundle options);
Copy the code

The ActivityOptions class provides the following static methods to set the transition of an Activity. These methods return an ActivityOptions object.

The method name instructions
makeClipRevealAnimation(View source, int startX, int startY, int width, int height) Start with a point at the center of the expose
makeCustomAnimation(Context context, int enterResId, int exitResId) similaroverridePendingTransition
makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY) Zoom in aBitmapTo transition
makeScaleUpAnimation(View source, int startX, int startY, int width, int height) Start zooming in on a point
** makeSceneTransitionAnimation(Activity activity)** No shared element transition animation
** makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)** Transition animation of a single shared element
** makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)** Transition animation of multiple shared elements

The most commonly used is the last three methods, the three methods will be set up before and after the Activity Shared between elements, so that we can after the Shared elements and unshared elements (it should be said that in addition to sharing elements of elements, the article unified with a Shared element generation refers to elements other than sharing elements 】) set different animation effects.

2.1 Setting Shared Elements

No shared element

startActivity(
        new Intent(this,MainActivity1.class), 
        ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
);
Copy the code

Single shared element

startActivity(
    new Intent(
        this,
        MainActivity2.class
    ),
    ActivityOptions.makeSceneTransitionAnimation(this,buttonMoveUp,"b1").toBundle()
);
Copy the code

Multi-shared elements

startActivity(
    new Intent(
        this,
        MainActivity3.class
    ),
    ActivityOptions.makeSceneTransitionAnimation(
        this,
        Pair.create(buttonMoveUp,"b1"), // The View is set as a shared element, and the View is named
        Pair.create(buttonShare,"b2")
    ).toBundle()
);
Copy the code

2.2 What is Transition

MakeSceneTransitionAnimation () can know from the method name, used the Transition to complete the transformation between the two scenarios. Android 5.0 introduced Transition. Transition is used for UI transitions between two scenes. It captures the state of each View in the beginning scene and the end scene, and then creates an Animator to Transition between the two scenes.

2.3 Setting non-shared Animation Effects

Also called setting content transition animation, this is to set the animation effect of elements other than shared elements.

#Window.java

The method name instructions
void setEnterTransition(Transition transition) You can think of it as an admission animation of a non-shared element when you create an Activity
void setReturnTransition(Transition transition) Think of it as an exit animation of a non-shared element when the Activity is destroyed
void setReenterTransition(Transition transition) This can be interpreted as an entry animation of unshared elements when an Activity returns to the foreground from the background
void setExitTransition(Transition transition) Can be understood as the Activity from the foreground to the background of the unshared element exit animation

2.4 Set the animation effect of shared elements

#Window.java

The method name instructions
void setSharedElementEnterTransition(Transition transition) You can think of it as an entry animation that shares elements when creating an Activity
void setSharedElementReturnTransition(Transition transition) Think of it as an exit animation of shared elements when an Activity is destroyed
void setSharedElementReenterTransition(Transition transition) This can be interpreted as an entry animation of shared elements when an Activity returns to the foreground from the background
void setSharedElementExitTransition(Transition transition) Can be understood as the Activity from the foreground to the background shared element exit animation

2.5 Transition Provided by the System

The following Transition is usually used to animate shared elements.

Because shared elements are a process of going from something to something, while non-shared elements are a process of going from nothing to something or from something to nothing, the Transition provided by the system is different.

The name of the class instructions
ChangeBounds Change layout boundaries in transformations, that is, change the size and position of the View
ChangeClipBounds Change in transformationView#getClipBounds()The value of thatCanvasWithin the scope ofViewThe boundary.
ChangeImageTransform Change in transformationImageViewtheMartixWhile completing the animation, that is, changing the size position.
ChangeTransform Change in transformationViewScale and rotate values of
ChangeScroll(API 23, Android M required) Change in transformationViewaboutScrollAssociated attribute values

2.6 System Visibility

Visibility inherits Transition, so the system’s own Transition Visibility also belongs to the system’s own Transition. The following transitions are usually used to set animation effects for non-shared elements.

The name of the class instructions
Explode The decomposition/aggregation animation, if no epicenter is provided, moves in/out of the focus View and the midpoint of the View.
Fade Fade in/out animation
Slide Slide in/slide out animation

2.7 Usage Examples

Refer to the previous Settings in the startActivity code section.

  • Non-shared element transition animation

#MainActivity

Slide slideExit = new Slide();
slideExit.setDuration(2000);
slideExit.setSlideEdge(Gravity.START);
// Animations of unshared elements that retreat from the foreground to the background
getWindow().setExitTransition(slideExit);
Copy the code

#MainActivity2

// Set whether the animation overlaps. True will execute the entry animation as soon as possible, so that it may overlap with the exit animation. False will wait for the exit animation to finish before performing the entry animation.
getWindow().setAllowEnterTransitionOverlap(false);
// Animation of non-shared elements coming into play when creating Activty
Slide slideEnter = new Slide();
slideEnter.setDuration(2000);
slideEnter.setSlideEdge(Gravity.END);
getWindow().setEnterTransition(slideEnter);

//postponeEnterTransition(); // Delay the entry animation start
//startPostponedEnterTransition(); // Start the delayed entry animation
Copy the code
  • Shared element transition animation
ChangeBounds changeBounds = new ChangeBounds();
ChangeClipBounds changeClipBounds = new ChangeClipBounds();
ChangeTransform changeTransform = new ChangeTransform();
ChangeImageTransform changeImageTransform = new ChangeImageTransform();

TransitionSet inherits Transition, which is used to set multiple transitions at once
TransitionSet transitionSet = new TransitionSet();
transitionSet.addTransition(changeImageTransform);
transitionSet.addTransition(changeBounds);
transitionSet.addTransition(changeClipBounds);
transitionSet.addTransition(changeTransform);
transitionSet.setDuration(2000);

// Sets the shared element animation when creating the Activity
getWindow().setSharedElementEnterTransition(transitionSet);
Copy the code

The reference to TransitionSet adds a built-in TransitionSet

#AutoTransition.java

public class AutoTransition extends TransitionSet {
    public AutoTransition(a) {
        init();
    }
    public AutoTransition(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init(a) {
        setOrdering(ORDERING_SEQUENTIAL);
        addTransition(new Fade(Fade.OUT)).
                addTransition(new ChangeBounds()).
                addTransition(newFade(Fade.IN)); }}Copy the code

3 Custom transition animation

3.1 Custom Transition

public class TestTransition extends Transition {
    @Override
    public void captureStartValues(TransitionValues transitionValues) {
      	// This method is used to get the starting state
      	/ / we're through to the transitionValues. Values. Submit began to state the value of the put method
				/ / transitionValues. Values is a ArrayMap < String, Object >
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
				// This method is used to get the value of the end state
    }

    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        return super.createAnimator(sceneRoot, startValues, endValues);
      	//startValues TransitionValues corresponding to captureStartValues
      	//endValues corresponds to TransitionValues of captureEndValues}}Copy the code

Customizing Transition requires solving an important problem: How do you get the parameters of the starting state? The easiest way to create Transition is to pass in the parameters for the initial state, but the parameters for the previous Activity (the start state) and the next Activity (the end state). And if there are many parameters, you need to pass in multiple parameters.

Specific solution reference: www.jianshu.com/p/fa1c8deea…

A simplified implementation is also referred to later in this article.

3.2 Defining Visibility

Similar to Transition inheritance, Transition Visibility provides onAppear and onDisappear methods. We can animate from invisible to visible in onAppear and from visible to invisible in onDisappear.

public class TestVisibility extends Visibility {
    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        super.captureStartValues(transitionValues);
    }

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

    @Override
    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility, TransitionValues endValues, int endVisibility) {
        return super.onAppear(sceneRoot, startValues, startVisibility, endValues, endVisibility);
    }

    @Override
    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility, TransitionValues endValues, int endVisibility) {
        return super.onDisappear(sceneRoot, startValues, startVisibility, endValues, endVisibility); }}Copy the code

But there’s the same problem with passing in parameters as there is with Transition inheritance.

3.3 How to Obtain the Start Status Parameters? The sample

The knowledge source: www.jianshu.com/p/fa1c8deea…

3.3.1 SharedElelmentCallback

The SharedElelmentCallback is a callback to the shared element animation and is set up using the following two methods.

activity.setExitSharedElementCallback(callback)
activity.setEnterSharedElementCallback(callback)
Copy the code

SharedElementCallback is an abstract class with the following seven callbacks, all of which have default implementations. It is worth noting that the order in which these callbacks are invoked on entry and exit is inconsistent.

public abstract class SharedElementCallback {...public void onSharedElementStart(List
       
         sharedElementNames, List
        
          sharedElements, List
         
           sharedElementSnapshots)
         
        
        {}
  
    public void onSharedElementEnd(List
       
         sharedElementNames, List
        
          sharedElements, List
         
           sharedElementSnapshots)
         
        
        {}
  
  
    /** * Views removed from the ShareElements list (onMapSharedElements) in the previous step will be called back here, and alpha animation will disappear by default if not handled */
    public void onRejectSharedElements(List<View> rejectedSharedElements) {}
  
    /** * is called first and is used to adjust SharedElements before the animation begins. For example, after sliding the large image, when you return to the original interface, the selected small image has changed, that is, the shared element has changed and needs to be adjusted. * /
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {}

    /** * ImageView records Bitmap, ScaleType, Matrix, etc. Other views only record size and position */
    public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) {
        if (sharedElement instanceof ImageView) {
            ImageView imageView = ((ImageView) sharedElement);
            Drawable d = imageView.getDrawable();
            Drawable bg = imageView.getBackground();
            if(d ! =null && (bg == null || bg.getAlpha() == 0)) {
                Bitmap bitmap = TransitionUtils.createDrawableBitmap(d, imageView);
                if(bitmap ! =null) {
                    Bundle bundle = new Bundle();
                    if(bitmap.getConfig() ! = Bitmap.Config.HARDWARE) { bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap); }else {
                        HardwareBuffer hardwareBuffer = bitmap.getHardwareBuffer();
                        bundle.putParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER, hardwareBuffer);
                        ColorSpace cs = bitmap.getColorSpace();
                        if(cs ! =null) {
                            bundle.putInt(BUNDLE_SNAPSHOT_COLOR_SPACE, cs.getId());
                        }
                    }
                    bundle.putString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE,
                            imageView.getScaleType().toString());
                    if (imageView.getScaleType() == ScaleType.MATRIX) {
                        Matrix matrix = imageView.getImageMatrix();
                        float[] values = new float[9];
                        matrix.getValues(values);
                        bundle.putFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX, values);
                    }
                    returnbundle; }}}if (mTempMatrix == null) {
            mTempMatrix = new Matrix(viewToGlobalMatrix);
        } else {
            mTempMatrix.set(viewToGlobalMatrix);
        }
        ViewGroup parent = (ViewGroup) sharedElement.getParent();
        return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds, parent);
    }

  	/** * Create A View with the same size and location as the * ShareElement in Activity A (in its original location and size, As overlay of DecorView). * /
    public View onCreateSnapshotView(Context context, Parcelable snapshot) {
        View view = null;
        if (snapshot instanceof Bundle) {
            Bundle bundle = (Bundle) snapshot;
            HardwareBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER);
            Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP);
            if (buffer == null && bitmap == null) {
                return null;
            }
            if (bitmap == null) {
                ColorSpace colorSpace = null;
                int colorSpaceId = bundle.getInt(BUNDLE_SNAPSHOT_COLOR_SPACE, 0);
                if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
                    colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
                }
                bitmap = Bitmap.wrapHardwareBuffer(buffer, colorSpace);
            }
            ImageView imageView = new ImageView(context);
            view = imageView;
            imageView.setImageBitmap(bitmap);
            imageView.setScaleType(
                    ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE)));
            if (imageView.getScaleType() == ScaleType.MATRIX) {
                float[] values = bundle.getFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX);
                Matrix matrix = newMatrix(); matrix.setValues(values); imageView.setImageMatrix(matrix); }}else if (snapshot instanceof Bitmap) {
            Bitmap bitmap = (Bitmap) snapshot;
            view = new View(context);
            Resources resources = context.getResources();
            view.setBackground(new BitmapDrawable(resources, bitmap));
        }
        return view;
    }
  
 		/** * indicates that the ShareElement is all in place and can be animated */
    public void onSharedElementsArrived(List
       
         sharedElementNames, List
        
          sharedElements, OnSharedElementsReadyListener listener)
        
        {
        listener.onSharedElementsReady();
    }

    /**
     * Listener to be called after {@link
     * SharedElementCallback#onSharedElementsArrived(List, List, OnSharedElementsReadyListener)}
     * when the shared elements are ready to be hidden in the source Activity and shown in the
     * destination Activity.
     */
    public interface OnSharedElementsReadyListener {

        /**
         * Call this method during or after the OnSharedElementsReadyListener has been received
         * in {@link SharedElementCallback#onSharedElementsArrived(List, List,
         * OnSharedElementsReadyListener)} to indicate that the shared elements are ready to be
         * hidden in the source and shown in the destination Activity.
         */
        void onSharedElementsReady(a); }}Copy the code

Returns the order in which the callbacks of the process are invoked

  ActivityB.onMapSharedElements()
->ActivityA.onMapSharedElements()
->ActivityA.onCaptureSharedElementSnapshot()
->ActivityB.onCreateSnapshotView()
->ActivityB.onSharedElementEnd()    
->ActivityB.onSharedElementStart()   // End first, Start second
->ActivityB.onSharedElementsArrived()
->ActivityA.onSharedElementsArrived()
->ActivityA.onRejectSharedElements()
->ActivityA.onCreateSnapshotView()
->ActivityA.onSharedElementStart()
->ActivityA.onSharedElementEnd()
Copy the code
3.3.2 rainfall distribution on 10-12 sample
public class SharedElementInfo implements Parcelable {
    // Additional information
    protected transient TextView mTextView;
    private String mText;
    private Integer mTextColor;
    private Float mTextSize;
    // Encapsulates information by default
    private Parcelable mSnapshot;
    // Whether to enter the animation
    private Boolean isEnter;

    public SharedElementInfo(TextView textView){
        this.mTextView = textView;
        this.mText = textView.getText().toString();
        this.mTextColor = textView.getCurrentTextColor();
        this.mTextSize = textView.getTextSize();
        textView.setTag(this);
    }

    public void setSnapshot(Parcelable mSnapshot) {
        this.mSnapshot = mSnapshot;
    }

    public Parcelable getSnapshot(a){
        return  mSnapshot;
    }

    public Boolean getIsEnter(a){
        return isEnter;
    }
    public void setIsEnter(Boolean b){
        isEnter = b;
    }

    public String getText(a){
        return mText;
    }

    public Integer getTextColor(a){
        return mTextColor;
    }

    public Float getTextSize(a){
        return mTextSize;
    }

    protected SharedElementInfo(Parcel in) {
        mText = in.readString();
        if (in.readByte() == 0) {
            mTextColor = null;
        } else {
            mTextColor = in.readInt();
        }
        if (in.readByte() == 0) {
            mTextSize = null;
        } else {
            mTextSize = in.readFloat();
        }
        mSnapshot = in.readParcelable(Parcelable.class.getClassLoader());
    }

    public static final Creator<SharedElementInfo> CREATOR = new Creator<SharedElementInfo>() {
        @Override
        public SharedElementInfo createFromParcel(Parcel in) {
            return new SharedElementInfo(in);
        }

        @Override
        public SharedElementInfo[] newArray(int size) {
            return newSharedElementInfo[size]; }};@Override
    public int describeContents(a) {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) { dest.writeString(mText); dest.writeInt(mTextColor); dest.writeFloat(mTextSize); dest.writeParcelable(mSnapshot,flags); }}Copy the code

#MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();

    btn_startTransition.setOnClickListener(view->{
        // Sets the callback to the shared element animation on exit
        setExitSharedElementCallback(new SharedElementCallback() {
            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
              / / to empty
                names.clear();
                sharedElements.clear();
              // Set the shared element we want
                names.add(iv_profile.getTransitionName());
                names.add(tv_userName.getTransitionName());
                sharedElements.put(iv_profile.getTransitionName(),iv_profile);
                sharedElements.put(tv_userName.getTransitionName(),tv_userName)
                  // Create the SharedElelmentInfo class and bind it to textView
                SharedElementInfo info = new SharedElementInfo(tv_userName);
            }

            @Override
            public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) {
              // Return the default snapshot if there is no shared element bound to SharedElelmentInfo
                if(sharedElement.getTag() == null) {return super.onCaptureSharedElementSnapshot(sharedElement, viewToGlobalMatrix, screenBounds);
                }else {
                  // If so, save the additional parameter information in SharedElelmentInfo
                    SharedElementInfo info = (SharedElementInfo) sharedElement.getTag();
                    info.setSnapshot(super.onCaptureSharedElementSnapshot(sharedElement, viewToGlobalMatrix, screenBounds));
                    returninfo; }}});// Start the shared element animation and jump
        ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(this,
                Pair.create(iv_profile,iv_profile.getTransitionName()),
                Pair.create(tv_userName,tv_userName.getTransitionName())
        );
        startActivity(new Intent(this, MainActivity2.class),activityOptions.toBundle());
    });
}
Copy the code

#MainActivity2

    private void setSharedElementAnimation(a) {
        final AtomicBoolean isEnter = new AtomicBoolean(true);
        setEnterSharedElementCallback(new SharedElementCallback() {
            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                names.clear();
                sharedElements.clear();
                names.add(iv_profile.getTransitionName());
                names.add(tv_userName.getTransitionName());
                sharedElements.put(iv_profile.getTransitionName(),iv_profile);
                sharedElements.put(tv_userName.getTransitionName(),tv_userName);
            }

            @Override
            public View onCreateSnapshotView(Context context, Parcelable snapshot) {
                if (snapshot instanceof SharedElementInfo) {
                    SharedElementInfo info = (SharedElementInfo) snapshot;
                    View view = super.onCreateSnapshotView(context, info.getSnapshot());
                    view.setTag(snapshot);
                    return view;
                } else {
                    return super.onCreateSnapshotView(context, snapshot); }}@Override
            public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots);
                if(sharedElements ! =null&& sharedElementSnapshots ! =null) {
                    for (int i = 0; i < sharedElements.size(); i++) {
                        View snapshotView = sharedElementSnapshots.get(i);
                        View shareElementView = sharedElements.get(i);
                        if(snapshotView.getTag()! =null){ ((SharedElementInfo)snapshotView.getTag()).setIsEnter(isEnter.get()); shareElementView.setTag(snapshotView.getTag()); }}}}@Override
            public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                super.onSharedElementEnd(sharedElementNames, sharedElements, sharedElementSnapshots);
                for (int i = 0; sharedElements ! =null && i < sharedElements.size(); i++) {
                    View snapshotView = sharedElementSnapshots.get(i);
                    View shareElementView = sharedElements.get(i);
                    if(snapshotView.getTag()! =null){
                        ((SharedElementInfo)snapshotView.getTag()).setIsEnter(isEnter.get());
                        shareElementView.setTag(snapshotView.getTag());
                    }
                }
                isEnter.set(false); }}); TransitionSet transitionSet =new TransitionSet();
        transitionSet.addTransition(new ChangeClipBounds());
        transitionSet.addTransition(new ChangeBounds());
        // Add a custom Transition
        transitionSet.addTransition(new ChangeTextTransition());
        transitionSet.addTransition(new ChangeImageTransform());
        transitionSet.setDuration(4000);
        getWindow().setSharedElementEnterTransition(transitionSet);
  
        // Set unshared element animation
        getWindow().setEnterTransition(new Fade());
        getWindow().setEnterTransition(new Fade());
      
        // Prevents the status bar from flashing
        Transition enterTransition = getWindow().getEnterTransition();
        Transition exitTransition = getWindow().getExitTransition();
        if(enterTransition ! =null) {
            enterTransition.excludeTarget(Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME, true);
            enterTransition.excludeTarget(Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, true);
        }
        if(exitTransition ! =null) {
            exitTransition.excludeTarget(Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME, true);
            exitTransition.excludeTarget(Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, true); }}Copy the code

#ChangeTextTransition

public class ChangeTextTransition extends Transition {
    private static final String TAG = "ChangeTextTransition";

    private static String PROPNAME_TEXT = "xiaweizi:changeText:text";
    private static String PROPNAME_TEXT_COLOR = "xiaweizi:changeTextColor:color";
    private static String PROPNAME_TEXT_SIZE = "xiaweizi:changeTextSize:size";
    public static int TAG_KEY_TYPEFACE_LEVEL = Awesome!;

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        captureValues(transitionValues,true);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        captureValues(transitionValues,false);
    }

    private void captureValues(TransitionValues transitionValues,Boolean start){
        if (transitionValues == null| |! (transitionValues.viewinstanceof TextView)) return;
        if(transitionValues.view.getTag() == null) return;
        SharedElementInfo info = (SharedElementInfo) transitionValues.view.getTag();
        if((info.getIsEnter()&&start)||(! info.getIsEnter()&&! start)){ transitionValues.values.put(PROPNAME_TEXT, info.getText()); transitionValues.values.put(PROPNAME_TEXT_COLOR, info.getTextColor()); transitionValues.values.put(PROPNAME_TEXT_SIZE, info.getTextSize()); }else{ TextView textView = ((TextView) transitionValues.view); transitionValues.values.put(PROPNAME_TEXT, textView.getText()); transitionValues.values.put(PROPNAME_TEXT_COLOR, textView.getCurrentTextColor()); transitionValues.values.put(PROPNAME_TEXT_SIZE, textView.getTextSize()); }}@Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return null;
        }
        if(! (endValues.viewinstanceof TextView)) {
            return super.createAnimator(sceneRoot, startValues, endValues);
        }
        TextView textView = (TextView) endValues.view;
        CharSequence startText = (CharSequence) startValues.values.get(PROPNAME_TEXT);
        CharSequence endText = (CharSequence) endValues.values.get(PROPNAME_TEXT);
        int startTextColor = (int) startValues.values.get(PROPNAME_TEXT_COLOR);
        int endTextColor = (int) endValues.values.get(PROPNAME_TEXT_COLOR);
        float startTextSize = (float) startValues.values.get(PROPNAME_TEXT_SIZE);
        float endTextSize = (float) endValues.values.get(PROPNAME_TEXT_SIZE);

        AnimatorSet animatorSet = new AnimatorSet();
        if(! TextUtils.equals(startText, endText)) { animatorSet.playTogether(createTextChangeAnimator(textView, startText, endText)); }if(startTextColor ! = endTextColor) { animatorSet.playTogether(createColorChangeAnimator(textView, startTextColor, endTextColor)); }if(startTextSize ! = endTextSize) { animatorSet.playTogether(createSizeChangeAnimator(textView, startTextSize, endTextSize)); }return animatorSet;
    }

    private Animator createColorChangeAnimator(final TextView endView, final int startTextColor, final int endTextColor) {
        ObjectAnimator animator = ObjectAnimator.ofArgb(endView, new TextColorProperty(), startTextColor, endTextColor);
        animator.setDuration(2000);
        return animator;
    }

    private Animator createSizeChangeAnimator(final TextView endView, final float startTextSize, final float endTextSize) {
        ObjectAnimator animator = ObjectAnimator.ofFloat(endView, new TextSizeProperty(), startTextSize, endTextSize);
        animator.setDuration(2000);
        return animator;
    }

    private Animator createTextChangeAnimator(TextView textView, CharSequence startText, CharSequence endText) {
        ValueAnimator animator =  ValueAnimator.ofFloat(0f.1f);
        animator.setDuration(2000);
        animator.addUpdateListener(animation -> {
            Float animatedValue = (Float)animation.getAnimatedValue();
            if(animatedValue<0.5 f) {// textView.setText(startText);
                textView.setAlpha((0.5 f-animatedValue)*2);
            }else{
// textView.setText(endText);
                textView.setAlpha((animatedValue-0.5 f) *2); }});return animator;
    }

    private class TextColorProperty extends Property<TextView.Integer> {

        TextColorProperty() {
            super(Integer.class, "textColor");
        }

        @Override
        public void set(TextView object, Integer value) {
            object.setTextColor(value);
        }

        @Override
        public Integer get(TextView object) {
            returnobject.getCurrentTextColor(); }}private class TextSizeProperty extends Property<TextView.Float> {

        TextSizeProperty() {
            super(Float.class, "textSize");
        }

        @Override
        public void set(TextView object, Float value) {
            object.setTextSize(TypedValue.COMPLEX_UNIT_PX, value);
        }

        @Override
        public Float get(TextView object) {
            returnobject.getTextSize(); }}}Copy the code