Android - 第一个动画出现的行为不同
Posted
技术标签:
【中文标题】Android - 第一个动画出现的行为不同【英文标题】:Android - first animation occurrence acts differently 【发布时间】:2020-09-07 20:32:49 【问题描述】:在我的应用程序中创建简单动画时遇到了一些问题,我为此苦苦挣扎了好几个小时。
我有一个 LinearLayout,其中包含隐藏在 Image View 后面的元素,并且应该在 click 事件上显示(通过在布局宽度上设置动画)。如果我从 LinearLayout 内部删除元素,一切都运行良好,但是因为布局的子级正在推动其宽度(这意味着即使布局宽度设置为 0,它仍会被内部元素推至宽度 +/- 100dp)我在隐藏布局时遇到问题。
但是,执行动画时并非如此 - 当我将布局设置为宽度为 0 时,它会正确裁剪子项。但是一旦动画完成 - 布局由孩子们推动。我有一个想法让布局默认裁剪它的孩子,但我尝试了多种解决方案,但都没有奏效。然后我想也许我会在动画完成后隐藏元素(可见性消失)。它“有点”解决了这个问题 - 但我仍然遇到第一次出现“显示”动画的问题。
我正在做的是 - 一开始我将布局宽度设置为 0 并将其与其子项一起隐藏(将其设置为可见性消失)。然后在“显示”动画中,我在 onAnimationStart 方法中使布局及其子项可见,然后动画将布局宽度从 0 增加到 156dp。 “隐藏”动画已恢复 - 我正在将布局宽度减小到 0,并且 onAnimationEnd 我正在隐藏布局及其内容。问题是,由于某种原因,第一次显示动画被调用并且我在 onAnimationStart 中使布局和视图可见,这段代码与动画实际开始的时刻之间存在差距,这使得视图在之前的一瞬间可见动画开始。
这是它的外观: hidden,shown。这是它的xml代码:
<LinearLayout
android:id="@+id/linSettingsPopup"
android:layout_
android:layout_
app:layout_constraintTop_toTopOf="@id/imgProfilePicture"
app:layout_constraintBottom_toBottomOf="@id/imgProfilePicture"
app:layout_constraintRight_toRightOf="@id/imgProfilePicture"
android:layout_marginEnd="24dp"
android:background="@drawable/settings_popup_container"
android:orientation="horizontal"
android:gravity="center|start"
android:visibility="visible">
<ImageButton
android:id="@+id/btnLogout"
android:layout_
android:layout_
android:layout_marginStart="24dp"
android:layout_marginEnd="22dp"
android:background="@drawable/logout"
android:visibility="visible">
</ImageButton>
<ImageButton
android:id="@+id/btnSettings"
android:layout_
android:layout_
android:background="@drawable/settings"
android:visibility="visible">
</ImageButton>
</LinearLayout>
为了更好地了解正在发生的事情,这里是所有内容的代码。 在 onCreate 方法期间设置视图(当然,此时视图已分配给变量):
private void initializeSettingsPopup()
settingsPopupWidth = linSettingsPopup.getLayoutParams().width;
linSettingsPopup.getLayoutParams().width = 0;
linSettingsPopup.requestLayout();
btnLogout.setVisibility(View.GONE);
btnSettings.setVisibility(View.GONE);
linSettingsPopup.setVisibility(View.GONE);
动画:
public class ResizeWidthAnimation extends Animation
private int mWidth;
private int mStartWidth;
private View mView;
public ResizeWidthAnimation(View view, int width)
mView = view;
mWidth = width;
mStartWidth = view.getWidth();
@Override
protected void applyTransformation(float interpolatedTime, Transformation t)
int newWidth = mStartWidth + (int) ((mWidth - mStartWidth) * interpolatedTime);
mView.getLayoutParams().width = newWidth;
mView.requestLayout();
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight)
super.initialize(width, height, parentWidth, parentHeight);
@Override
public boolean willChangeBounds()
return true;
调用动画:
private void showSettingsPopup()
linSettingsPopup.setVisibility(View.INVISIBLE);
settingsPopupShown = true;
ResizeWidthAnimation resizeAnimation = new ResizeWidthAnimation(linSettingsPopup, settingsPopupWidth);
resizeAnimation.setDuration(350);
resizeAnimation.setAnimationListener(new Animation.AnimationListener()
@Override
public void onAnimationStart(Animation animation)
linSettingsPopup.setVisibility(View.VISIBLE);
btnLogout.setVisibility(View.VISIBLE);
btnSettings.setVisibility(View.VISIBLE);
);
linSettingsPopup.startAnimation(resizeAnimation);
private void hideSettingsPopup()
settingsPopupShown = false;
ResizeWidthAnimation resizeAnimation = new ResizeWidthAnimation(linSettingsPopup, 0);
resizeAnimation.setDuration(350);
resizeAnimation.setAnimationListener(new Animation.AnimationListener()
@Override
public void onAnimationEnd(Animation animation)
linSettingsPopup.setVisibility(View.GONE);
btnLogout.setVisibility(View.GONE);
btnSettings.setVisibility(View.GONE);
);
linSettingsPopup.startAnimation(resizeAnimation);
我还要补充一点,我设法通过延迟一点“显示”动画的 onAnimationStart 方法中的代码来解决这个问题。但是感觉更像是避免问题而不是解决问题,所以我希望有人能指出我做错了什么,并有一些好主意我可以如何解决这个问题。
【问题讨论】:
【参考方案1】:一段时间后,我终于找到了一个不需要对视图可见性进行任何操作的“解决方案”。事实证明,如果布局宽度为 0dp,内部的视图将不断推动它,这使得布局尽可能宽以适应其子级。但是,如果我将布局宽度设置为 1dp,它实际上会削减其中的视图。因此,我没有在隐藏时将布局宽度从 156dp 设置为 0dp,而是将其从 156dp 设置为 1dp,并且它可以正常工作而没有任何问题。这是它的工作代码:
private static final int SETTINGS_POPUP_ANIM_DURATION = 350;
private static final int SETTINGS_POPUP_HIDDEN_WIDTH = 1;
private void initializeSettingsPopup()
settingsPopupWidth = linSettingsPopup.getLayoutParams().width;
linSettingsPopup.getLayoutParams().width = SETTINGS_POPUP_HIDDEN_WIDTH;
linSettingsPopup.requestLayout();
private void showSettingsPopup()
settingsPopupShown = true;
ResizeWidthAnimation resizeAnimation = new ResizeWidthAnimation(linSettingsPopup, settingsPopupWidth);
resizeAnimation.setDuration(SETTINGS_POPUP_ANIM_DURATION);
linSettingsPopup.startAnimation(resizeAnimation);
private void hideSettingsPopup()
settingsPopupShown = false;
ResizeWidthAnimation resizeAnimation = new ResizeWidthAnimation(linSettingsPopup, SETTINGS_POPUP_HIDDEN_WIDTH);
resizeAnimation.setDuration(SETTINGS_POPUP_ANIM_DURATION);
linSettingsPopup.startAnimation(resizeAnimation);
【讨论】:
以上是关于Android - 第一个动画出现的行为不同的主要内容,如果未能解决你的问题,请参考以下文章
使用 [UIView animateKeyframesWithDuration] 为 UIView 设置动画的奇怪行为
Android ListView 项目动画 - 仅动画第一个可见项目