view.animate()第一次不起作用,但后续工作

时间:2017-11-09 09:30:54

标签: android-fragments visibility slide visible android-constraintlayout

要点:

视图以visibility ='GONE'开头。当视图设置为可见时,我希望它下面的所有内容都向下移动该视图的高度。它不是第一次工作,但在此之后每次都有效。

说明:

我正在使用一个有三种传送选项的广播组。

如果用户点击第三个选项,则第二个广播组会显示更多选项。

第二个无线电组仅在选择第一个无线电组的第三个选项时可见。当它变得可见时,我希望它下面的一切都向下滑动以腾出空间。我添加了view.animate()。translationY()调用两个无线电组下面的每个视图。这可以在第二个无线电组出现时将所有东西移开,并在它消失时将它们向后滑动。问题是这只能在第二次工作。无线电组第一次出现时,所有视图都保持不变。

尝试:

  • SystemClock - 我尝试添加SystemClock.sleep(1500)调用。这只会给动画添加一个延迟,但它仍然无法在第一次工作。

  • 处理程序 - 我尝试添加处理程序来处理动画视图,同样的问题。

  • 启动延迟 - 我尝试按照in this stack-overflow answerthis one

  • 添加启动延迟
  • 硬编码高度 - 我已经尝试过硬编码距离向下移动。我认为问题可能是我通过在设置为可见之后调用无线电组上的getHeight()来获得高度toMove。如果这是问题,我虽然硬编码高度可能会起作用,但同样的问题仍然存在。

  • 垂直链 - 我尝试将所有视图附加到垂直链中,并在链变得可见时将其添加到链中。当可见性为'GONE'时,无线电组不能包含在链中,将其添加到链中什么也没做。如果在将可见性设置为“VISIBLE”后将其添加到Constraint Layout,则应用程序崩溃。

截图:

这是我第一次点击单选按钮时发生的情况: 显示screenshot:广播组,视图不会向下滑动

当我点击最后一个单选按钮时会发生这种情况: screenshot:无线电组2消失了

当我选择“标准交付”之后会发生这种情况,以及我第一次想要发生的事情: screenshot:广播组2设置为可见,其他视图向下滑动

代码:

GitHub:This is the whole app GitHub:The specific java file -- radio group switch starts on 109

Snipit:

  --- Switch Statement ---
       ...
       ...  
    case R.id.standard_delivery_radio:

        delivery = STD_DELIVERY;
        deliveryType = "Standard Delivery";
        stdDeliveryGroup.setVisibility(View.VISIBLE);

        break;
     }

 // Move the views down
     if (stdDeliveryGroup.getVisibility() == View.VISIBLE) {
          toMove = stdDeliveryGroup.getHeight(); }

 // Move the views back to starting position
     if (stdDeliveryGroup.getVisibility() == View.GONE) {
          toMove = 0;}

 // Animate the Views
     shippingNumber.animate().translationY(toMove);
     shippingText.animate().translationY(toMove);
     orderButton.animate().translationY(toMove);
     totalText.animate().translationY(toMove);
     totalNumber.animate().translationY(toMove);

说明:

  • 这发生在片段内。
  • 代码位于onCreateView方法内的switch语句中。
  • 该片段位于主活动中,该活动具有带标签的视图寻呼机。
  • 如果要在文件中找到代码,请在java / com / example / OrderScreenFragment.java下

  • 我真的环顾四周,找不到为什么会这样,请不要标记为重复或模糊。如果您需要澄清任何内容,我将很乐意澄清。

2 个答案:

答案 0 :(得分:2)

<强>更新 当首次显示标记为gone的无线电组的布局时,由于gone窗口小部件没有高度(或者可能没有),因此无线电组的高度已经测量为零测量,因为它是gone无论如何)。因此,当您引用其高度时,toMove变为零。现在,无线电组可见,Android会对其进行测量并将其解决。不幸的是,自toMove == 0以来,无线电组不会改变。 (使用getHeight()捕获高度后进行测量和布局。)

当无线电组再次标记为gone,然后标记为visible时,toMove会获得无线电组的高度,因为之前已经过测量并存储了这些测量值。有关详细信息,请参阅"How Android Draws View"

