How to use custom transitions from resource file - android

I've just written a new custom transition but I'm not sure how to completely define it so can be used in the transition resource files for example res/transition/rotate_transition.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="275"
android:interpolator="#android:interpolator/accelerate_decelerate"/>
Here is my rotate transition code below:
public class Rotate extends Transition {
private static final String PROPNAME_ROTATION = "com.example.transition:rotate:rotation";
#Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public Animator createAnimator(
ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
float startValue = (float) startValues.values.get(PROPNAME_ROTATION);
float endValue = (float) endValues.values.get(PROPNAME_ROTATION);
View view = endValues.view;
ValueAnimator animator = ValueAnimator.ofFloat(startValue, endValue);
animator.addUpdateListener(
animation -> {
float value = (float) animation.getAnimatedValue();
view.setRotation(value);
});
return animator;
}
private void captureValues(TransitionValues values) {
View view = values.view;
values.values.put(PROPNAME_ROTATION, view.getRotation());
}
}
My question is what else should I initialize in order to get this work because now I am only getting java.lang.RuntimeException: Unknown scene name: rotate?

Related

Scale transition animation

I want to create custom Transition for the Scale View elements in the ConstraintLayout. Inside the AutoTransition.java. We have Fade In, AdjustBounds and Fade Out. So performing simple Scale doesn't animate changes.
After some workaround I was able to Create custom Transition with Scale. And my point, it's to create Transition Set with Visiblity and Scale. With changes below this animation works well, despite Scale Pivot.
//..................... General method from Custom Scale Transition
#Nullable
#Override
public Animator createAnimator(#NonNull ViewGroup sceneRoot, #Nullable TransitionValues startValues,
#Nullable TransitionValues endValues) {
if (null == startValues || null == endValues) {
return null;
}
final View view = endValues.view;
final float startX = (float) startValues.values.get(PROPNAME_SCALE_X);
final float endX = (float) endValues.values.get(PROPNAME_SCALE_X);
final float startY = (float) startValues.values.get(PROPNAME_SCALE_Y);
final float endY = (float) endValues.values.get(PROPNAME_SCALE_Y);
final AnimatorSet set = new AnimatorSet();
final ValueAnimator animatorX = ValueAnimator.ofFloat(startX, endX);
animatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
final float value = (float) animation.getAnimatedValue();
view.setScaleX(value);
}
});
final ValueAnimator animatorY = ValueAnimator.ofFloat(startY, endY);
animatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
final float value = (float) animation.getAnimatedValue();
view.setScaleY(value);
}
});
set.playTogether(animatorX, animatorY);
return set;
}
//..................... Complete Set Transitions
public class ScaleVisibility extends TransitionSet {
public ScaleVisibility() {
setOrdering(ORDERING_TOGETHER);
addTransition(new Fade()).
addTransition(new Scale());
}
}
//..................... Code for starting Animation.
mConstraintSet.clone(mConstraintLayout);
Transition transition = new ScaleVisibility();
transition.setDuration(3000);
mConstraintSet.setScaleX(item.resource, item.scale);
mConstraintSet.setScaleY(item.resource, item.scale);
mConstraintSet.setTransformPivot(item.resource, 0.5f, 0.5f);
mConstraintSet.setVisibility(item.resource, item.visibility);
TransitionManager.beginDelayedTransition(mConstraintLayout, transition);
mConstraintSet.applyTo(mConstraintLayout);
//..................... Main XML. Trying to Animate input_send_button
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_input_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="#+id/input_background"
android:layout_width="match_parent"
android:layout_height="#dimen/chat_input_panel_height"
android:background="#color/white"
app:layout_constraintBottom_toBottomOf="parent"/>
<!--This View will change Visibility with Text Changes-->
<ImageButton
android:id="#+id/input_send_button"
android:layout_width="#dimen/chat_input_panel_height"
android:layout_height="0dp"
android:background="#android:color/transparent"
android:src="#drawable/chat_send"
android:tint="#color/primary"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#+id/input_background"
app:layout_constraintRight_toRightOf="#+id/input_background"
app:layout_constraintTop_toTopOf="#+id/input_background"
tools:ignore="ContentDescription"
tools:visibility="visible"/>
</android.support.constraint.ConstraintLayout>
Main issue here, it's Scale animation Pivot, which is zero (top left corner of view). And I cannot change Transition pivot for Animated view. Neither with adding this property to the View.java nor ConstraintSet.javaparameters. So question it's how to change View Pivot for this Scale Transition. (As additional question, I was interested with changing Pivot for the default AdjustBounds Transition, where we changing view Height/Width).
Try resetting the pivot on each animation step. If you're looking for center pivot you can just slash through getWidth(), otherwise you need to capture another pivot value and use it.
Try this transition:
public class ScaleTransition extends Transition {
private final static String PROPNAME_SCALE_X = "PROPNAME_SCALE_X";
private final static String PROPNAME_SCALE_Y = "PROPNAME_SCALE_Y";
#Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues values){
values.values.put(PROPNAME_SCALE_X, values.view.getScaleX());
values.values.put(PROPNAME_SCALE_Y, values.view.getScaleY());
}
#Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
if(endValues == null || startValues == null)
return null; // no values
float startX = (float) startValues.values.get(PROPNAME_SCALE_X);
float startY = (float) startValues.values.get(PROPNAME_SCALE_Y);
float endX = (float) endValues.values.get(PROPNAME_SCALE_X);
float endY = (float) endValues.values.get(PROPNAME_SCALE_Y);
if(startX == endX && startY == endY)
return null; // no scale to run
final View view = startValues.view;
PropertyValuesHolder propX = PropertyValuesHolder.ofFloat(PROPNAME_SCALE_X, startX, endX);
PropertyValuesHolder propY = PropertyValuesHolder.ofFloat(PROPNAME_SCALE_Y, startY, endY);
ValueAnimator valAnim = ValueAnimator.ofPropertyValuesHolder(propX, propY);
valAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
view.setPivotX(view.getWidth()/2f);
view.setPivotY(view.getHeight()/2f);
view.setScaleX((float) valueAnimator.getAnimatedValue(PROPNAME_SCALE_X));
view.setScaleY((float) valueAnimator.getAnimatedValue(PROPNAME_SCALE_Y));
}
});
return valAnim;
}
}
In order to create a custom transition(s) for TransitionManager you need to create a custom Transition or TransitionSet. For example:
TransitionSet transitionSet = new TransitionSet();
//your types of transitions
Transition first = new ChangeBounds();
Transition second = new Fade();
first.addTarget(firstView);
second.addTarget(secondView);
//Add your transitions to TransitionSet
transitionSet.addTransition(first).addTransition(second);
//Start transitions
TransitionManager.beginDelayedTransition(layout, transitionSet);
You can learn more about TransitionSet here and about Transition here

