The transition API is certainly a good thing, but it cannot solve everything for you. You did not instruct how to perform this animation in the transition structure, how does it understand what is the final animation that you want to perform?
I am not sure that this animation can be achieved using only the transition APIs. Instead, you can stick with standard animation APIs, for example. ValueAnimator .
Animation consists of several stages. When a button is pressed, you want it to become a little wider, also losing transparency. And after that, you want the EditText appear on the scene and be animated to the final value, starting from the width where the button was clicked.
So, inside the button, click the listen button:
@Override public void onClick(View v) { final int from = addButton.getWidth(); final int to = (int) (from * 1.2f); // increase by 20% final LinearInterpolator interpolator = new LinearInterpolator(); ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to); firstAnimator.setTarget(addButton); firstAnimator.setInterpolator(interpolator); firstAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = addButton.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); addButton.setAlpha(1 - animation.getAnimatedFraction()); addButton.requestLayout(); } }); firstAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // reset alpha channel addButton.setAlpha(1.0f); addButton.setVisibility(View.GONE); mItemInputEditText.setVisibility(View.VISIBLE); ValueAnimator secondAnimator = ValueAnimator.ofInt(to, editTextWidth); secondAnimator.setTarget(mItemInputEditText); secondAnimator.setInterpolator(interpolator); secondAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); mItemInputEditText.requestLayout(); } }); secondAnimator.start(); } }); firstAnimator.start(); }
@Override public void onClick(View v) { final int from = addButton.getWidth(); final int to = (int) (from * 1.2f); // increase by 20% final LinearInterpolator interpolator = new LinearInterpolator(); ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to); firstAnimator.setTarget(addButton); firstAnimator.setInterpolator(interpolator); firstAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = addButton.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); addButton.setAlpha(1 - animation.getAnimatedFraction()); addButton.requestLayout(); } }); firstAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // reset alpha channel addButton.setAlpha(1.0f); addButton.setVisibility(View.GONE); mItemInputEditText.setVisibility(View.VISIBLE); ValueAnimator secondAnimator = ValueAnimator.ofInt(to, editTextWidth); secondAnimator.setTarget(mItemInputEditText); secondAnimator.setInterpolator(interpolator); secondAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); mItemInputEditText.requestLayout(); } }); secondAnimator.start(); } }); firstAnimator.start(); }
Similar actions are performed when returning from EditText to the button:
@Override public void onClick(View view) { final int from = mItemInputEditText.getWidth(); final int to = (int) (from * 0.8f); final LinearInterpolator interpolator = new LinearInterpolator(); ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to); firstAnimator.setTarget(mItemInputEditText); firstAnimator.setInterpolator(interpolator); firstAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); mItemInputEditText.requestLayout(); } }); firstAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mItemInputEditText.setVisibility(View.GONE); addButton.setVisibility(View.VISIBLE); ValueAnimator secondAnimator = ValueAnimator.ofInt(to, buttonWidth); secondAnimator.setTarget(addButton); secondAnimator.setInterpolator(interpolator); secondAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = addButton.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); addButton.setAlpha(animation.getAnimatedFraction()); addButton.requestLayout(); } }); secondAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { addButton.setAlpha(0.0f); } }); secondAnimator.start(); } }); firstAnimator.start(); }
@Override public void onClick(View view) { final int from = mItemInputEditText.getWidth(); final int to = (int) (from * 0.8f); final LinearInterpolator interpolator = new LinearInterpolator(); ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to); firstAnimator.setTarget(mItemInputEditText); firstAnimator.setInterpolator(interpolator); firstAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); mItemInputEditText.requestLayout(); } }); firstAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mItemInputEditText.setVisibility(View.GONE); addButton.setVisibility(View.VISIBLE); ValueAnimator secondAnimator = ValueAnimator.ofInt(to, buttonWidth); secondAnimator.setTarget(addButton); secondAnimator.setInterpolator(interpolator); secondAnimator.setDuration(DURATION); final ViewGroup.LayoutParams params = addButton.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); addButton.setAlpha(animation.getAnimatedFraction()); addButton.requestLayout(); } }); secondAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { addButton.setAlpha(0.0f); } }); secondAnimator.start(); } }); firstAnimator.start(); }
editTextWidth and buttonWidth are the initial sizes of the views:
private int editTextWidth, buttonWidth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... // `transitions_container` is the parent of both `EditText` and `Button` // Thus, posting on it ensures that both of those views are laid out when this runnable is executed findViewById(R.id.transitions_container).post(new Runnable() { @Override public void run() { editTextWidth = mItemInputEditText.getWidth(); // `mItemInputEditText` should be left visible from XML in order to get measured // setting to GONE after we have got actual width mItemInputEditText.setVisibility(View.GONE); buttonWidth = addButton.getWidth(); } }); }
private int editTextWidth, buttonWidth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... // `transitions_container` is the parent of both `EditText` and `Button` // Thus, posting on it ensures that both of those views are laid out when this runnable is executed findViewById(R.id.transitions_container).post(new Runnable() { @Override public void run() { editTextWidth = mItemInputEditText.getWidth(); // `mItemInputEditText` should be left visible from XML in order to get measured // setting to GONE after we have got actual width mItemInputEditText.setVisibility(View.GONE); buttonWidth = addButton.getWidth(); } }); }
Here's the conclusion:

You may have a patch file with the changes here .