我在自己的应用中创建简单的动画时遇到了一些问题,需要花费数小时的时间。
我有一个LinearLayout,其中的元素隐藏在Image View的后面,应该在click事件中显示(通过对布局宽度进行动画处理)。如果我从LinearLayout内部删除元素,一切都会很好,但是由于布局的子级正在推动其宽度(这意味着,即使布局的width设置为0,其内部的元素仍会将其推入宽度+/- 100dp)我在隐藏布局时遇到问题。
但是执行动画不是这种情况-当我将布局动画设置为宽度0时,它将正确裁剪子代。但是,一旦动画完成,布局就会被孩子们推动。我有一个想法,使布局默认情况下裁剪其子级,但是我尝试了多种解决方案,但没有一个起作用。然后我想也许动画结束后我只会隐藏元素(可见性消失了)。它“有点”解决了这个问题-但我还是第一次出现“显示”动画时遇到了问题。
[我正在做的-在一开始,我将布局宽度设置为0,并将其及其子项隐藏(将其可见性设置为隐藏)。然后在“显示”动画上,我通过onAnimationStart方法使布局及其子级可见,然后动画将布局宽度从0增加到156dp。 “隐藏”动画将还原-我将布局宽度减小为0,而onAnimationEnd我隐藏了布局及其内容。问题是由于某种原因,第一次调用显示动画,并且我在onAnimationStart中使布局和视图可见,因此这段代码与动画实际开始的时间之间存在间隙,从而使视图在一秒钟之前可见动画开始。
<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方法内的代码设法解决了这个问题。但是,感觉起来比解决问题更像是避免问题,因此我希望有人可以指出我做错了什么,并对如何解决这个问题有一些好主意。
一段时间后,我终于找到了不需要对视图可见性进行任何操作的“解决方案”。事实证明,如果布局宽度为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);
}