Transition from TextView inside Fragment to title of Toolbar

I got a fragment inside of an Activity which contains a TextView and a Button.
If I click the Button another Fragment loads and the text of the TextView in the first Fragment is now the title of the Toolbar. I want to animate this change with the Transition Framework and something like changeBounds but I don't know how to set a transition for the Toolbar.
Could someone point me towards a solution?
You can create a custom transition that animates a TextView's text size as follows:
public class TextSizeTransition extends Transition {
private static final String PROPNAME_TEXT_SIZE = "lychmanit:transition:textsize";
private static final String[] TRANSITION_PROPERTIES = { PROPNAME_TEXT_SIZE };
private static final Property<TextView, Float> TEXT_SIZE_PROPERTY =
new Property<TextView, Float>(Float.class, "textSize") {
#Override
public Float get(TextView textView) {
return textView.getTextSize();
}
#Override
public void set(TextView textView, Float textSizePixels) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePixels);
}
};
public TextSizeTransition() {
}
public TextSizeTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public String[] getTransitionProperties() {
return TRANSITION_PROPERTIES;
}
#Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
if (transitionValues.view instanceof TextView) {
TextView textView = (TextView) transitionValues.view;
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;
}
Float startSize = (Float) startValues.values.get(PROPNAME_TEXT_SIZE);
Float endSize = (Float) endValues.values.get(PROPNAME_TEXT_SIZE);
if (startSize == null || endSize == null ||
startSize.floatValue() == endSize.floatValue()) {
return null;
}
TextView view = (TextView) endValues.view;
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, startSize);
return ObjectAnimator.ofFloat(view, TEXT_SIZE_PROPERTY, startSize, endSize);
}
}
Since changing the TextView's text size will cause its layout bounds to change during the course of the animation, getting the transition to work properly will take a little more effort than simply throwing a ChangeBounds transition into the same TransitionSet. What you will need to do instead is manually measure/layout the view in its end state in a SharedElementCallback.

