动画不流畅

5

我制作了一个应用程序,在其中的按钮单击时,我已经滑动了一个线性布局。滑动线性布局的代码运行良好,但问题是它在滑动时出现延迟。此外,我设置的用于滑动布局的高度在所有屏幕尺寸上看起来都不太合适(特别是在Nexus 5上)。请帮助我解决这个问题。

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/iv_upload_add"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/add" />


        <LinearLayout
            android:id="@+id/ll_upload_options"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:background="@drawable/choosefile_bg"
            android:gravity="center"
            android:orientation="vertical">

            <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.TextViewGeneral
                android:id="@+id/tv_upload_gallery"
                style="@style/text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="GALLERY"
                android:textSize="20sp"
                android:visibility="visible" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="1dp"
                android:layout_marginLeft="30dp"
                android:layout_marginRight="30dp"

                android:background="@drawable/line" />

            <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.TextViewGeneral
                android:id="@+id/tv_upload_camera"
                style="@style/text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="bottom"
                android:padding="5dp"
                android:text="CAMERA"
                android:textSize="20sp"
                android:visibility="visible" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="1dp"
                android:layout_marginLeft="30dp"
                android:layout_marginRight="30dp"

                android:background="@drawable/line" />

            <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.TextViewGeneral
                android:id="@+id/tv_upload_file"
                style="@style/text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="bottom"
                android:padding="5dp"
                android:text="FILE"
                android:textSize="20sp"
                android:visibility="visible" />


        </LinearLayout>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_gravity="center"
        android:layout_marginLeft="@dimen/all_left_mar"
        android:layout_marginRight="@dimen/all_right_mar"
        android:layout_weight="2"
        android:gravity="center"
        android:orientation="vertical">

        <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.EditTextFont
            style="@style/edit_text"
            android:drawableBottom="@drawable/line_black"
            android:hint="File Title"
            android:textColor="#000"
            android:textColorHint="#000" />

        <AutoCompleteTextView
            style="@style/edit_text"
            android:layout_marginTop="10dp"
            android:completionThreshold="1"
            android:drawableBottom="@drawable/line_black"
            android:hint="Type"
            android:textColor="#000"
            android:textColorHint="#000" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <Switch
                android:id="@+id/switch1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:checked="false"
                android:textOff="No"
                android:textOn="Yes" />

            <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.TextViewGeneral
                style="@style/text_view"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="3"
                android:text="@string/Protect"
                android:textColor="#000" />

        </LinearLayout>

        <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.EditTextFont
            style="@style/edit_text"
            android:layout_marginTop="10dp"
            android:drawableBottom="@drawable/line_black"
            android:hint="Password"
            android:inputType="numberPassword"
            android:textColor="#000"
            android:textColorHint="#000" />


    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginLeft="@dimen/all_left_mar"
        android:layout_marginRight="@dimen/all_right_mar"
        android:layout_weight="1">

        <pocketdocs.indiehustlers.com.pocketdocsv2.Utils.ButtonFont
            style="@style/button"
            android:text="UPLOAD" />
    </LinearLayout>

</LinearLayout>

代码

if (llUploadOptions.getMeasuredHeight() != 0) {

//                    tvGallery.setVisibility(View.GONE);
//                    tvCamera.setVisibility(View.GONE);
//                    tvFile.setVisibility(View.GONE);

                    ValueAnimator anim = ValueAnimator.ofInt(llUploadOptions.getMeasuredHeight(),200);
                    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator valueAnimator) {
                            int val = (Integer) valueAnimator.getAnimatedValue();
                            ViewGroup.LayoutParams layoutParams = llUploadOptions.getLayoutParams();
                            layoutParams.height = val;
                            llUploadOptions.setLayoutParams(layoutParams);
                        }
                    });
                    anim.setDuration(700);
                    anim.start();
                } else {
                    ValueAnimator anim = ValueAnimator.ofInt(llUploadOptions.getMeasuredHeight(),250);
                    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator valueAnimator) {
                            int val = (Integer) valueAnimator.getAnimatedValue();
                            ViewGroup.LayoutParams layoutParams = llUploadOptions.getLayoutParams();
                            layoutParams.height = val;
                            llUploadOptions.setLayoutParams(layoutParams);
                        }
                    });
                    anim.setDuration(700);
                    anim.start();

                }
