简体   繁体   English

如何设置布局的宽度和高度的动画?

[英]How to animate the width and height of a Layout?

I have a LinearLayout which is expanded to full screen by hiding all other layouts and views on onClick . 我有一个LinearLayout ,它通过隐藏onClick上的所有其他布局和视图扩展到全屏。 There is a Relativelayout above LinearLayout LinearLayout之上有一个Relativelayout

I want to apply custom animation on this. 我想对此应用自定义动画。 The size should should increase slowly (like in 500 milli seconds). 尺寸应该缓慢增加(如在500毫秒内)。

But I doubt is it possible? 但我怀疑是否可能? Thanks. 谢谢。

Here is what I am doing onClick : 这是我正在做的onClick

private void expandView (int viewId) {
    RelativeLayout relativeLayout = (RelativeLayout) ((LinearLayout) view.findViewById(viewId)).getParent();
    ViewGroup.MarginLayoutParams rlMargin = (ViewGroup.MarginLayoutParams) relativeLayout.getLayoutParams();
    rlMargin.setMargins(0, 0, 0, 0);
    relativeLayout.setLayoutParams(rlMargin);
    LinearLayout linearLayout = (LinearLayout) relativeLayout.getParent();
    hideAllLinearLayoutExcept(linearLayout.getId());
    hideAllTilesExcept(viewId);
}

viewId is the id of the LinearLayout I am clicking. viewId是我点击的LinearLayout的id。 This function is called from onClick() onClick()调用此函数

Sure that is possible. 当然有可能。

Simply write your own custom-animation and modify the LayoutParams of your animated view. 只需编写自己的自定义动画并修改动画视图的LayoutParams In this example, the animation animates the height of the animated View. 在此示例中,动画为动画视图的高度设置动画。 Of course, animating the width is also possible . 当然, 也可以设置宽度的动画

This is how it could look like: 这是它的样子:

public class ResizeAnimation extends Animation {

    private int startHeight;
    private int deltaHeight; // distance between start and end height
    private View view;

    /**
     * constructor, do not forget to use the setParams(int, int) method before
     * starting the animation
     * @param v
     */
    public ResizeAnimation (View v) {
        this.view = v;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        view.getLayoutParams().height = (int) (startHeight + deltaHeight * interpolatedTime);
        view.requestLayout();
    }

    /**
     * set the starting and ending height for the resize animation
     * starting height is usually the views current height, the end height is the height
     * we want to reach after the animation is completed
     * @param start height in pixels
     * @param end height in pixels
     */
    public void setParams(int start, int end) {

        this.startHeight = start;
        deltaHeight = end - startHeight;
    }

    /**
     * set the duration for the hideshowanimation
     */
    @Override
    public void setDuration(long durationMillis) {
        super.setDuration(durationMillis);
    }

    @Override
    public boolean willChangeBounds() {
        return true;
    }
}   

In code, create a new Animation and apply it to the RelativeLayout that you want to animate: 在代码中, 创建一个新动画并将其应用于要设置动画的RelativeLayout

RelativeLayout relativeLayout = (RelativeLayout) ((LinearLayout) view.findViewById(viewId)).getParent();

// getting the layoutparams might differ in your application, it depends on the parent layout
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();

ResizeAnimation a = new ResizeAnimation(relativeLayout);
a.setDuration(500);

// set the starting height (the current height) and the new height that the view should have after the animation
a.setParams(lp.height, newHeight);

relativeLayout.startAnimation(a);

I was looking for this for hours and Philipp Jahoda's answer was the perfect one since it can be added to an AnimationSet as well. 我几个小时都在寻找这个,Philipp Jahoda的答案是完美的,因为它也可以添加到AnimationSet中。 I made a couple of small modifications to support a more similar constructor to the default animation class (except for the View parameter) and to support the "fillEnabled" property. 我进行了一些小的修改,以支持与默认动画类(View参数除外)更相似的构造函数,并支持“fillEnabled”属性。

public class ResizeAnimation extends Animation
{

private int startWidth;
private int deltaWidth; // distance between start and end height
private int startHeight;
private int deltaHeight;

private int originalWidth;
private int originalHeight;
private View view;

private boolean fillEnabled = false;


public ResizeAnimation(View v, int startW, int endW, int startH, int endH)
{
    view = v;
    startWidth = startW;
    deltaWidth = endW - startW;

    startHeight = startH;
    deltaHeight = endH - startH;

    originalHeight = v.getHeight();
    originalWidth = v.getWidth();
}

@Override
public void setFillEnabled(boolean enabled)
{
    fillEnabled = enabled;
    super.setFillEnabled(enabled);
}


@Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
    if(interpolatedTime == 1.0 && !fillEnabled)
    {
        view.getLayoutParams().height = originalHeight;
        view.getLayoutParams().width = originalWidth;
    }
    else
    {
        if(deltaHeight != 0)
            view.getLayoutParams().height = (int) (startHeight + deltaHeight * interpolatedTime);
        if(deltaWidth != 0)
            view.getLayoutParams().width = (int) (startWidth + deltaWidth * interpolatedTime);
    }

    view.requestLayout();
}
}

Here's a simplified, more general (any parameter of layout), Xamarin version. 这是一个简化的,更通用的(任何布局参数),Xamarin版本。

public class SizeAnimation : Animation 
{
    private int _newValue;
    private int _initialValue;
    private string _property;
    private object _target;
    private View _view;

    public SizeAnimation (View view, string property, int newValue)
    {
        _view = view;
        _property = property;
        _newValue = newValue;
        _target = view.LayoutParameters;

        // View measure is generally an enum of wrap_content / fill_parent
        // we need to make the measure explicit
        if (property == "Width" || property == "Height")
        {
            view.Measure ((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified);
            var unmeasuredValue = (int)view.GetType().GetProperty(property).GetValue(view);
            _initialValue = unmeasuredValue < 1
                ? (int) view.GetType().GetProperty("Measured" + _property).GetValue(view)
                : unmeasuredValue;

            view.LayoutParameters.GetType().GetProperty(property).SetValue(view.LayoutParameters,_initialValue);
        } else
        {
            _initialValue = (int) _target.GetType ().GetProperty (property).GetValue(_target);
        }
    }

    protected override void ApplyTransformation(float interpolatedTime, Transformation t) 
    {
        _target.GetType().GetProperty(_property).SetValue(_target, (int)(_initialValue + (_newValue - _initialValue) * interpolatedTime));
        _view.RequestLayout();  
    }

    public override bool WillChangeBounds() 
    {
        return true;
    }
}

Usage: 用法:

var property = "Width";
var value = 120;
var animation = new SizeAnimation(myView, property, value);
animation.Duration = 2000;
animation.Interpolator = (new LinearInterpolator());
myView.StartAnimation(animation);

"Theorically" working, not fully tested. “理论上”工作,没有经过充分测试。

I worked with the answer by Philipp Jahoda . 我使用Philipp Jahoda的答案。 Here is an implementation that works for both expand and collapse animations based on the start and end values we pass. 这是一个适用于基于我们传递的起始值和结束值的展开和折叠动画的实现。 Hope it helps. 希望能帮助到你。

https://gist.github.com/rahulrvp/dcccd1b78cd09b31a024 https://gist.github.com/rahulrvp/dcccd1b78cd09b31a024

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM