【问题标题】:Apply animation sequentially to multiple views将动画顺序应用到多个视图
【发布时间】:2018-06-21 20:53:40
【问题描述】:

我有一个在垂直线性布局中具有 3 个视图 (buttonViews) 的活动。我正在动态生成(膨胀)这些视图。我想应用一个动画,以便在活动开始时,第一个按钮滑入 -> 100 毫秒延迟 -> 第二个按钮滑入 -> 100 毫秒延迟 -> 第三个按钮滑入。

尝试

我尝试以这种方式实现它:

private void setMainButtons() {
    ArrayList<String> dashboardTitles = DashboardUtils.getDashboardTitles();
    ArrayList<Integer> dashboardIcons = DashboardUtils.getDashboardIcons();

    final ViewGroup root = findViewById(R.id.button_container);

    for (int i = 0; i < (dashboardTitles.size() < dashboardIcons.size() ? dashboardTitles.size() : dashboardIcons.size()); i++){
        final View buttonView = DashboardButtonInflater.getDashboardButton(root, dashboardTitles.get(i), dashboardIcons.get(i), this);
        if (buttonView == null) continue;
        buttonView.setOnClickListener(this);
        root.addView(buttonView);
        animateBottomToTop(buttonView, (long) (i*50)); // Calling method to animate buttonView
    }
}

//The function that adds animation to buttonView, with a delay.
private void animateBottomToTop(final View buttonView,long delay) {
    AnimationSet animationSet = new AnimationSet(false);
    animationSet.addAnimation(bottomToTop);
    animationSet.addAnimation(fadeIn);
    animationSet.setStartOffset(delay);
    buttonView.setAnimation(animationSet);
}

结果:

上述方法等待所有视图的总延迟,最后将所有视图合并在一起。我可以猜到这里的罪魁祸首是线程。交易实际上是阻止 UI 线程执行任何动画。不过我可能是错的。

我也试过在里面运行动画代码

new Thread(new Runnable(){...}).run()

但这也没有用。

期望:

有人可以帮我实现buttonView 上的一对一动画吗?谢谢你。

