转换pdf时共享有冲突_共享元素转换中的隐藏错误

转换pdf时共享有冲突

There is a good practice to make your application beautiful and live, and nowadays there are a lot of tools and ways to achieve this. One of them is Shared Element Transition.

有一种很好的做法可以使您的应用程序美观和生动,如今,有许多工具和方法可以实现这一目标。 其中之一是共享元素转换。

In this article I’ll cover a few mistakes which have cost me a lot of time; I’ll show how to avoid them if you decide to implement this kind of transitions with Fragments on application.

在本文中,我将介绍一些错误,这些错误花费了我很多时间; 如果您决定在应用程序中使用Fragments实现这种过渡,我将展示如何避免它们。

开始吧 (Get started)

Before making the animation I’ve read dozens of articles but most of them were about Activity Transition. However, I came across a really good ones about Fragments and I want to give a little recap on how to create Shared Element Transition.

在制作动画之前,我已经阅读了数十篇文章,但其中大多数都是关于“活动过渡”的。 但是,我遇到了有关Fragments的非常好的文章,我想对如何创建Shared Element Transition进行一些回顾。

Here are main steps to create animation:

以下是创建动画的主要步骤:

  1. Enable setReorderingAllowed(true). It allows to reorder a calling the lifecycle methods and your animation will be displayed correctly.

    启用setReorderingAllowed(true) 。 它允许对调用生命周期方法进行重新排序,并且动画将正确显示。

  2. Call addSharedElement() and add the views that will be shared between screens

    调用addSharedElement()并添加将在屏幕之间共享的视图

  3. Add unique android:transitionName on each view in transition

    在转换中的每个视图上添加唯一的android:transitionName transitionName

  4. Add sharedElementEnterTransition/sharedElementReturnTransition in destination fragment. Optionally: for better effect we can also set enterTransition/exitTransition.

    在目标片段中添加sharedElementEnterTransition/sharedElementReturnTransition 。 可选:为了获得更好的效果,我们还可以设置enterTransition/exitTransition

  5. Add postponeEnterTransition/startPostponedEnterTransition to define the moment when the data is loaded and UI is ready to be drawn

    添加postponeEnterTransition/startPostponedEnterTransition来定义加载数据和准备绘制UI的时刻

Seems like that’s enough to build animation and make your designers and users happy. BUT there are always some accidents. Let’s take a look what we’ll have if we take the steps listed above:

看起来足以制作动画并使您的设计师和用户满意。 但是总会有一些意外。 让我们看看如果采取上面列出的步骤将会得到什么:

动画损坏 (Broken animation)

That’s not what we expected. Let’s figure it out.

那不是我们所期望的。 让我们弄清楚。

错误#1。 静态transitionNames(浪费了半天) (Mistake #1. Static transitionNames (half a day wasted))

As I said before, our Views should have unique transition names — otherwise the transition framework won’t be able to recognize which View take part with transition and will make it without them. So where is a problem?

如前所述,我们的视图应具有唯一的过渡名称-否则过渡框架将无法识别哪个View参与过渡,并且没有过渡时将使其参与。 那么哪里有问题呢?

The thing is RecyclerView. That’s it.

事情是RecyclerView。 而已。

If there is RecyclerView and an animating view is a part of RecyclerView item, you should build and set transitionName dynamically (forget about XML). Besides, you should do it in both fragments even if the second one doesn’t have RecyclerView.

如果有RecyclerView,并且动画视图是RecyclerView项的一部分,则应动态构建和设置transitionName (忘记XML)。 此外,即使第二个片段没有RecyclerView,也应在两个片段中都执行此操作。

So the fix is:

因此解决方法是:

val transitionNameImage = context.getString(R.string.transition_image, title)

You might have noticed I put «title» as an argument to get a unique name. It’s better to use domain model instead of, for instance, item position on the screen, because there is no need to pass these names as arguments to Bundle and parse them from the second Fragment.

您可能已经注意到,我将“ title”作为自变量来获得唯一的名称。 最好使用域模型而不是例如屏幕上的项目位置,因为不需要将这些名称作为参数传递给Bundle并从第二个Fragment解析它们。

错误2。 不考虑父片段(浪费了1.5天) (Mistake #2. Not considering parent fragment (1.5 days wasted))

I know, you might ask «How come?». But when I was reading the articles about shared animation, no one considered an example in complex fragment’s hierarchy. That’s why you might sometimes not pay attention to it.

我知道,您可能会问《为什么?》。 但是,当我阅读有关共享动画的文章时,没有人考虑过复杂片段层次结构中的示例。 这就是为什么您有时可能不注意它的原因。

So, my first fragment was a child of fragment’s container and no wonder that postponeEnterTransition()/startPostponedEnterTransition() had no effect.

因此,我的第一个片段是该片段的容器的子片段,也难怪postponeEnterTransition()/startPostponedEnterTransition()无效。

这里是 (Here it is)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        parentFragment?.also { parentFragment ->
            NewsTransitioner.setupFirstFragment(parentFragment)
            parentFragment.postponeEnterTransition()
        }
        // Initialization UI
}

What you need to do here is to call these methods from parent fragment.

您需要在此处从父片段调用这些方法。

