28

我指的是此处找到的展开/折叠动画代码。

Android:展开/折叠动画

虽然它有效,但它并不能很好地完成这项工作。动画不流畅。

我在代码中做了一些记录。

public static void expand(final View v) {
    v.measure(MeasureSpec.makeMeasureSpec(((View)v.getParent()).getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(1024, MeasureSpec.AT_MOST));
    final int targtetHeight = v.getMeasuredHeight();

    v.getLayoutParams().height = 0;
    v.setVisibility(View.VISIBLE);
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            v.getLayoutParams().height = interpolatedTime == 1
                    ? LayoutParams.WRAP_CONTENT
                    : (int)(targtetHeight * interpolatedTime);
            Log.i("CHEOK", "E v.getLayoutParams().height = " + v.getLayoutParams().height);
            v.requestLayout();
        }

打印以下日志消息。

10-09 12:29:58.808: I/CHEOK(7874): E v.getLayoutParams().height = 0
10-09 12:29:58.808: I/CHEOK(7874): E v.getLayoutParams().height = 0
10-09 12:29:58.918: I/CHEOK(7874): E v.getLayoutParams().height = 11
10-09 12:29:59.015: I/CHEOK(7874): E v.getLayoutParams().height = 35
10-09 12:29:59.117: I/CHEOK(7874): E v.getLayoutParams().height = 64
10-09 12:29:59.215: I/CHEOK(7874): E v.getLayoutParams().height = 85
10-09 12:29:59.316: I/CHEOK(7874): E v.getLayoutParams().height = -2
10-09 12:29:59.406: I/CHEOK(7874): E v.getLayoutParams().height = -2

每~100ms出现新的高度。所以,动画的FPS大约是10fps

我想看看理想的动画帧率是多少。我删除v.requestLayout();. 我得到以下日志记录。

10-09 12:32:06.547: I/CHEOK(8926): E v.getLayoutParams().height = 0
10-09 12:32:06.562: I/CHEOK(8926): E v.getLayoutParams().height = 0
10-09 12:32:06.605: I/CHEOK(8926): E v.getLayoutParams().height = 4
10-09 12:32:06.625: I/CHEOK(8926): E v.getLayoutParams().height = 7
10-09 12:32:06.644: I/CHEOK(8926): E v.getLayoutParams().height = 10
10-09 12:32:06.664: I/CHEOK(8926): E v.getLayoutParams().height = 14
10-09 12:32:06.679: I/CHEOK(8926): E v.getLayoutParams().height = 18
10-09 12:32:06.699: I/CHEOK(8926): E v.getLayoutParams().height = 22
10-09 12:32:06.715: I/CHEOK(8926): E v.getLayoutParams().height = 27
10-09 12:32:06.734: I/CHEOK(8926): E v.getLayoutParams().height = 32
10-09 12:32:06.750: I/CHEOK(8926): E v.getLayoutParams().height = 37
10-09 12:32:06.769: I/CHEOK(8926): E v.getLayoutParams().height = 42
10-09 12:32:06.785: I/CHEOK(8926): E v.getLayoutParams().height = 47
10-09 12:32:06.804: I/CHEOK(8926): E v.getLayoutParams().height = 52
10-09 12:32:06.828: I/CHEOK(8926): E v.getLayoutParams().height = 59
10-09 12:32:06.840: I/CHEOK(8926): E v.getLayoutParams().height = 62
10-09 12:32:06.863: I/CHEOK(8926): E v.getLayoutParams().height = 67
10-09 12:32:06.879: I/CHEOK(8926): E v.getLayoutParams().height = 71
10-09 12:32:06.894: I/CHEOK(8926): E v.getLayoutParams().height = 75
10-09 12:32:06.910: I/CHEOK(8926): E v.getLayoutParams().height = 79
10-09 12:32:06.929: I/CHEOK(8926): E v.getLayoutParams().height = 82
10-09 12:32:06.945: I/CHEOK(8926): E v.getLayoutParams().height = 85
10-09 12:32:06.965: I/CHEOK(8926): E v.getLayoutParams().height = 88
10-09 12:32:06.984: I/CHEOK(8926): E v.getLayoutParams().height = 89
10-09 12:32:07.000: I/CHEOK(8926): E v.getLayoutParams().height = 91
10-09 12:32:07.019: I/CHEOK(8926): E v.getLayoutParams().height = 91
10-09 12:32:07.039: I/CHEOK(8926): E v.getLayoutParams().height = -2
10-09 12:32:07.054: I/CHEOK(8926): E v.getLayoutParams().height = -2

新高度每~20ms出现一次。所以,动画的FPS大约是50fps

当然,我不能只删除requestLayout,因为 UI 不会在屏幕上更新。

我想知道,有没有什么改进可以实现动画FPS接近50fps?我看过一些带有平滑展开/折叠示例的商业产品。所以,我认为这是可以实现的。就是这样,我不确定到底是怎么回事。

我的布局代码如下:

        <LinearLayout
            android:clickable="true"
            android:id="@+id/chart_linear_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:background="@drawable/dummy"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:orientation="horizontal">
                <TextView
                    android:layout_width="0dp"
                    android:width="0dp"
                    android:layout_weight="0.6"
                    android:layout_height="wrap_content"
                    android:gravity="left"
                    android:textSize="20sp" 
                    android:textColor="#ff000000"
                    android:text="Summary chart" />
                <TextView
                    android:id="@+id/chart_price_text_view"
                    android:layout_width="0dp"
                    android:width="0dp"
                    android:layout_weight="0.4"
                    android:layout_height="wrap_content"
                    android:gravity="right"
                    android:textSize="20sp" 
                    android:textColor="#ffF76D3C"
                    android:text="$2.99" />

            </LinearLayout>
            <TextView
                android:visibility="gone"
                android:id="@+id/chart_description_text_view"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"         
                android:text="@string/currency_exchange_description"
                android:textColor="#ff626262"
                android:textSize="15sp" />                 
        </LinearLayout>

我希望在chart_description_text_viewfrom上执行流畅的动画

折叠(在应用程序启动期间)

在此处输入图像描述

扩展(当用户点击它时)

在此处输入图像描述

我能想到的“榜样”之一是https://play.google.com/store/apps/details?id=ch.bitspin.timely。尝试从其Shop菜单项中调用以下对话框。你会意识到他们的动画是多么流畅。不完全确定他们是如何实现这一目标的。

在此处输入图像描述

4

5 回答 5

87

您可以通过以下方式对视图进行平滑动画处理:

public class ViewAnimationUtils {

    public static void expand(final View v) {
        v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        final int targtetHeight = v.getMeasuredHeight();

        v.getLayoutParams().height = 0;
        v.setVisibility(View.VISIBLE);
        Animation a = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                v.getLayoutParams().height = interpolatedTime == 1
                        ? LayoutParams.WRAP_CONTENT
                        : (int)(targtetHeight * interpolatedTime);
                v.requestLayout();
            }

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

        a.setDuration((int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }

    public static void collapse(final View v) {
        final int initialHeight = v.getMeasuredHeight();

        Animation a = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                if(interpolatedTime == 1){
                    v.setVisibility(View.GONE);
                }else{
                    v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                    v.requestLayout();
                }
            }

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

        a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }
}

希望它会帮助你。

于 2015-07-30T09:37:16.443 回答
27

制作动画的最简单方法是将以下内容添加到您的线性布局的 xml 中:

android:animateLayoutChanges="true"

它工作得很好,并且直接使用来自 Android 的默认动画

于 2014-12-03T20:14:08.810 回答
17

它很容易在视图上获得平滑的动画(展开/折叠)

public void expandOrCollapse(final View v,String exp_or_colpse) {
    TranslateAnimation anim = null;
    if(exp_or_colpse.equals("expand"))
    {
        anim = new TranslateAnimation(0.0f, 0.0f, -v.getHeight(), 0.0f);
        v.setVisibility(View.VISIBLE);  
    }
    else{
        anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, -v.getHeight());
        AnimationListener collapselistener= new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
            v.setVisibility(View.GONE);
            }
        };

        anim.setAnimationListener(collapselistener);
    }

     // To Collapse
        //

    anim.setDuration(300);
    anim.setInterpolator(new AccelerateInterpolator(0.5f));
    v.startAnimation(anim);
}