2个回答

5
问题在于,您正在尝试动画化布局的高度。这意味着,每次动画步骤中调用setLayoutParams()都会强制整个布局(包括子元素)通过浏览完整个视图层次结构进行重新布局,从而导致动画卡顿。布局是一项昂贵的操作!
有一些"解决方法"(我不确定您想要做什么):
  1. 自Android 4.0以来,您可以简单地在xml中使用animate layout changes,如果您只想在布局中显示/隐藏元素并带有动画效果
  2. 对于更复杂的事情,您可能需要考虑使用Kitkat(Api 19)中引入的转换框架https://www.youtube.com/watch?v=S3H7nJ4QaD8。向后兼容:https://github.com/guerwan/TransitionsBackporthttps://github.com/andkulikov/transitions-everywhere
  3. 通过手动设置翻译,alpha等属性为视图进行“伪造”动画,并在动画完成后仅一次设置LayoutParams
  4. 我不记得API叫什么,但您可以从ViewGroup子类化并将其用作根布局。在动画高度时必须拦截布局更改,以某种方式实现平滑的动画(这就是animateLayoutChanges = true的工作原理)。然而,这是一个高级话题,我建议采用其他方法之一进行操作

请查看此视频 https://www.youtube.com/watch?v=xXpNUeUHfWE ,从20:35开始......他们正在讨论动画高度,这也是我在第4点谈论的内容。 - sockeqwe
请注意,Chet 正在说:“如果在动画期间发生重新布局,你可能会度过糟糕的一天...”,从 26:20 开始。 - sockeqwe

3

您正在使用Animators(而不是Animations),这可能会导致卡顿,特别是在移动小部件时。尝试使用TranslateAnimation

TranslateAnimation animation = new TranslateAnimation(0.0f, 200.0f,
        0.0f, 0.0f);          
//  these are delta's, check doc for this constructor
//  TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
animation.setDuration(700);     

llUploadOptions.startAnimation(animation);

如果您想让动画视图保留其最终坐标,请使用以下方法:

animation.setFillAfter(true);

但它可能无法被点击,或者可能出现其他问题。对于这些问题,您可以使用

animation.setAnimationListener(new AnimationListener() {
                public void onAnimationStart(Animation anim)
                {
                };
                public void onAnimationRepeat(Animation anim)
                {
                };
                public void onAnimationEnd(Animation anim)
                {
                    //set fixed position in here, using LayoutParams or setTop/setRight etc. methods of View (API 11)
                };
            });

编辑:

所以,与其使用ValueAnimator,您可以尝试这样做:

int desiredHeightInPx = getResources().getDimensionPixelSize(R.dimen.expandedHeight);
//note those are pixels, not dp. you might set this as =200 or =250 like you have

ScaleAnimation animation = new ScaleAnimation(0, 0, 0, desiredHeightInPx/llUploadOptions.getMeasuredHeight(), Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);
animation.setDuration(1000); //ms
llUploadOptions.startAnimation(animation);

下一步如上所述,使用fillAfter或设置AnimationListener并在onAnimationEnd内设置最终的LayoutParams。
请注意,ScaleAnimation正在缩放,可能更适合使用RelativeLayout而不是线性布局(它会重新调整其子元素的大小)。

但我希望LinearLayout在ImageView下方开始。 - Anuj
我看到你正在改变大小(高度),因此更适合的动画是ScaleAnimation(并且只缩放一个维度)。你可以随意处理这个,但我不理解LinearLayout中“从下方开始”的ImageView是什么意思。请注意,动画化的View不能更大(例如缩放/调整大小)或超出父级边界(平移/移动)。 - snachmsm
请问您能提供代码吗?因为我对安卓和动画非常新手。 - Anuj
R.dimen.expandedHeight是什么? - Anuj
你在资源文件中使用的尺寸应该是以 dp 为单位,而不是 px。你所设定的值 200/250 是固定的像素单位,这对于不同密度的屏幕并不好。 - snachmsm
显示剩余2条评论

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