草庐IT

android - fragment 共享元素转换不适用于 ViewPager

coder 2023-06-05 原文

我的应用程序包含一个 View ,该 View 由一个 ViewPager 组成,该 ViewPager 由一些 fragment 组成。当您单击这些 fragment 之一中的项目时,预期行为是共享元素(在本例中为图像)转换到显示有关单击内容的更多信息的 fragment 。

这是一个非常简单的视频,它应该是什么样子:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-114842.mp4

这只是使用 Fragment->Fragment 过渡。

将起始 fragment 放在 ViewPager 中时会出现问题。我怀疑这是因为 ViewPager 使用其父 fragment 的子 fragment 管理器,它与处理 fragment 事务的 Activity 的 fragment 管理器不同。以下是发生的视频:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-120029.mp4

正如我上面解释的那样,我很确定这里的问题是子 fragment 管理器与 Activity 的 fragment 管理器。以下是我的过渡方式:

SimpleFragment fragment = new SimpleFragment();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.am_list_pane, fragment, fragment.getClass().getSimpleName());

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    TransitionSet enterTransition = new TransitionSet();
    enterTransition.addTransition(new ChangeBounds());
    enterTransition.addTransition(new ChangeClipBounds());
    enterTransition.addTransition(new ChangeImageTransform());
    enterTransition.addTransition(new ChangeTransform());

    TransitionSet returnTransition = new TransitionSet();
    returnTransition.addTransition(new ChangeBounds());
    returnTransition.addTransition(new ChangeClipBounds());
    returnTransition.addTransition(new ChangeImageTransform());
    returnTransition.addTransition(new ChangeTransform());

    fragment.setSharedElementEnterTransition(enterTransition);
    fragment.setSharedElementReturnTransition(returnTransition);

    transaction.addSharedElement(iv, iv.getTransitionName());
}

transaction.addToBackStack(fragment.getClass().getName());

transaction.commit();

当两个 fragment 都由 Activity 的 fragment 管理器管理时,这工作正常,但是当我像这样加载 ViewPager 时:

ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(new Adapter(getChildFragmentManager()));

ViewPager 的子项不再由 Activity 管理,它不再工作。

这是 Android 团队的疏忽吗?有什么办法可以解决这个问题吗?谢谢。

最佳答案

您可能已经找到了答案,但如果您还没有找到答案,这就是我在摸索了几个小时后所做的解决方法。

我认为这个问题是两个因素的结合:

  • ViewPager 中的 Fragments 加载延迟,这意味着 Activity 返回的速度比 ViewPager< 中包含的="" fragment="">

  • 如果你和我一样,你的 ViewPager 的子 fragment 很可能是同一类型。这意味着,它们都共享相同的过渡名称(如果您已在 xml 布局中设置它们),除非您在代码中设置它们并且只在可见 fragment 上设置一次

为了解决这两个问题,我这样做了:

1.修复延迟加载问题:

在您的 Activity (包含 ViewPager 的 Activity )中,在 super.onCreate() 之后和 setContentView() 之前添加这一行:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActivityCompat.postponeEnterTransition(this); // This is the line you need to add

    setContentView(R.layout.feeds_content_list_activity);
    ...
}

<强>2。修复多个 fragment 具有相同过渡名称的问题:

现在有很多方法可以做到这一点,但这就是我在“详细” Activity 中最终得到的结果,即包含 ViewPager 的 Activity (在 onCreate() 但你真的可以在任何地方做):

_viewPager.setAdapter(_sectionsPagerAdapter);
_viewPager.setCurrentItem(position);
...
...
_pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic));

您需要小心,因为 Activity 可能尚未附加到您的 ViewPager fragment ,因此将过渡名称从 Activity 传递给 fragment 会更容易如果您从资源中加载它

实际的实现和你想象的一样简单:

public void setTransitionName(String transitionName) {
    _transitionName = transitionName;
}

然后在 fragment 的 onViewCreated() 中,添加以下行:

public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    ...
    if (_transitionName != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        setTransitionNameLollipop();
    }
    ...
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setTransitionNamesLollipop() {
    _imgTopic.setTransitionName(_transitionName);
}

最后一个难题是找出 fragment 何时完全加载,然后调用 ActivityCompat.startPostponedEnterTransition(getActivity());

在我的情况下,我的 fragment 直到后来才完全加载,因为我从 UI 线程中加载了大部分内容,这意味着我必须想办法在加载所有内容时调用它,但如果不是你的情况,你可以在您调用 setTransitionNameLollipop() 后立即调用它。

这种方法的问题是退出转换可能不起作用,除非您非常小心并在您退出 Activity 以返回之前重置“可见” fragment 上的转换名称。可以像这样轻松完成:

  1. 在您的 ViewPager
  2. 上收听页面变化
  3. 一旦您的 fragment 不在视野范围内,请立即删除过渡名称
  4. 在可见 fragment 上设置过渡名称。
  5. 不调用 finish(),而是调用 ActivityCompat.finishAfterTransition(activity);

如果您返回转换需要转换到 RecyclerView 这是我的情况,这很快就会变得非常复杂。为此,@Alex Lockwood 在这里提供了一个更好的答案:ViewPager Fragments – Shared Element Transitions这里有一个写得很好的示例代码(尽管比我刚刚写的要复杂得多):https://github.com/alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/activity/transitions

就我而言,我不必去实现他的解决方案,而我发布的上述解决方案适用于我的案例。

如果您有多个共享元素,我相信您可以弄清楚如何扩展方法以满足它们的需求。

关于android - fragment 共享元素转换不适用于 ViewPager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30628543/

有关android - fragment 共享元素转换不适用于 ViewPager的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  4. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  5. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  6. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  7. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  8. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  9. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  10. ruby - inverse_of 是否适用于 has_many? - 2

    当我使用has_one时,它​​工作得很好,但在has_many上却不行。在这里您可以看到object_id不同,因为它运行了另一个SQL来再次获取它。ruby-1.9.2-p290:001>e=Employee.create(name:'rafael',active:false)ruby-1.9.2-p290:002>b=Badge.create(number:1,employee:e)ruby-1.9.2-p290:003>a=Address.create(street:"123MarketSt",city:"SanDiego",employee:e)ruby-1.9.2-p290

随机推荐