Created
November 11, 2015 14:22
-
-
Save richarddd/c5e4c83c14565306140b to your computer and use it in GitHub Desktop.
Shared Transition Text
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.animation.Animator; | |
import android.animation.ArgbEvaluator; | |
import android.animation.ValueAnimator; | |
import android.annotation.SuppressLint; | |
import android.app.Activity; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.graphics.Rect; | |
import android.os.Parcelable; | |
import android.transition.Transition; | |
import android.transition.TransitionSet; | |
import android.transition.TransitionValues; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.util.Pair; | |
import android.util.TypedValue; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.TextView; | |
import java.lang.reflect.Array; | |
import java.util.Arrays; | |
import java.util.List; | |
/** | |
* Created by richard on 24/10/15. | |
*/ | |
@SuppressLint("NewApi") | |
public class ChangeText extends Transition { | |
private static final String PROPNAME_TEXTSIZE = "android:resizetext:textSize"; | |
private static final String PROPNAME_TEXTCOLOR = "android:resizetext:textColor"; | |
private static final String PROPNAME_TEXTPADDING = "android:resizetext:textPadding"; | |
private static final String KEY_TEXT_SIZES = "key_text_sizes"; | |
private static final String KEY_TEXT_COLORS = "key_text_colors"; | |
private static final String KEY_TEXT_PADDINGS = "key_text_padding"; | |
private static final String KEY_TEXT_NAMES = "key_text_names"; | |
private static final String TAG = ChangeText.class.getSimpleName(); | |
private List<String> keyNames; | |
private float[] sizeValues; | |
private int[] colorValues; | |
private Rect[] paddingValues; | |
private boolean enter; | |
@Override | |
public void captureStartValues(TransitionValues transitionValues) { | |
captureValues(transitionValues, "start"); | |
} | |
private void captureValues(TransitionValues transitionValues, String log) { | |
View view = transitionValues.view; | |
if (view.getVisibility() == View.GONE) { | |
return; | |
} | |
int index = keyNames.indexOf(view.getTransitionName()); | |
if (index > -1) { | |
Log.d(TAG,log+"direction = "+enter); | |
float textSize = sizeValues[index]; | |
int textColor = colorValues[index]; | |
Rect padding = paddingValues[index]; | |
transitionValues.values.put(PROPNAME_TEXTSIZE, textSize); | |
transitionValues.values.put(PROPNAME_TEXTCOLOR, textColor); | |
transitionValues.values.put(PROPNAME_TEXTPADDING, padding); | |
} | |
} | |
public ChangeText() { | |
init(); | |
} | |
public ChangeText(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(); | |
} | |
private void init() { | |
addTarget(TextView.class); | |
} | |
@Override | |
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { | |
if (startValues == null || startValues.values.size() == 0) { | |
return null; | |
} | |
final TextView textView = ((TextView) startValues.view); | |
int fromColor = (int) startValues.values.get(PROPNAME_TEXTCOLOR); | |
int toColor = textView.getTextColors().getDefaultColor(); | |
float fromSize = (float) startValues.values.get(PROPNAME_TEXTSIZE); | |
float toSize = textView.getTextSize(); | |
Rect fromPadding = (Rect)startValues.values.get(PROPNAME_TEXTPADDING); | |
Rect toPadding = paddingToRect(textView); | |
if(!enter){ | |
fromColor = fromColor + toColor; | |
toColor = fromColor - toColor; | |
fromColor = fromColor - toColor; | |
fromSize = fromSize + toSize; | |
toSize = fromSize - toSize; | |
fromSize = fromSize - toSize; | |
Rect temp = new Rect(toPadding); | |
toPadding = fromPadding; | |
fromPadding = temp; | |
} | |
final Rect finalFromPadding = fromPadding; | |
final Rect finalToPadding = toPadding; | |
final float finalFromSize = fromSize; | |
final float finalToSize = toSize; | |
ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), | |
fromColor, toColor); | |
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
Object value = animation.getAnimatedValue(); | |
float fraction = animation.getAnimatedFraction(); | |
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fracturedValue(fraction, finalFromSize, finalToSize)); | |
textView.setPadding(fracturedValue(fraction, finalFromPadding.left, finalToPadding.left), fracturedValue(fraction, finalFromPadding.top, finalToPadding.top), fracturedValue(fraction, finalFromPadding.right, finalToPadding.right), fracturedValue(fraction, finalFromPadding.bottom, finalToPadding.bottom)); | |
if (null != value) { | |
textView.setTextColor((Integer) value); | |
} | |
} | |
}); | |
return animator; | |
} | |
private static Rect paddingToRect(TextView textView) { | |
return new Rect(textView.getPaddingLeft(),textView.getPaddingTop(),textView.getPaddingRight(),textView.getPaddingBottom()); | |
} | |
private static float fracturedValue(float fraction, float from, float to) { | |
return from + ((to-from)*fraction); | |
} | |
private static int fracturedValue(float fraction, int from, int to) { | |
return (int) fracturedValue(fraction,(float)from,(float)to); | |
} | |
@Override | |
public void captureEndValues(TransitionValues transitionValues) { | |
captureValues(transitionValues, "end"); | |
} | |
public static void intent(Intent intent, View sharedView, String sharedElementName) { | |
intent(intent, new Pair<View, String>(sharedView, sharedElementName)); | |
} | |
public static void intent(Intent intent, Pair<View, String>... sharedElements) { | |
float[] sizeArray = new float[sharedElements.length]; | |
int[] colorArray = new int[sharedElements.length]; | |
Rect[] paddingArray = new Rect[sharedElements.length]; | |
String[] keyArray = new String[sharedElements.length]; | |
boolean hasValue = false; | |
int index = 0; | |
for (Pair<View, String> sharedElement : sharedElements) { | |
View view = sharedElement.first; | |
if (view instanceof TextView) { | |
TextView textView = ((TextView) sharedElement.first); | |
hasValue = true; | |
sizeArray[index] = textView.getTextSize(); | |
colorArray[index] = textView.getTextColors().getDefaultColor(); | |
paddingArray[index] = paddingToRect(textView); | |
keyArray[index] = sharedElement.second; | |
} | |
index++; | |
} | |
if (hasValue) { | |
intent.putExtra(KEY_TEXT_SIZES, sizeArray); | |
intent.putExtra(KEY_TEXT_COLORS, colorArray); | |
intent.putExtra(KEY_TEXT_PADDINGS,paddingArray); | |
intent.putExtra(KEY_TEXT_NAMES, keyArray); | |
} | |
} | |
public static <T extends Parcelable> T[] getParcelableArray(Intent bundle, String key, Class<T[]> type) { | |
Parcelable[] value = bundle.getParcelableArrayExtra(key); | |
if (value == null) { | |
return null; | |
} | |
Object copy = Array.newInstance(type.getComponentType(), value.length); | |
System.arraycopy(value, 0, copy, 0, value.length); | |
return (T[]) copy; | |
} | |
public static void setup(Activity activity) { | |
Intent intent = activity.getIntent(); | |
if (intent.hasExtra(KEY_TEXT_NAMES)) { | |
Transition transitionEnter = activity.getWindow().getSharedElementEnterTransition(); | |
Transition transitionExit = activity.getWindow().getSharedElementReturnTransition(); | |
float[] sizeValues = intent.getFloatArrayExtra(KEY_TEXT_SIZES); | |
int[] colorValues = intent.getIntArrayExtra(KEY_TEXT_COLORS); | |
Rect[] paddingValues = getParcelableArray(intent,KEY_TEXT_PADDINGS,Rect[].class); | |
List<String> keyNames = Arrays.asList(intent.getStringArrayExtra(KEY_TEXT_NAMES)); | |
setupValues(keyNames, sizeValues, colorValues, paddingValues,transitionEnter, true); | |
setupValues(keyNames, sizeValues, colorValues, paddingValues,transitionExit, false); | |
} | |
} | |
private static void setupValues(List<String> keyNames, float[] sizeValues, int[] colorValues, Rect[] paddingValues, Transition transition, boolean enter) { | |
if (transition != null) { | |
ChangeText changeTextTransition = null; | |
if (transition instanceof TransitionSet) { | |
TransitionSet set = (TransitionSet) transition; | |
for (int i = 0; i < set.getTransitionCount(); i++) { | |
Transition transitionInSet = set.getTransitionAt(i); | |
if (transitionInSet instanceof ChangeText) { | |
changeTextTransition = (ChangeText) transitionInSet; | |
break; | |
} | |
} | |
} else if (!(transition instanceof ChangeText)) { | |
return; | |
} else { | |
changeTextTransition = (ChangeText) transition; | |
} | |
if (changeTextTransition != null) { | |
changeTextTransition.setValues(keyNames, sizeValues, colorValues, paddingValues,enter); | |
} | |
} | |
} | |
private void setValues(List<String> keyNames, float[] sizeValues, int[] colorValues, Rect[] paddingValues, boolean enter) { | |
this.keyNames = keyNames; | |
this.sizeValues = sizeValues; | |
this.colorValues = colorValues; | |
this.paddingValues = paddingValues; | |
this.enter = enter; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<transitionSet | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:duration="450"> | |
<changeBounds /> | |
<changeTransform/> | |
<changeClipBounds/> | |
<changeImageTransform/> | |
<transition class="com.yourpackage.transition.ChangeText" /> | |
<arcMotion android:minimumHorizontalAngle="50" android:minimumVerticalAngle="50" /> | |
</transitionSet> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void startActivity(Activity activity, int intentParamterOrSomething, View sharedView){ | |
Intent intent = new Intent(activity, DetailActivity.class); | |
intent.putExtra(EXTRA_WHATEVER, intentParamterOrSomething); | |
Bundle bundle = null; | |
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { | |
bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedView, sharedView.getTransitionName()).toBundle(); | |
ChangeText.intent(intent, sharedView, sharedView.getTransitionName()); | |
} | |
ActivityCompat.startActivity(activity, intent, bundle); | |
} | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
... | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | |
getWindow().setSharedElementEnterTransition(TransitionInflater.from(this) | |
.inflateTransition(R.transition.curve)); | |
getWindow().setSharedElementReturnTransition(TransitionInflater.from(this) | |
.inflateTransition(R.transition.curve)); | |
ChangeText.setup(this); | |
} | |
... | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment