55

我有一个带有项目列表的活动,当您单击一个项目时,我希望该项目的播放控件从屏幕底部向上滑动并变得可见。我已经为滑入和滑出定义了一个动画集,它们可以工作。我已经在我的活动中设置了我的animationListener,并在一个项目的onClick 动画中开始了我的幻灯片。我的问题是,第一次运行应用程序时,当我单击一个项目时,会执行 onClick 回调,但动画不会发生。第二次单击时,动画中的幻灯片会发生,但不会滑出。第三次及以后,它按预期工作。这是我的动画集。

vm_slide_in.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
           android:fillAfter="true">
    <translate
        android:fromYDelta="800"
        android:toYDelta="0"
        android:duration="600" />
</set>

vm_slide_out.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
           android:fillAfter="true">
    <translate
        android:fromYDelta="0"
        android:toYDelta="800"
        android:duration="600" />
</set>

这是我的活动布局

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/AppBG">
    <RelativeLayout 
        style="@style/LogoBar" 
        android:id="@+id/logo_bar"      
        android:layout_alignParentTop="true">
        <include layout="@layout/logobar"></include>
    </RelativeLayout>
    <RelativeLayout 
        style="@style/TitleBar" 
        android:id="@+id/title_bar"     
        android:layout_below="@+id/logo_bar">
        <include layout="@layout/titlebar"></include>"
        <Button style="@style/TitleBarButton"
            android:id="@+id/vm_speaker_btn"
            android:text="@string/vm_speaker_btn_label" 
            android:layout_alignParentLeft="true"
            android:layout_margin="4dp">
        </Button>
        <Button style="@style/TitleBarButton"
            android:id="@+id/vm_edit_btn"
            android:text="@string/vm_edit_btn_label" 
            android:layout_alignParentRight="true"
            android:layout_margin="4dp">
        </Button>
    </RelativeLayout>
    <ListView
        android:id="@+id/@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_bar"/>
    <RelativeLayout
        android:id="@+id/vm_control_panel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/footer"
        android:visibility="gone">
        <include layout="@layout/vm_control"/>
    </RelativeLayout>
    <RelativeLayout
        android:id="@+id/footer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <include layout="@layout/taskbar"/>
    </RelativeLayout>
</RelativeLayout>

这是包含的控件的布局

    <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <RelativeLayout 
        android:id="@+id/vm_control"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/dark_grey">
        <TextView
            android:id="@+id/vm_ctl_branding"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:text="@string/branding"
            android:textColor="@color/white">
        </TextView>
        <TextView style="@style/TimeMark"
            android:id="@+id/vm_timestamp"
            android:layout_toLeftOf="@+id/vm_progress"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_marginRight="3dp"
            android:text="0:00">
        </TextView>
        <SeekBar
            android:id="@+id/vm_progress"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_centerHorizontal="true">
        </SeekBar>
        <TextView style="@style/TimeMark"
            android:id="@+id/vm_timeleft"
            android:layout_toRightOf="@+id/vm_progress"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_marginLeft="3dp"
            android:text="-0:00">
        </TextView>
        <LinearLayout
            android:id="@+id/vm_action_button_layout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/vm_timestamp"
            android:layout_alignRight="@+id/vm_timeleft"
            android:orientation="horizontal"
            android:layout_below="@+id/vm_progress">
            <TextView style="@style/Vm_Action_Button"
                android:background="@drawable/vm_action_btn_call"
                android:id="@+id/vm_callback_btn"
                android:layout_marginRight="5dp"
                android:text="@string/vm_action_btn_callback">
            </TextView>
            <TextView style="@style/Vm_Action_Button"
                android:background="@drawable/vm_action_btn_delete"
                android:id="@+id/vm_delete_btn"
                android:layout_marginLeft="5dp"
                android:text="@string/vm_action_btn_delete">
            </TextView>
        </LinearLayout>
    </RelativeLayout>
</merge>

从我的 onCreate 方法...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.startAnimation(mSlideIn);
    }
});

我的动画回调......

@Override
public void onAnimationStart(Animation animation) {
    vm_controls_in = !vm_controls_in;
    if (vm_controls_in) {
        vVm_controls.setVisibility(View.GONE);
    } else {
        vVm_controls.setVisibility(View.VISIBLE);
        // vVm_controls.bringToFront();
    }
}

@Override
public void onAnimationEnd(Animation animation) {
    if (!vm_controls_in) {
        try {
            Thread.sleep(1000);
            vVm_controls.startAnimation(mSlideOut);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

@Override
public void onAnimationRepeat(Animation animation) {
    // TODO Auto-generated method stub

}
4

11 回答 11

139

正如您所发现的,问题在于可见性。当视图最初在 xml 文件中设置为消失时,Android 将不会呈现布局,直到可见性更改为可见或不可见。如果您尝试在尚未渲染的视图上设置动画,则动画将在没有布局的视图上发生。动画完成后,它会渲染它,突然视图会出现没有动画。它在随后的时间里工作,因为即使设置为消失,视图也有一个布局。

关键是将可见性设置为不可见而不是在 xml 文件中消失,以便呈现但隐藏。当动画第一次出现时,视图会按预期移动。

于 2012-03-12T04:41:16.410 回答
12

当然不是在发布这个问题后 20 分钟,我就发现了我的问题。由于我将布局的可见性设置为“GONE”,因此当我尝试在其上启动动画时,它并没有第一次触发。不知道为什么它会出现第二次和随后的时间,但如果我在开始动画之前将可见性设置为“可见”,它就解决了问题。这是我更改它的代码...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.setVisibility(View.VISIBLE);
        vVm_controls.startAnimation(mSlideIn);
    }
});
于 2010-12-21T19:43:17.793 回答
6

