活动和共享视图之间的动画:动画结束时出现故障/破解?

Posted

技术标签:

【中文标题】活动和共享视图之间的动画:动画结束时出现故障/破解?【英文标题】:Animation between Activities and shared views: glitchy/hack at the ends of animation? 【发布时间】:2015-01-23 06:29:29 【问题描述】:

所以,我面临的问题是我在两个活动和两个共享视图之间做的动画看起来不太好。

问题在于它的“故障”,当从 Activity2 回到 Activity1 时,共享的 TextViews 在动画结束时会闪烁,显示来自 Activity2 的“更大的文本”只有几分之一秒,所以它“闪烁”。

Activity 1(RecyclerView 有三个项目):

活动二(详情):

我在制作动画的同时拍摄了屏幕。当从 Activity2 回到 Activit2 时,您可以看到文本在最后闪烁。这段视频(36MB,大小抱歉)展示了它:

https://drive.google.com/file/d/0B3wIZ9CS9Kj_a0MyVFlzX1YtY0E/view?usp=sharing

问题是:我做错了什么?为什么会这样闪烁?我看过其他动画的视频,它们都非常流畅和漂亮。

我已经测试了不同类型的转换(changeBounds、explode 等),但总会发生一些奇怪的事情。任何提示,想法将不胜感激 =)

我的代码

主活动(Activity1):

package se.snapcode.lollipoptest;

import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.util.Pair;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.support.v7.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends Activity 

    private RecyclerView mRecyclerView;
    private MyAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    GestureDetectorCompat gestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // specify an adapter (see also next example)
        String[] strings = new String[3];
        strings[0] = "A1";
        strings[1] = "A2";
        strings[2] = "A3";
        mAdapter = new MyAdapter(strings);
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setOnItemClickListener(new OnItemClickListener() 
            @Override
            public void onItemClick(View view, int position) 
                final TextView headerView = (TextView)view.findViewById(R.id.textView1);
                final TextView textView = (TextView)view.findViewById(R.id.textView2);
                Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
                intent.putExtra("header", headerView.getText().toString());
                intent.putExtra("text", textView.getText().toString());

                ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, Pair.create((View)headerView, "header"),
                        Pair.create((View)textView, "text"));

                startActivity(intent, options.toBundle());
            
        );

        RecyclerView.ItemDecoration itemDecoration =
                new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
        mRecyclerView.addItemDecoration(itemDecoration);

        // this is the default; this call is actually only necessary with custom ItemAnimators
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    

DetailsActivity(活动2):

package se.snapcode.lollipoptest;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;


public class DetailsActivity extends Activity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);

        String header = getIntent().getStringExtra("header");
        String text = getIntent().getStringExtra("text");

        TextView tv1 = (TextView)findViewById(R.id.tv_details_header);
        tv1.setText(header);
        TextView tv2 = (TextView)findViewById(R.id.tv_details_text);
        tv2.setText(text);
    

还有布局,首先是 RecyclerView 列表中的 my_text_view:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_
    android:layout_
    android:clickable="true"
    android:focusable="true"
    android:background="?android:attr/selectableItemBackground"
    android:colorControlHighlight="@android:color/holo_blue_light"
    android:padding="10dp">

    <TextView
        android:layout_
        android:layout_
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="MY HEADER IS HERE"
        android:transitionName="header"
        android:id="@+id/textView1" />

    <TextView
        android:layout_
        android:layout_
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="This is some text that is of relevance"
        android:transitionName="text"
        android:id="@+id/textView2" />
</LinearLayout>

还有activity_details.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_
    android:layout_ android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="se.snapcode.lollipoptest.DetailsActivity">

    <TextView android:id="@+id/tv_details_header" android:text="A1" android:layout_
        android:transitionName="header"
        android:textSize="48dp"
        android:layout_ />

    <TextView android:id="@+id/tv_details_text" android:text="Some text of lesser importance" android:layout_
        android:textSize="24dp"
        android:transitionName="text"
        android:layout_ />

