I have a scene transition and I want to use Recolor animation to change background of a ViewGroup from transparent to another color. Here is my login_to_register.xml
:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<fade android:fadingMode="fade_out"/>
<fade android:fadingMode="fade_in">
<targets>
<target android:targetId="@id/passwordEditor" />
<target android:targetId="@id/loginNameEditor" />
</targets>
</fade>
<!--<changeTransform />-->
<changeBounds />
<recolor>
<targets>
<target android:targetId="@id/loginOptions" />
</targets>
</recolor>
</transitionSet>
This is the XML for the layout of the fragment, which is inside the ViewPager.
<FrameLayout
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent" android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/onboarding_bg"
/>
<LinearLayout
android:id="@+id/loginOptions"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:background="@android:color/transparent"
android:layout_gravity="bottom"
android:gravity="center_horizontal"
>
<android.support.design.widget.TextInputLayout
android:id="@+id/loginNameEditor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
app:errorEnabled="true"
app:hintTextAppearance="@style/BlackFloatingTextTextAppearance"
android:visibility="gone"
tools:visibility="visible"
>
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={regModel.emailAddress, default=`twinkle`}"
android:inputType="textEmailAddress"
android:maxLength="254"
android:onFocusChange="@{(v, focus) -> context.loginFocusChanged(true, focus)}"
android:afterTextChanged="@{() -> context.loginTextChanged()}"
/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/passwordEditor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
app:passwordToggleEnabled="true"
app:errorEnabled="true"
app:hintTextAppearance="@style/BlackFloatingTextTextAppearance"
app:counterEnabled="true"
app:counterMaxLength="50"
android:visibility="gone"
tools:visibility="visible"
>
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={regModel.password}"
android:inputType="textPassword"
android:fontFamily="monospace"
android:onFocusChange="@{(v, focus) -> context.loginFocusChanged(false, focus)}"
android:afterTextChanged="@{() -> context.loginTextChanged()}"
/>
</android.support.design.widget.TextInputLayout>
<TextView
android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textAppearance="@style/TextAppearance.Design.Error"
android:gravity="start"
android:visibility="gone"
tools:visibility="visible"
/>
<!--<Button-->
<!--android:id="emailAuthButton"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_marginTop="@dimen/loginButtonSpacing"-->
<!--android:text="@string/login"-->
<!--style="@style/PrimaryColorButtonBorderlessStyle"-->
<!--android:onClick="loginEmail"-->
<!--/>-->
<com.google.android.gms.common.SignInButton
android:id="@+id/googButton"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/loginButtonSpacing"
android:layout_marginTop="@dimen/loginButtonSpacing"
android:onClick="loginGoogle"
app:buttonSize="wide"
/>
<com.facebook.login.widget.LoginButton
android:id="@+id/fbButton"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/loginButtonSpacing"
app:com_facebook_login_text="@string/com_facebook_loginview_log_in_button"
android:layout_marginBottom="@dimen/loginButtonSpacing"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:onClick="loginFB"
/>
<TextView
android:id="@+id/emailInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:layout_marginTop="@dimen/register_row_spacing"
android:layout_marginStart="10dp"
android:text="@string/unauth_email_prompt"
android:textColor="?android:attr/textColorPrimaryInverse"
/>
<Button
android:id="@+id/unfederatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/loginButtonSpacing"
android:layout_marginBottom="@dimen/loginButtonSpacing"
android:text="@string/create_account"
style="@style/ScalableBorderlessButton"
android:textColor="@color/colorAccent"
android:minHeight="53dp"
android:onClick="showUnfederatedUI"
/>
<TextView
android:id="@+id/forgotPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="15dp"
android:paddingTop="@dimen/smallLinkTopPadding"
android:paddingBottom="@dimen/smallLinkBottomPadding"
android:paddingLeft="@dimen/smallLinkHPadding"
android:paddingRight="@dimen/smallLinkHPadding"
app:hypertext="@{R.string.forgot_pass}"
android:background="?android:attr/selectableItemBackground"
tools:text="@string/forgot_pass"
android:textSize="@dimen/smallLinkTextSize"
android:onClick="recoverPassword"
android:visibility="gone"
/>
</LinearLayout>
</FrameLayout>
Now the view that I want to use Recolor is the id loginOptions
. You can see that I am giving its specific targetId in the transition. And it is defaulting to transparent
in case there are any issues with starting from null. So here is the code to start the scene transition
val trans = TransitionInflater.from(this).inflateTransition(R.transition.login_to_register)
TransitionManager.beginDelayedTransition(this.dataBinding.root, trans)
this.loginBinding!!.loginNameEditor.visibility = View.VISIBLE
this.loginBinding!!.passwordEditor.visibility = View.VISIBLE
this.loginBinding!!.error.visibility = View.VISIBLE
this.loginBinding!!.googButton.visibility = View.GONE
this.loginBinding!!.fbButton.visibility = View.GONE
this.loginBinding!!.emailInfo.visibility = View.GONE
this.loginBinding!!.forgotPassword.visibility = View.VISIBLE
val color = this.resources.getColor(R.color.almostWhite)
this.loginBinding!!.loginOptions.background = ColorDrawable(color)
I am not including the activity layout of the ViewPager, it is straightforward, and probably doesn't have any issues, because all the other transitions work! Yes, all the VISIBILITY changes are working properly, and the bounds changes.
What's wrong with the Recolor? Edit: Let me add that, if I remove <recolor>
, the background of @id/loginOptions
does change to almostWhite
.
This reported to Google issue tracker,there has a solution that works for me, which is why I'm accepting this.
To use a custom transition in a transition xml do :
<transition
class="com.example.BackgroundRecolor"
android:duration="200"/>
Add constructors from Transition in your custom transition to support xml attributes :
public BackgroundRecolor() {}
public BackgroundRecolor(Context context, AttributeSet attrs) {
super(context, attrs);
}
[Update] The code file on the issuetracker is "deleted", here is the full contents of this code as it is in my project:
public class BackgroundRecolor extends Transition {
public BackgroundRecolor() {}
public BackgroundRecolor(Context context, AttributeSet attrs) {
super(context, attrs);
}
private static final String PROPNAME_BACKGROUND = "com.example:recolor:background";
private void captureValues(TransitionValues transitionValues) {
Drawable bg = transitionValues.view.getBackground();
if (bg != null && bg instanceof ColorDrawable) {
transitionValues.values.put(PROPNAME_BACKGROUND, ((ColorDrawable) bg).getColor());
}
}
@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) {
if (startValues == null || endValues == null) {
return null;
}
if (startValues.values.get(PROPNAME_BACKGROUND) == null || !(startValues.values.get(PROPNAME_BACKGROUND) instanceof Integer))
return null;
if (endValues.values.get(PROPNAME_BACKGROUND) == null || !(endValues.values.get(PROPNAME_BACKGROUND) instanceof Integer))
return null;
int colorStart = (int) startValues.values.get(PROPNAME_BACKGROUND);
int colorEnd = (int) endValues.values.get(PROPNAME_BACKGROUND);
Drawable bg = endValues.view.getBackground();
if (!(bg instanceof ColorDrawable))
return null;
ColorDrawable bgc = (ColorDrawable) bg;
bgc.setColor(colorStart);
return ObjectAnimator.ofObject(bgc, "color", new ArgbEvaluator(), colorStart, colorEnd);
}
}