要解决此问题,您需要明确测量无线电组。我对以下onCreateView()进行了更改:

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the Layout for this fragment
        View myView = inflater.inflate(R.layout.fragment_order, container, false);
        constraintLayout = (ConstraintLayout) myView.findViewById(R.id.order_screen_layout);
        set = new ConstraintSet();
        set.clone(constraintLayout);
        set.applyTo(constraintLayout);

        // Radio Groups
        RadioGroup deliveryGroup = (RadioGroup) myView.findViewById(R.id.radioGroup);
        stdDeliveryGroup = (RadioGroup) myView.findViewById(R.id.std_delivery_group);

        deliveryGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                // Checked ID is the radio button selected

                switch (checkedId) {
                    case R.id.pickup_radio_button:
                        shipping = 0;
                        delivery = PICKUP;
                        deliveryType = "Pick-Up";
                        updatePrice();
                        stdDeliveryGroup.setVisibility(View.GONE);
                        break;

                    case R.id.free_delivery_radio:
                        shipping = 0;
                        delivery = CBD_DELIVERY;
                        deliveryType = "CBD - Delivery";
                        updatePrice();
                        stdDeliveryGroup.setVisibility(View.GONE);
                        break;

                    case R.id.standard_delivery_radio:
                        // ToDo: Impliment delivery charges if delivering outside of CBD
                        delivery = STD_DELIVERY;
                        deliveryType = "Standard Delivery";
                        stdDeliveryGroup.setVisibility(View.VISIBLE);
//                                SystemClock.sleep(2000);
                        break;
                }

                if (stdDeliveryGroup.getVisibility() == View.VISIBLE) {
                    // Force measurement since view was "gone" at last measurement.
                    if (stdDeliveryGroup.getMeasuredHeight() == 0) {
                        // Only force measurement if the view is gone; otherwise, the normal flow
                        // will work.
                        ViewGroup.LayoutParams lp = stdDeliveryGroup.getLayoutParams();
                        int widthSpec = View.MeasureSpec.makeMeasureSpec(lp.width, View.MeasureSpec.EXACTLY);
                        int heightSpec = View.MeasureSpec.makeMeasureSpec(lp.height, View.MeasureSpec.EXACTLY);
                        stdDeliveryGroup.measure(widthSpec, heightSpec);
                    }
                    toMove = stdDeliveryGroup.getMeasuredHeight();
                }

                if (stdDeliveryGroup.getVisibility() == View.GONE) {
                    toMove = 0;
                }

                shippingNumber.animate().translationY(toMove);
                shippingText.animate().translationY(toMove);
                orderButton.animate().translationY(toMove);
                totalText.animate().translationY(toMove);
                totalNumber.animate().translationY(toMove);
            }
        });

        return myView;
    }

经过反思,我意识到如果没有以精确单位指定无线电组的大小,前面的解决方案会有问题。最初将无线电组的可见性设置为visible的另一种方法。这将导致Android测量和布局无线电组。然后,我们将在ConstraintLayout上使用预绘制侦听器来中止布局绘制,并将可见性设置为gone。将XML中广播组的可见性更改为visible,并将以下代码添加到onCreate()

constraintLayout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        constraintLayout.getViewTreeObserver().removeOnPreDrawListener(this);
        stdDeliveryGroup.setVisibility(View.GONE);
        return false;
    }
});

纠正这个问题的另一种方法,也许是最好的方法是稍微修改你的布局。将要向下滑动的小部件的顶部限制在gone无线电组的底部。您现在可以使用ConstraintSetTransitionManager.beginDelayedTransition()来制作动画。有关简介,请参阅本教程。如果您需要对边距进行一些调整,请查看ConstraintLayout文档中的Visibility Behavior

答案 1 :(得分:1)

解决方案:

我最终通过使用visibility =(visible&lt; =&gt; invisible)

来解决问题

说明:

最初的可见性来自(去掉了&lt; =&gt;可见)。

通过在活动启动时将其设置为“不可见”,我可以测量组的高度,但不会以任何其他方式影响布局。感谢@Cheticamp指出我正确的方向。它确实没有首先测量视图的高度,即使在视图设置为可见之后调用了getHeight()。

前两个答案都不适用于我,他们仍然做同样的事情。对于最后的约束布局建议,我无法将视图的约束附加到设置为“已消失”的视图的底部。

我不知道视图是否“隐形”是理想的解决方案,但它具有预期的效果。如果我将来发现这个方法有任何问题,我会在这里更新。