Why Fade transition doesn't work on Shared Element

I have 2 Activities , the Shared Element transition works fine.ChangeBounds is the only the transition applied.
I want to apply a fade transition while the shared element moves, so the ordering is ORDERING_TOGETHER.
public class TransitionUtils {
public static Transition makeSharedElementEnterTransition(final Context context, final long duration) {
TransitionSet set = new TransitionSet();
set.setOrdering(TransitionSet.ORDERING_TOGETHER);
set.setDuration(duration);
Transition changeBounds = new ChangeBounds();
changeBounds.addTarget(context.getString(R.string.transition_name_search_text));
set.addTransition(changeBounds);
Transition fade = new Fade(Fade.OUT);
fade.addTarget(context.getString(R.string.transition_name_search_text));
set.addTransition(fade);
return set;
}
}
The startActivity calls ActivityOptions.makeSceneTransitionAnimation
In the EndActivity , the enter shared element transition is set
public class EndActivity extends Activity{
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blabla);
getWindow().setSharedElementEnterTransition(TransitionUtils.makeSharedElementEnterTransition(this,2000));
}
}
Notes : I noticed that
Fade() is often applied to getWindow().setEnterTransition()
setting a
duration to TransitionSet applies to all Transistions contained
except Fade.
How to apply a Fade Transition to a sharedElement ?
What am I doing wrong ?
android.transition.Fade uses TransitionAlpha , which cannot be resolved in my IDE. android.transition.Fade works for enter and exit transition between activities.
So I created my own Fade to use Alpha. An Android view's opacity is set by alpha. And shared element uses View.
You call it like this :
Transition fadeOut = new FadeTransition(1f, 0f, new LinearInterpolator());
fadeOut.addTarget(transitionName);
The full code is here
#TargetApi(21)
public class FadeTransition extends Transition {
private static final String PROPNAME_BACKGROUND = "android:faderay:background";
private static final String PROPNAME_TEXT_COLOR = "android:faderay:textColor";
private static final String PROPNAME_ALPHA = "android:faderay:alpha";
private float startAlpha;
private float endAlpha;
private TimeInterpolator timeInterpolator;
public FadeTransition(final float startAlpha, final float endAlpha, final TimeInterpolator timeInterpolator) {
this.startAlpha = startAlpha;
this.endAlpha = endAlpha;
this.timeInterpolator = timeInterpolator;
}
public FadeTransition(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
private void captureValues(final TransitionValues transitionValues) {
transitionValues.values.put(PROPNAME_BACKGROUND, transitionValues.view.getBackground());
transitionValues.values.put(PROPNAME_ALPHA, transitionValues.view.getAlpha());
if (transitionValues.view instanceof TextView) {
transitionValues.values.put(PROPNAME_TEXT_COLOR, ((TextView) transitionValues.view).getCurrentTextColor());
}
}
#Override
public void captureStartValues(final TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(final TransitionValues transitionValues) {
captureValues(transitionValues);
}
#SuppressLint("NewApi")
#Override
public Animator createAnimator(final ViewGroup sceneRoot, final TransitionValues startValues,
final TransitionValues endValues) {
TextView textView = (TextView) endValues.view;
if (startAlpha != endAlpha) {
textView.setAlpha(endAlpha);
}
ObjectAnimator fade = ObjectAnimator.ofFloat(textView, View.ALPHA, startAlpha, endAlpha);
fade.setInterpolator(timeInterpolator);
return fade;
}
}

Animate a tint in android via scene transition animation

So in my app, I have a scene transition on an image view that transitions it from one activity to another:
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(),tracks.class);
i.putExtra("album", al);
ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation((item_display) v.getContext(), cover, "pic");
v.getContext().startActivity(i, transitionActivityOptions.toBundle());
}
});
Now, the scale and positioning transition works fine. However, on the imageview in the 2nd activity, I have a tint attribute in the xml to make it darker (style choice). The tint does not animate, so the whole effect is slightly more jarring that I would like. Is there any way to get the tint to smoothly transition back and forth like the rest of the image?
Use a custom transition. Something like this.
public class TintTransition extends Transition {
private static final String PROPNAME_TINT = "com.example:TintTransition:tint";
public TintTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
private void captureValues(TransitionValues values) {
if (values.view instanceof AppCompatImageView) {
values.values.put(PROPNAME_TINT, ((AppCompatImageView) values.view).getImageTintList());
}
}
#Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public Animator createAnimator(ViewGroup sceneRoot, final TransitionValues startValues, final TransitionValues endValues) {
if (endValues == null) {
return null;
}
if (!(endValues.view instanceof AppCompatImageView)) {
return null;
}
ColorStateList startColorStateList = (ColorStateList) startValues.values.get(PROPNAME_TINT);
ColorStateList endColorStateList = (ColorStateList) endValues.values.get(PROPNAME_TINT);
final int endColor = endColorStateList.getDefaultColor();
final int startColor = startColorStateList == null
? Color.TRANSPARENT
: startColorStateList.getDefaultColor();
ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer color = (Integer) animation.getAnimatedValue();
if (color != null) {
((AppCompatImageView) endValues.view).setImageTintList(ColorStateList.valueOf(color));
}
}
});
return animator;
}
}
If you need to inflate from XML, this is the way to do it:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<transition class="com.example.transitions.TintTransition" android:duration="400" android:interpolator="#android:interpolator/fast_out_slow_in"/>
</transitionSet>