我不知道它是否仍然是最新的,但是是的,这是可见性的问题。因此,我将 xml 文件中的可见性设置为不可见,并在初始化视图的位置调用:

view.post(new Runnable() {
    @Override
    public void run() {
        view.animate().translationY(view.getHeight());
    }
};

现在打电话

view.animate().translationY(0).setListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
        view.setVisibility(View.VISIBLE);
    }
}

也是第一次工作。

于 2015-06-15T01:42:34.363 回答
3

即使我在动画开始时将视图设置为可见,也遇到了完全相同的问题。我听从了 brockoli 的建议,在开始动画之前将其设置为可见,它就像一个魅力。

前:

Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_left);
animation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        view.setVisibility(View.VISIBLE);
    }

    @Override
    public void onAnimationEnd(Animation animation) { }

    @Override
    public void onAnimationRepeat(Animation animation) {       }
);
view.startAnimation(animation);

后:

Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_left);
view.setVisibility(View.VISIBLE);
view.startAnimation(animation);
于 2017-04-01T20:03:30.923 回答
3

如果可见性是问题,您只需要在渲染后延迟动画,例如:

vVm_controls.setVisibility(View.INVISIBLE);
vVm_controls.post(() -> vVm_controls.startAnimation(mSlideIn));
于 2019-07-26T14:07:52.033 回答
3

当前的许多答案对我不起作用,唯一起作用的答案是 using onFocusWindowChange(),但我不喜欢该解决方案。

我解决此问题的方法:首先将view您尝试设置动画的当前设置为invisible在您的 xml 布局中。

接下来在布局中添加一个监听器,以便在绘制完成onCreate时通知您:view

mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mLayout.setVisibility(View.GONE);
                mLayout.animate()
                        .translationX(-mLayout.getWidth());
                        
                mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });

完成渲染后将其移出屏幕

于 2021-01-03T11:39:06.800 回答
2

我在 Android 4.4.3 中遇到了类似的问题。我尝试了大多数提出的解决方案,但只有一个解决方案对我来说很好。您必须在窗口完成渲染后运行动画,最好的方法是在onWindowFocusChanged内运行它。不要通过 runnable 使用延迟,因为它会影响您在高速手机中的应用程序性能。

@Override
public void onWindowFocusChanged (boolean hasFocus) {
   super.onWindowFocusChanged(hasFocus);
   if (hasFocus)
      yourView.startAnimation(anim);
}

更多信息可以在这篇文章中找到: https ://damianflannery.wordpress.com/2011/06/08/start-animation-in-oncreate-or-onresume-on-android/

于 2016-08-12T00:16:39.160 回答
1

如果您在设置适配器 ty 后使用 RecyclerView 并加载列表项,请使用此

recyclerView.scheduleLayoutAnimation();

adapter.notifyDataSetChanged();

它适用于我的情况

于 2020-12-03T19:08:42.700 回答
0

我有完全相同的问题,但是通过使用ViewPropertyAnimator. 例如,您声明一个GridView被调用的mGridView. 您现在所要做的就是打电话mGridView.animate()给您想要的更改。

我的动画GridView被触发了,但由于未知的情况,没有实际的动画可见。我也全部更改View.GONEView.VISIBLE,但它没有改变任何东西。就我而言,我发现我只需要android:requiresFadingEdge="vertical"在我的 XML 中删除这个特定的GridView. 可能无法将 Fading Edge 与ViewPropertyAnimator.

于 2014-06-07T08:54:15.713 回答
0

即使根本没有使用 Visibility.GONE,整个 SO 的答案都没有对我有用。

所以我最终得到了创可贴,有一天我会研究它。

我的临时解决方案是将高度设置为 1px(而不是 0dp,这使得在我的情况下无法工作)并将可见性设置为 INVISIBLE。所以我最终损失了 1px,但很难注意到。

代码:

调整大小动画.kt

class ResizeAnimation(private val view: View, private val newHeight: Int) : Animation() {
    private val initialHeight: Int = view.layoutParams.height
    private val deltaHeight: Int

    init {
        deltaHeight = newHeight - initialHeight
    }

    override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
        view.layoutParams.height = (initialHeight + deltaHeight * interpolatedTime).toInt()
        view.requestLayout()
    }

    override fun willChangeBounds(): Boolean {
        return true
    }
}

用法:

private fun displayProgressBar() {
        progressBar.visibility = View.VISIBLE
        val animation = ResizeAnimation(progressBar, 78).apply {
            duration = inAnimationDuration
        }
        progressBar.startAnimation(animation)
    }

private fun removeProgressBar() {
        val animation = ResizeAnimation(progressBar, 1).apply {
            duration = outAnimationDuration
        }
        progressBar.startAnimation(animation)
        progressBar.visibility = View.INVISIBLE
    }

请不要将其视为最终解决方案,将其视为创可贴。

于 2020-08-24T09:46:24.590 回答
-2

我知道这个问题很老,但我的回答可能对其他人有所帮助。当我们需要动画视图但默认情况下它的可见性消失时,请在 xml 中设置所有属性隐藏代码对于我的情况,我在 java 文件中使用了 translationY 和 alpha。我在第一次运行时做了一些简单的事情来解决问题。然后添加代码中使用的所有 XML 属性。

于 2019-01-02T14:06:23.097 回答