首页 > 解决方案 > Android - 第一个动画出现的行为不同

问题描述

在我的应用程序中创建一个简单的动画时,我遇到了一些问题,我挣扎了好几个小时。

我有一个 LinearLayout,其中的元素隐藏在 Image View 后面,应该在 click 事件上显示(通过在布局宽度上设置动画)。如果我从 LinearLayout 内部删除元素,一切都运行良好,但是因为布局的子级正在推动其宽度(这意味着即使布局宽度设置为 0,它仍会被内部元素推至宽度 +/- 100dp)我在隐藏布局时遇到问题。

但是,执行动画时并非如此 - 当我将布局设置为宽度为 0 时,它会正确裁剪子项。但是一旦动画完成 - 布局由孩子们推动。我有一个想法让布局默认裁剪它的孩子,但我尝试了多种解决方案,但都没有奏效。然后我想也许我会在动画完成后隐藏元素(可见性消失)。它“有点”解决了这个问题 - 但我仍然遇到第一次出现“显示”动画的问题。

我正在做的是 - 一开始我将布局宽度设置为 0 并将其与其子项一起隐藏(将其设置为可见性消失)。然后在“显示”动画中,我在 onAnimationStart 方法中使布局及其子项可见,然后动画将布局宽度从 0 增加到 156dp。“隐藏”动画已恢复 - 我将布局宽度减小到 0,并且 onAnimationEnd 我正在隐藏布局及其内容。问题是,由于某种原因,第一次显示动画被调用并且我在 onAnimationStart 中使布局和视图可见,这段代码与动画实际开始的时刻之间存在差距,这使得视图在之前的一瞬间可见动画开始。

这就是它的外观: hiddenshown。这是它的xml代码:

<LinearLayout
    android:id="@+id/linSettingsPopup"
    android:layout_width="156dp"
    android:layout_height="56dp"
    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_width="32dp"
        android:layout_height="32dp"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="22dp"
        android:background="@drawable/logout"
        android:visibility="visible">

    </ImageButton>

    <ImageButton
        android:id="@+id/btnSettings"
        android:layout_width="32dp"
        android:layout_height="32dp"
        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 方法中的代码来解决这个问题。然而,感觉更像是避免问题而不是解决问题,所以我希望有人能指出我做错了什么,并知道我该如何解决这个问题。

标签: javaandroidandroid-layoutandroid-animation

解决方案


过了一会儿,我终于找到了一个不需要对视图可见性进行任何操作的“解决方案”。事实证明,如果布局宽度为 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);
}

推荐阅读