Android - 使用动画改变左边距

68

我正在按照以下方式更改图像视图的左边距:

ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) image.getLayoutParams ();
layoutParams.leftMargin = VALUE;
image.setLayoutParams ( layoutParams );

我希望边距的改变能够带有动画效果。有什么线索吗?

我尝试过的:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat ( image , "x" , VALUE);
objectAnimator.start();

这种方法的移动图片效果非常完美,但是layoutParams.leftMargin的值保持不变!!因此我无法使用这种方法,因为如果我在使用值为100的objectAnimator后尝试将layoutParams.leftMargin的值更改为100,那么应用的值就不正确(200被应用而不是100),即使我以以下方式设置左边距,objectAnimator的效果仍然存在:

layoutParams.leftMargin = 100;

请参考以下使用ViewPropertyAnimator的简单解决方案:https://stackoverflow.com/a/33077358/1438339 - Adam Johns
5个回答

142
使用Animation类而不是ObjectAnimator。
final int newLeftMargin = <some value>;
Animation a = new Animation() {

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        LayoutParams params = yourView.getLayoutParams();
        params.leftMargin = (int)(newLeftMargin * interpolatedTime);
        yourView.setLayoutParams(params);
    }
};
a.setDuration(500); // in ms
yourView.startAnimation(a);

请注意,您应该使用正确的LayoutParams类。即,如果您的视图是LinearLayout的子项,则params应为LinearLayout.LayoutParams。

14
别忘了设置动画的持续时间,我在没有设置动画持续时间时遇到了一些问题:a.setDuration(duration); - Brandon Romano
1
当我尝试使用params.leftMargin时,出现了错误。显然它不是一个字段。 - Soroush
2
这是因为有很多LayoutParams类。例如 - ViewGroup.LayoutParams,FrameLayout.LayoutParams,LinearLayout.LayoutParams等。 ViewGroup.LayoutParams没有leftMargin字段,但RelativeLayout.LayoutParams有。 - user1991679
1
根据http://developer.android.com/reference/android/view/animation/Animation.html#Animation(),默认持续时间为0毫秒,因此您必须设置持续时间。 - Sean Barbeau
1
如果我想让newLeftMargin为0怎么办? - Ashkan Sarlak
显示剩余4条评论

98

我看到了这个问题,但是我无法使用它,因为我想将外边距从负值动画到0,所以我使用了valueAnimator,基于user1991679的答案:

final View animatedView = view.findViewById(R.id.animatedView);
final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) animatedView.getLayoutParams();
ValueAnimator animator = ValueAnimator.ofInt(params.bottomMargin, 0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator)
    {
        params.bottomMargin = (Integer) valueAnimator.getAnimatedValue();
        animatedView.requestLayout();
    }
});
animator.setDuration(300);
animator.start();

你需要根据动画视图容器更改LinearLayout.LayoutParams。 对于没有ValueAnimator的旧版本,您可以使用nineoldandroids。


您可以使用Animation类将边距从负值动画到0。没有任何限制。 - user1991679
@user1991679,您如何使用“Animation”类将动画从400播放到200? - StuStirling
4
假设200是newMargin(我们应该进行动画的边距),而400是currentMargin(我们要从中进行动画的边距)。在这种情况下,代码将如下所示:@Override protected void applyTransformation(float interpolatedTime, Transformation t) { LayoutParams params = yourView.getLayoutParams(); params.leftMargin = currentMargin - (int)((currentMargin - newMargin) * interpolatedTime); yourView.setLayoutParams(params); } - user1991679
1
我在这里遇到了奇怪的重绘问题。看起来我的布局经常出现波动。 - Michael
@MikeMilla 在FrameLayout中使用它,LinearLayout会产生不良效果。 - Ali
@Ali 我有些失望,最终还是使用了上面的答案。 - Michael

17

用户user1991679的回答很好,但是如果你需要从除0以外的任何其他值插值边距,你需要在计算中使用它:

ViewGroup.MarginLayoutParams params = (MarginLayoutParams) mBottomLayout.getLayoutParams();
final int bottomMarginStart = params.bottomMargin; // your start value
final int bottomMarginEnd = <your value>; // where to animate to
Animation a = new Animation() {
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        ViewGroup.MarginLayoutParams params = (MarginLayoutParams) mBottomLayout.getLayoutParams();
        // interpolate the proper value
        params.bottomMargin = bottomMarginStart + (int) ((bottomMarginEnd - bottomMarginStart) * interpolatedTime);
        mBottomLayout.setLayoutParams(params);
    }
};
a.setDuration(300);
mBottomLayout.startAnimation(a);

在我的情况下,我需要执行一个“进入屏幕”的动画,从“-48dp”到0。没有起始值,动画总是为0,因此会跳跃,而不是对视图进行动画处理。解决方案是插值偏移量并将其添加到原始值中。


我尝试过这个。虽然结果是正确的位置,但它不再执行动画了。有什么想法吗?如果我回到非计算的东西,动画就可以正常工作。 - HideAndSeek
当设置起始点后,您可以设置断点以查看输入内容。如果跳转,则意味着您正在分配错误的值。在我的代码片段中,bottomMarginStart从视图中读取,假设视图应该从其位置开始动画。 - Björn Kechel

0

对我来说,没有任何东西能像我想要的那样工作... 我需要从-80 dp(旧左边距)创建ToggleMenu到0dp。 底部边距也是如此。 现在它可以正常工作:

final int oldLeftMargin = (int) getResources().getDimension(R.dimen.left_menu_button_margin_left);
    Animation a = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) llMeniuToggle.getLayoutParams();
            params.leftMargin = oldLeftMargin + (int) ((0 - oldLeftMargin) * interpolatedTime);
            llMeniuToggle.setLayoutParams(params);
        }
    };
    a.setDuration(500);
    llMeniuToggle.startAnimation(a);

-3
你可以使用以下代码。
image.animate().setDuration(durationIn).translationXBy(offsetFloat).start();

你也可以添加 .setInterpolator(new BounceInterpolator()) 来改变动画的外观。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接