错误3。 低估滑行(浪费了2天) (Mistake #3. Underestimating Glide (2 days wasted))

«Ok, I’ve learnt how to make shared transition, when to call required methods regarding the lifecycle and the loading. This time it’s gonna work!»

«好,我已经学会了如何进行共享转换,何时调用有关生命周期和加载的必需方法。 这次它将起作用!»

Well I was wrong. This is perhaps the trickiest mistake I’ve faced. Let’s take a look at what we have so far:

好吧,我错了。 这也许是我遇到的最棘手的错误。 让我们来看看到目前为止的情况:

当前动画 (Current animation)

You may notice there is a weird glitch with enter transition. When it starts, the image has already changed matrix and then just move to the final position.

您可能会注意到在输入过渡时出现了一个奇怪的故障。 开始时,图像已经改变了矩阵,然后仅移动到最终位置。

I don’t want to describe the whole investigation here. Long story short, I was lucky to stumble across a nice article.

我不想在这里描述整个调查。 长话短说,我很幸运偶然发现一篇不错的文章

Where I found solution. Here it is:

我在哪里找到解决方案。 这里是:

“We have this glitch because Glide tries to optimize image loading. By default, Glide is resizing and trimming images to match the target view.”

“我们有这个小故障,因为Glide试图优化图像加载。 默认情况下,Glide会调整图像大小和修剪以匹配目标视图。”

In order to fix it, I added, no jokes, a single line of code like this to initialization Glide’s chain:

为了解决这个问题,我没有开玩笑地将一行这样的代码添加到初始化Glide的链中:

Glide
    .with(target)
    .load(url)
    .apply(
        RequestOptions().dontTransform() // this line
    )

So, you should disable any Glide’s transformations on images if they’re involved in a shared transition.

因此,如果图像涉及共享转换,则应禁用它们的任何Glide转换。

错误#4。 错误地管理postPostponeTransition() (Mistake #4. Incorrectly managing postPostponeTransition())

Honestly, it’s not exactly a mistake but still I assume it would be good to mention.

老实说,这不是一个错误,但我仍然认为应该提一下。

When it comes to manage postPostponeTransition() and startPostponedEnterTransition() methods, you should select the right moment. The moment is when the UI is already to be drawn.

在管理postPostponeTransition()startPostponedEnterTransition()方法时,您应该选择合适的时机。 现在是已经绘制UI的时候。

There are two main points we should know before calling the methods:

在调用方法之前,我们应该知道两点:

  • on the one hand, when images with transition are loaded and ready

    一方面,当加载具有过渡的图像并准备就绪时
  • on the other hand, the views hierarchy are measured and laid out

    另一方面,对视图层次进行了测量和布局

For images usually we use Glide and it has a fancy listener:

对于图像,我们通常使用Glide,它具有出色的监听器:

RequestListener<Drawable> {
    override fun onLoadFailed(
        e: GlideException?, 
        model: Any?,   
        target: Target<Drawable>?, 
        isFirstResource: Boolean
    ): Boolean {
        startPostponedEnterTransition()
        return false
    }

    override fun onResourceReady(
        resource: Drawable?, 
        model: Any?, 
        target: Target<Drawable>?, 
        dataSource: DataSource?, 
        isFirstResource: Boolean
    ): Boolean {
        startPostponedEnterTransition()
        return false
    }
}

Note that we call startPostponedEnterTransition() in both cases: success and error. It’s vital because if we don’t make it your application will freeze.

请注意,在两种情况下,我们都调用startPostponedEnterTransition() :成功和错误。 这很重要,因为如果不这样做,您的应用程序将冻结。

In cases when transition comes without any images you may use doOnPreDraw() extension method from ktx on the root layout and do startPostponedEnterTransition() over there.

如果过渡时没有任何图像,则可以在根布局上使用doOnPreDraw()扩展方法,并在该位置执行startPostponedEnterTransition()

奖金 (BONUS)

: Speaking of RecyclerView, it’s not enough to simply add a listener for images. We should retain an item position of RecyclerView where transition starts from. When the user goes back to the previous screen, we should compare image loaded position with the retained position at the listener and start transition only when they are matched.

:就RecyclerView而言,仅添加图像的侦听器是不够的。 我们应该保留从其开始过渡的RecyclerView的项目位置。 当用户返回上一个屏幕时,我们应该将图像加载位置与侦听器上的保留位置进行比较,并仅在它们匹配时才开始过渡。

放在一起 (Putting all together)

In this article, I’ve showed some gotchas you might face implementing a shared transition with fragments and the ways to deal with them.

在本文中,我已经展示了一些可能需要面对的难题,这些难题可能会导致您使用片段及其处理方式实现共享过渡。

Briefly, here they are:

简而言之,它们是:

  1. Keep in mind fragments hierarchy (don’t forget about parent fragment)

    记住片段层次结构(不要忘记父片段)
  2. In case with RecyclerView, always build transition names dynamically (source + destination)

    如果使用RecyclerView,请始终动态构建转换名称(源+目标)
  3. Disable any Glide transformations

    禁用任何滑行转换
  4. Do calls postPostponeTransition() and startPostponedEnterTransition() correctly regarding your logic.

    关于您的逻辑,请正确调用postPostponeTransition()startPostponedEnterTransition()

最终动画 (Final animation)

Thank you for reading and see you next time!

感谢您的阅读,下次见!

P.S. If you wonder how to animate image corners, here the code, just add to the rest shared animation transitions.

PS:如果您想知道如何对图像角进行动画处理,请在此处的代码中添加到其余的共享动画过渡中。

(Example)

fragment.sharedElementEnterTransition = TransitionSet().apply {
            addTransition(ChangeImageTransform())
            addTransition(ChangeBounds())
            addTransition(ChangeTransform())
            addTransition(ChangeOutlineRadiusTransition(animationRadiusData.startRadius, 
            animationRadiusData.endRadius)
            )
}

翻译自: https://habr.com/en/company/redmadrobot/blog/463459/

转换pdf时共享有冲突

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值