1

我正在开发一个项目,我希望根据材料设计使用循环显示效果。项目拥有minSDK = 11,因此与前棒棒糖设备的兼容性,我使用这个库https://github.com/ozodrukh/CircularReveal使用带有棒棒糖循环显示库的setVisibility(View.INVISIBLE)

我已经与FloatingActionButton片段,轻敲后,将改变自己在CardView,喜欢这里描述FAB transformations

一旦显示卡片,它就会有一个按钮来恢复动画,将卡片重新转换为FAB。现在我的问题是这样的:假设用户点击FAB并显示CardView。现在用户旋转他的设备,所以活动重置片段。我想要实现的是卡片保持可见和透露状态,而FAB应该被禁用且不可见。问题是,如果我简单地在我的FAB上使用setVisibility(View.INVISIBLE)它不起作用(请注意,如果我在使用getVisibility()后将它设置为不可见,它会正确返回值4 == View.INVISIBLE,但晶圆厂仍然可见)。我必须将setVisibility(...)呼叫包含在postDelayed()之内,延迟时间至少为50-100毫秒,以使工厂不可见。

所以我的问题是:我是否正确地做事或者有更好的方法来完成我想要的事情(因为它对我来说似乎很丑陋)?

这是一些代码。这是片段的我的XML布局:

<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/my_appbar" 
     android:layout_width="match_parent" 
     android:layout_height="@dimen/toolbar_expanded_height" 
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> 

     <android.support.design.widget.CollapsingToolbarLayout 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      app:expandedTitleMarginEnd="64dp" 
      app:expandedTitleMarginStart="70dp" 
      app:layout_scrollFlags="scroll|exitUntilCollapsed"> 

      <android.support.v7.widget.Toolbar 
       android:layout_width="match_parent" 
       android:layout_height="?attr/actionBarSize" 
       app:popupTheme="@style/ToolbarPopupTheme" 
       app:layout_collapseMode="pin"/> 
     </android.support.design.widget.CollapsingToolbarLayout> 
    </android.support.design.widget.AppBarLayout> 
    ... 
    <io.codetail.widget.RevealFrameLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <include layout="@layout/my_fragment" /> 
    </io.codetail.widget.RevealFrameLayout> 
    <android.support.design.widget.FloatingActionButton 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_margin="@dimen/fab_margin" 
     app:fabSize="mini" 
     app:layout_anchor="@+id/my_appbar" 
     app:layout_anchorGravity="bottom|left|start" /> 
</android.support.design.widget.CoordinatorLayout> 

这是包括CardView的XML布局:

<android.support.v7.widget.CardView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:card_view="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_margin="16dp" 
    android:layout_gravity="center" 
    card_view:cardCornerRadius="2dp" 
    android:visibility="invisible" 
    android:focusableInTouchMode="true"> 

    <RelativeLayout android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     ... 
     <LinearLayout android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="horizontal" 
      android:gravity="end"> 
      <Button android:layout_height="wrap_content" 
       android:layout_width="wrap_content" 
       android:text="Ok" /> 
      <Button android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Cancel" /> 
     </LinearLayout> 
    </RelativeLayout> 
</android.support.v7.widget.CardView> 

这是我的片段代码:

public class MyFragment extends Fragment { 

    private static final String CARD_OPEN_TAG = "CARD_OPEN_TAG"; 

    public static MyFragment newInstance(){ 
     return new MyFragment(); 
    } 

    private int cardOpen; 
    private FloatingActionButton fabAddPublication; 
    private CardView card; 
    private Button cardCancel; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
     final View rootView = inflater.inflate(R.layout.fragment_magazines, container, false); 
     toolbar = (Toolbar) rootView.findViewById(R.id.layout); 

     ... 

     // Initialize view status 
     if (savedInstanceState != null){ 
      cardOpen = savedInstanceState.getInt(CARD_OPEN_TAG); 
     } else { 
      cardOpen = -1; 
     } 

     ... 