Android fragment transition custom view

I want to create a custom animation for fragment transition. The animation is in form of a circle that increases his radius from a specific size until it is equal to window height. I can use ScaleAnimation, but then I'll lose drawable quality. Does someone have any ideas ho to do this. Thanks in advance.
Ok. I'll answer my own question :). To animate the fragment transition with my custom transition (a colored circle that increases his size) I have done the following:
- create a custom view that draws a circle and add the possibility to increase his radius;
- place this view in my FragmentActivity xml layout;
- when the target button is clicked and fragment should change I've called ValueAnimator to change circle radius;
Final code will look something like this:
public class MainScreenActivity extends AppCompatActivity {
private Button targetButton;
private CircleView circleView;
public void targetButtonClick(View view) {
AnimationHandler handler = new AnimationHandler(view.getX(),view.getY());
handler.animate();
}
private class AnimationHandler implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
private static final int TRANSITION_ANIM_DURATION = 500;
private final float centerX;
private final float centerY;
private ValueAnimator valueAnimator;
public AnimationHandler(float x, float y) {
this.centerX = x;
this.centerY = y;
init();
}
private void init() {
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
valueAnimator = ValueAnimator.ofFloat(0, point.y);
valueAnimator.setDuration(TRANSITION_ANIM_DURATION);
valueAnimator.addUpdateListener(this);
valueAnimator.addListener(this);
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationUpdate(ValueAnimator animation) {
circleView.setRadius((float) animation.getAnimatedValue());
}
public void animate() {
circleView.setXCenter(centerX);
circleView.setYCenter(centerY);
int color = getResources().getColor(android.R.color.dark_red);
circleView.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.trans_circle_width));
valueAnimator.start();
}
}
}

Categories

Resources