</LinearLayout>

还有过渡xml(在/res/transition中):

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeBounds/>
    <explode />
</transitionSet>

还有styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
        <!-- enable window content transitions -->
        <item name="android:windowContentTransitions">true</item>

        <!-- specify enter and exit transitions -->
        <item name="android:windowEnterTransition">@android:transition/slide_left</item>
        <item name="android:windowExitTransition">@android:transition/slide_right</item>

        <!-- specify shared element transitions -->
        <item name="android:windowSharedElementEnterTransition">
            @transition/change_image_transform</item>
        <item name="android:windowSharedElementExitTransition">
            @transition/change_image_transform</item>
    </style>
</resources>

【问题讨论】:

我认为这个答案可能会对您有所帮助:***.com/a/26813670/758458 感谢您的意见。那么,在我的情况下,在 XML 中定义动画/过渡是行不通的,也不好?你认为这是谷歌的官方立场吗? 事实证明,共享对象转换比我预期的要麻烦一些。我希望谷歌会改进文档,因为它缺乏。 @Ted 您如何使用您在问题中引用的“transition xml (in /res/transition)”代码 sn-p?我不明白你为什么要在同一个TransitionSet 中添加一个explode 转换一个changeBounds 转换。 explode 将视图动画显示在屏幕外,而 changeBounds 将视图从一个特定位置/大小动画到屏幕内的另一个...所以并行运行这两个对我来说没有任何意义。 @Ted 另外,您在上一个代码 sn-p 中引用了 @transition/change_image_transform。您能否在您的问题中发布您的change_image_transform.xml 文件的内容? 【参考方案1】:

问题是您正在尝试使用ChangeBounds 转换将TextView 的大小设置为共享元素。由于ChangeBounds 的工作方式,这将不起作用。 ChangeBounds 过渡在过渡的开始和结束处分析视图的布局边界,并在两者之间设置动画。 ChangeBounds 适用于任意视图,因此在转换期间它不会在您的TextView 上调用setTextSize()...如果您想查看@987654329,您需要使用自定义转换自己做@ 的大小在动画期间无缝增加/减少。 this *** answer 中有一些关于如何执行此操作的信息。

【讨论】:

所以,链接到上面的答案详细说明了实现一个过渡类。我看不出谷歌会如何认为有人会想出编写这样一个类的想法。我是一个非常有经验的编码员,我不知道如何编写该类。看起来很麻烦很乱。 但是。基本上,我复制了那个 Transition 类,然后把它添加到 XML 中,像这样? 我只是尝试过,添加了java类,如上更改转换xml(使用正确的包名),但是动画不存在,只是从一个活动跳转到下一个活动,同样文字出现“故障”... @Ted Android 框架不能总是满足你的所有需求。有时你只需要自己写。 :) 自定义转换实际上并没有那么复杂......它基本上只是一个围绕Animator 的包装器,它为文本视图的TextSize 设置动画。唯一困难的部分是学习如何编写自定义Transition(因为目前没有很多文档解释应该如何完成)。但在我查看了框架默认转换的源代码后,这很容易弄清楚。 啊哈,感谢您的意见。但是,我一定是做错了什么,因为如果我根本没有做任何动画,所以,其他的话没有效果=)对不起,我似乎遗漏了一些东西。

以上是关于活动和共享视图之间的动画:动画结束时出现故障/破解?的主要内容,如果未能解决你的问题,请参考以下文章

为基于 flex 框的进度条设置动画时出现一个奇怪的故障

UIView 滑动动画故障

如何避免在 jQuery 动画 [fadeIn() 或 animate()] 结束时出现文本闪烁?

片段之间动画的共享元素

滑动 UIView 时出现动画错误

从 UINavigationController (IOS 5) 弹出 UIViewController 时出现奇怪的动画