     // Get FAB reference 
     fab = (FloatingActionButton) rootView.findViewById(R.id.fab_id); 
     // Get card reference 
     card = (CardView) rootView.findViewById(R.id.card_id); 
     editorPublication.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       // Using this event because I need my card to be measured to move correctly fab at his center 
       if (cardOpen != -1){ 
        // Move FAB to center of card 
        fab.setTranslationX(coordX); // WORKS 
        fab.setTranslationY(coordY); // WORKS 
        // fab.setVisibility(View.INVISIBLE) -> DOESN'T WORK, fab remain visible on top and at center of my card 
        // Ugly workaround 
        new Handler().postDelayed(new Runnable() { 
         @Override 
         public void run() { 
          // Hide FAB 
          fab.setVisibility(View.INVISIBLE); 
         } 
        }, 50); // Sometimes fails: if device/emulator use too much time to "rotate" screen, fab stay visible 
        // Remove listener 
        ViewTreeObserver obs = card.getViewTreeObserver(); 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 
         obs.removeOnGlobalLayoutListener(this); 
        else obs.removeGlobalOnLayoutListener(this); 
       } 
      } 
     }); 
     if (editorOpen != -1){ 
      fab.setEnabled(false); // WORKS 
      card.setVisibility(View.VISIBLE); // WORKS 
     } 
     // Get editors buttons reference 
     cardCancel = (Button) card.findViewById(R.id.card_cancel_id); 
     // Set FAB listener 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // Explode FAB 
       explodeFab(fab, card); // This method trigger the reveal animation 
       cardOpen = card.getId(); 
      } 
     }); 
     // Set editors button listeners 
     cardCancel.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // Implode FAB 
       implodeFAB(fab, card); // This card reverts the reveal animation 
     cardOpen = -1; 
      } 
     }); 

     ... 

     return rootView; 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState){ 
     super.onSaveInstanceState(outState); 
     ... 
     outState.putInt(CARD_OPEN_TAG, cardOpen); 
    } 

} 

回答

0

我不要认为你在做什么是正确的,这是为什么:

1.

该通告显示您正在使用的库与Android 11至17(3.0至4.2)上的硬件加速不兼容。它使用了Canvas.clipPath() - 这是一种仅在Android 4.3以前的软件中实现的方法。这意味着您必须关闭硬件加速功能,否则您的应用会在不支持的OpenGL通话中崩溃。

剪辑布局的最佳方式是使用Canvas.saveLayer()/ restoreLayer()。这是支持所有设备,获取抗锯齿图像并正确支持无效/布局/绘制流程的唯一方法。

2.

依托定时器和布局听众改变布局意味着东西是不是真的为你工作。每个更改都可以直接执行而无需等待。你只需要为这段代码找到合适的地方。

定时器还可以在您的应用程序处于后台时触发。这意味着它会在尝试从Timer线程访问UI时崩溃。

也许你在代码的某个地方调用setVisibility(true),这就是为什么你的FAB是可见的?设置可见性是可以的,应该没有任何延迟的调用。只需将可视性保存为FAB的状态并在方向更改后恢复。

如果您希望将FAB放置在工具栏的中心,请将它们都包装在FrameLayout(wrap_content)中,并使用layout_gravity =“center”定位FAB。这应该允许您删除布局侦听器。

3.

support.CardView坏了,不应该使用。它看起来和Lollipop和旧系统有点不同。阴影是不同的,填充不同的是,内容剪辑不会对预棒棒糖设备的工作,等等。这就是为什么它是很难获得在所有平台上一致的,效果不错。

您应该考虑使用简单的布局用于这一目的。

4.

一些动画是长得帅,但难以实现,不给任何价值,迅速成为刺激性,因为用户必须等待动画,他每次做完/她点击按钮。

我不是为你的情况说不做,但你可以考虑删除的改造和使用下拉菜单,底部片,静态工具栏或为目的的对话。

+0

Zielony您好,感谢您的时间。我开始认为你对删除这部动画是正确的,尤其是因为我不是图形专家。我之所以使用这个库,是因为它宣称在Lollipop之前的Android版本中启用了这种效果,并且我没有提到任何关于硬件加速问题的信息(或者我错了吗?)。 我正在使用CardView来显示一个小表格来在我的数据库中创建一个新条目(只有2个edittexts)。如果我决定更换CardView,那么您为此目的建议我做什么? DialogFragment(我使用片段)? – MatteoBelfiori

+0

我谈论硬件加速问题被报告为这里的问题:https://github.com/ozodrukh/CircularReveal/issues/27。我会在那里用某种对话,但我不知道你的情况,这只是我的看法。选择最适合你的方式。 – Zielony

+0

谢谢Zielony,我想我会去找一个DialogFragment。 – MatteoBelfiori