并在您的代码中使用此方法。我在 TextView 中使用过,并且已经过测试。您可以在此方法中将视图作为参数传递。

        TextView tv=(TextView)findViewById(R.id.textview);
          //TO Expand 
         expandOrCollapse(tv,"expand");

        //TO Collapse
        expandOrCollapse(tv,"collapse");

并享受流畅的折叠和展开动画......

于 2014-05-29T11:57:25.210 回答
7

这是 Github 上 SlideExpandibleList 的一个很好的例子。

https://github.com/tjerkw/Android-SlideExpandableListView

希望这将帮助您实现流畅的动画和折叠。

在这个例子中,它保存了展开列表项的状态。因此,即使您向下滚动列表,它也不会让展开的列表项关闭。

在此示例中,按钮上给出了展开或折叠事件,因此您需要更改它的列表项父布局。

我附上了屏幕截图。

希望这会帮助你。

在此处输入图像描述

于 2013-10-09T05:08:34.617 回答
6

这是 kotlin 方式的平滑动画。我向@TomEsterez 答案添加了一些淡入淡出动画:

扩张:

  fun expand(v: View) {
        if (v.visibility == View.VISIBLE) return
        val durations: Long
        val matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(
            (v.parent as View).width,
            View.MeasureSpec.EXACTLY
        )
        val wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(
            0,
            View.MeasureSpec.UNSPECIFIED
        )
        v.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
        val targetHeight = v.measuredHeight

        // Older versions of android (pre API 21) cancel animations for views with a height of 0.
        v.layoutParams.height = 1
        v.visibility = View.VISIBLE
        durations = ((targetHeight / v.context.resources
            .displayMetrics.density)).toLong()

        v.alpha = 0.0F
        v.visibility = View.VISIBLE
        v.animate().alpha(1.0F).setDuration(durations).setListener(null)

        val a: Animation = object : Animation() {
            override fun applyTransformation(
                interpolatedTime: Float,
                t: Transformation
            ) {
                v.layoutParams.height =
                    if (interpolatedTime == 1f) LinearLayout.LayoutParams.WRAP_CONTENT else (targetHeight * interpolatedTime).toInt()
                v.requestLayout()
            }

            override fun willChangeBounds(): Boolean {
                return true
            }
        }

        // Expansion speed of 1dp/ms
        a.duration = durations
        v.startAnimation(a)
    }

坍塌

fun collapse(v: View) {
        if (v.visibility == View.GONE) return
        val durations: Long
        val initialHeight = v.measuredHeight
        val a: Animation = object : Animation() {
            override fun applyTransformation(
                interpolatedTime: Float,
                t: Transformation
            ) {
                if (interpolatedTime == 1f) {
                    v.visibility = View.GONE
                } else {
                    v.layoutParams.height =
                        initialHeight - (initialHeight * interpolatedTime).toInt()
                    v.requestLayout()
                }
            }

            override fun willChangeBounds(): Boolean {
                return true
            }
        }

        durations = (initialHeight / v.context.resources
            .displayMetrics.density).toLong()

        v.alpha = 1.0F
        v.animate().alpha(0.0F).setDuration(durations)
            .setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    v.visibility = View.GONE
                    v.alpha = 1.0F
                }
            })

        // Collapse speed of 1dp/ms
        a.duration = durations
        v.startAnimation(a)
    }

这是输出结果

然后,您可以根据需要旋转图标。(

// Expande
exImgHeader.animate().rotation(180f).start()
// Collapse
exImgHeader.animate().rotation(0f).start()

) 结果将是这样的:

在此处输入图像描述

于 2021-04-26T06:07:05.400 回答