【问题讨论】:

    标签: android android-layout animation android-animation android-view


    【解决方案1】:

    动画是有状态的对象,你不应该同时多次使用同一个实例。在您的情况下,bottomToTopfadeIn 动画在动画集之间共享。当集合开始时(initialize() 被调用),它会设置其子元素的起始偏移量。

    例如,该方法可能如下所示:

    //The function that adds animation to buttonView, with a delay.
    private void animateBottomToTop(final View buttonView,long delay) {
        AnimationSet animationSet = new AnimationSet(false);
        // create new instances of the animations each time
        animationSet.addAnimation(createBottomToTop());
        animationSet.addAnimation(createFadeIn());
        animationSet.setStartOffset(delay);
        buttonView.setAnimation(animationSet);
    }
    

    【讨论】:

    • 这没有给出我想要的结果,但答案就是我想要的。完美且非常准确。如果其他人想回答或将其标记为正确,我将等待几天。谢谢。
    • @SrujanBarai:这个解决方案对我不起作用。你是怎么解决的?请分享
    【解决方案2】:

    使用Transitions API 可以轻松解决问题。用这个 xml 声明了一个根布局:

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

    然后是内部活动:

    class MainActivity : AppCompatActivity() {
    
        lateinit var content: LinearLayout
        private var counter = 0
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            content = findViewById(R.id.content_frame)
            // wait this view to be laid out and only then start adding and animating views
            content.post { addNextChild() }
        }
    
        private fun addNextChild() {
            // terminal condition
            if (counter >= 3) return
            ++counter
    
            val button = createButton()
            val slide = Slide()
            slide.duration = 500
            slide.startDelay = 100
            slide.addListener(object : TransitionListenerAdapter() {
                override fun onTransitionEnd(transition: Transition) {
                    addNextChild()
                }
            })
            TransitionManager.beginDelayedTransition(content, slide)
            content.addView(button)
        }
    
        private fun createButton(): Button {
            val button = Button(this)
            button.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
            button.text = "button"
            return button
        }
    
    }
    

    这段代码将产生以下输出:

    您可以分别调整动画和延迟时间。


    如果你想要以下行为:

    然后你可以使用以下代码:

    class MainActivity : AppCompatActivity() {
    
        lateinit var content: LinearLayout
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            content = findViewById(R.id.content_frame)
            content.post { addChildren() }
        }
    
        private fun addChildren() {
            val button1 = createButton()
            val button2 = createButton()
            val button3 = createButton()
    
            val slide1 = Slide()
            slide1.duration = 500
            slide1.addTarget(button1)
    
            val slide2 = Slide()
            slide2.duration = 500
            slide2.startDelay = 150
            slide2.addTarget(button2)
    
            val slide3 = Slide()
            slide3.duration = 500
            slide3.startDelay = 300
            slide3.addTarget(button3)
    
            val set = TransitionSet()
            set.addTransition(slide1)
            set.addTransition(slide2)
            set.addTransition(slide3)
    
            TransitionManager.beginDelayedTransition(content, set)
            content.addView(button1)
            content.addView(button2)
            content.addView(button3)
        }
    
        private fun createButton(): Button {
            val button = Button(this)
            button.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
            button.text = "button"
            return button
        }
    }
    

    【讨论】:

    • 我不想听起来粗鲁,但如果我用 Java 提出问题,我肯定希望用 Java 得到答案。无论如何,感谢您花时间实际运行代码并发布结果。寿,这不会给出我想要的结果。您在onTransitionEnd() 中调用addNextButton(),它将等待上一个动画结束。如果我每个动画的持续时间是 500 并且希望它们以 100 毫秒的延迟执行怎么办?
    【解决方案3】:

    Create 方法,它将接受任意数量的Animation 一个接一个地调用。就像例子一样。

    private void playOneAfterAnother(@NonNull Queue<Animation> anims) {
         final Animation next = anims.poll();
    
         /* You can set any other paramters, 
         like delay, for each next   Playing view, if any of course */
    
         next.addListener(new AnimationListener() {
                @Override
                public void onAnimationEnd(Animator a) {
                    if (!anim.isEmpty()) {
                        playOneAfterAnother(anims);
                    }
                }
                @Override
                public void onAnimationStart(Animator a) {
                }
                @Override
                public void onAnimationCancel(Animator a) {
                }
                @Override
                public void onAnimationRepeat(Animator a) {
                }
            });
         next.play();
    }
    

    或者延迟动画,也很容易。

    private void playOneAfterAnother(@NonNull Queue<Animation> anims, 
                      long offsetBetween, int nextIndex) {
         final Animation next = anims.poll();
    
         /* You can set any other paramters, 
         like delay, for each next   Playing view, if any of course */
    
         next.setStartOffset(offsetBetween * nextIndex);
         next.play();
    
         if (!anim.isEmpty()) {
             playOneAfterAnother(anims, 
                  offsetBetween, nextIndex +1);
         }
    
    }
    

    【讨论】:

      【解决方案4】:

      很可能,你需要使用的是AnimatorSet而不是AnimationSet。 AnimatorSet API 允许您以两种方式编排动画: 1.按顺序播放 2. 一起玩 使用 API:

      AnimatorSet animatorSet = new AnimatorSet();
      animatorSet.playSequentially(anim1, anim2, anim3, ...);
      animatorSet.playTogether(anim1, anim2, anim3, ...);
      

      您可以使用

      进一步为您的动画添加延迟
      animatorSet.setStartDelay();
      

      在此处访问完整的 API 文档 https://developer.android.com/reference/android/animation/AnimatorSet

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        我使用此代码及其正常工作 希望能帮到你

        // 首先将你的视图放入一个名为arrayViews的数组中

         final int[] time = {0};
            for (int i = 0; i < arrayViews.size(); i++) {
                Animation zoom = AnimationUtils.loadAnimation(this, R.anim.fade_in);
                zoom.setDuration(250);
                zoom.setStartOffset(time[0] += 250);
                arrayViews.get(i).startAnimation(zoom);
                arrayViews.get(i).setVisibility(View.VISIBLE);
            }
        

        【讨论】:

          猜你喜欢
          • 2013-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多