java - introduccion - ¡No se puede iniciar este animador en una vista separada! efecto revelador
introduccion a la animacion (10)
¿Qué tal si simplemente colocamos el método en el método onViewCreated ()?
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
toggleInformationView(view);
}
funciona
Estoy tratando de crear el efecto revelador en mi aplicación pero sin éxito. Lo que quiero es revelar una vista de tarjeta cuando abro un fragmento. Lo que probé hasta ahora es:
private void toggleInformationView(View view) {
infoContainer = view.findViewById(R.id.contact_card);
int cx = (view.getLeft() + view.getRight()) / 2;
int cy = (view.getTop() + view.getBottom()) / 2;
float radius = Math.max(infoContainer.getWidth(), infoContainer.getHeight()) * 2.0f;
if (infoContainer.getVisibility() == View.INVISIBLE) {
infoContainer.setVisibility(View.VISIBLE);
ViewAnimationUtils.createCircularReveal(infoContainer, cx, cy, 0, radius).start();
} else {
Animator reveal = ViewAnimationUtils.createCircularReveal(
infoContainer, cx, cy, radius, 0);
reveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
infoContainer.setVisibility(View.INVISIBLE);
}
});
reveal.start();
}
}
y en el onCreateView
comencé el método:
toggleInformationView(view);
Esta es la tarjeta de visita:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="@+id/contact_card"
android:visibility="invisible"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:elevation="4dp"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical"
android:padding="10dp"
card_view:cardCornerRadius="2dp" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/bg_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_weight="0"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/banner" />
</LinearLayout>
</android.support.v7.widget.CardView>
y la logcat:
11-08 17:25:48.541: E/AndroidRuntime(26925): java.lang.IllegalStateException: Cannot start this animator on a detached view!
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.view.RenderNode.addAnimator(RenderNode.java:817)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.view.RenderNodeAnimator.setTarget(RenderNodeAnimator.java:277)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.view.RenderNodeAnimator.setTarget(RenderNodeAnimator.java:261)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.animation.RevealAnimator.<init>(RevealAnimator.java:37)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.view.ViewAnimationUtils.createCircularReveal(ViewAnimationUtils.java:48)
11-08 17:25:48.541: E/AndroidRuntime(26925): at com.as.asapp.TFragment.toggleInformationView(TFragment.java:64)
11-08 17:25:48.541: E/AndroidRuntime(26925): at com.as.asapp.TFragmentshowInformation(TFragment.java:52)
11-08 17:25:48.541: E/AndroidRuntime(26925): at com.as.asapp.TFragment.onCreateView(TFragment.java:37)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.os.Handler.handleCallback(Handler.java:739)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.os.Handler.dispatchMessage(Handler.java:95)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.os.Looper.loop(Looper.java:135)
11-08 17:25:48.541: E/AndroidRuntime(26925): at android.app.ActivityThread.main(ActivityThread.java:5221)
11-08 17:25:48.541: E/AndroidRuntime(26925): at java.lang.reflect.Method.invoke(Native Method)
11-08 17:25:48.541: E/AndroidRuntime(26925): at java.lang.reflect.Method.invoke(Method.java:372)
11-08 17:25:48.541: E/AndroidRuntime(26925): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
11-08 17:25:48.541: E/AndroidRuntime(26925): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Comprobando, parece que getWidth()
y getHeight()
devuelven 0. Pero no sé si es el problema real. Gracias
Así es como lo resolví, agregué un oyente onLayoutChange a la vista en la devolución de llamada onCreateView, así que cada vez que se adjunta a la vista y está listo para dibujar, hace la revelación.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_map_list, container, false);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
toggleInformationView(view);
}
});
}
return view;
}
Estaba usando la vista personalizada, así que isAttachedToWindow()
método isAttachedToWindow()
para verificar si la vista está adjunta y evitar hacer revelaciones mientras la vista no está adjunta
Pequeña adición a Hitesh''s respuesta Hitesh''s . Es mejor usar https://developer.android.com/reference/android/support/v4/view/ViewCompat.html#isAttachedToWindow(android.view.View)
android.support.v4.view.ViewCompat
boolean isAttachedToWindow (View view)
Ejemplo:
LinearLayout rootView = null;
rootView = (LinearLayout) findViewById(R.id.rootView);
boolean isAttachedToWindow = ViewCompat.isAttachedToWindow(rootView);
Puedes usar runnable para hacer la animación. El ejecutable se ejecutará después de la creación de la vista.
view.post(new Runnable() {
@Override
public void run() {
//create your anim here
}
});
Simplificado fuera del alcance de la pregunta.
private void startAnimation(@NonNull final View view, @NonNull final OnAttachedToWindow onAttachedToWindow) {
if (view.isAttachedToWindow()) {
onAttachedToWindow.execute();
} else {
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
onAttachedToWindow.execute();
}
@Override
public void onViewDetachedFromWindow(View view) {
}
});
}
}
private interface OnAttachedToWindow {
void execute();
}
llame a startAnimation para una o varias animaciones en mente
startAnimation(view, new OnAttachedToWindow() {
@Override
public void execute() {
//the code inside toggleInformationView(view)
}
});
Trate de llamarlo en el método onViewCreated
Utilice un ViewTreeObserver.
ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
revealActivity(revealX, revealY);
rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
Verifique que su Diseño esté adjunto a la ventana o no mediante el método rootLayout.isAttachedToWindow()
.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (rootLayout!= null) {
if(rootLayout.isAttachedToWindow()) {
ViewTreeObserver viewTreeObserver = drawerLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
startRevealAnimation(rootLayout);
rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
}
}
ah !!!, así que finalmente aquí está la solución para este error. En realidad, el problema es que estamos asignando una vista a la animación con su altura y anchura, y de repente no notamos que puede haber un caso, esa vista no se cargará correctamente en el momento en que la asignamos a la animación. Así que para eso, tenemos que esperar hasta que la vista se cargue correctamente.
LayoutInflater inflater = this.getLayoutInflater();
View rowView = inflater.inflate( R.layout.fileselecttype,null, true );
rowView or [Your View]
[Your View].post(new Runnable() {
@Override
public void run() {
//Do your animation work here.
}
});