将Snackbar置于最高z顺序,以避免被AutoCompleteTextView下拉

时间:2017-05-31 19:40:20

标签: android autocompletetextview android-coordinatorlayout android-windowmanager android-snackbar

我有Snackbar,如下所示:

enter image description here

但是,如果AutoCompleteTextView下拉过长,则下拉列表会阻止Snackbar

enter image description here

正如您在上图中看到的那样,Snackbar实际上正在显示。然而,长期下降阻碍了它的可见性。您可以从上图中看到

我尝试使用以下Snackbar code。添加bringToFront()并没有多大帮助。

private void showSnackbar(String message) {
    Snackbar snackbar
            = Snackbar.make(getActivity().findViewById(R.id.content), message, Snackbar.LENGTH_LONG);
    snackbar.getView().bringToFront();
    snackbar.show();
}

R.id.contentCoordinatorLayout

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/content"
        android:background="?attr/MyActivityBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:foreground="?attr/headerShadow" />

有没有什么好方法可以避免SnackbarAutoCompleteTextView下拉覆盖?

6 个答案:

答案 0 :(得分:7)

我可能有针对该案例的解决方案。当然,有一些假设,但也许解决方案适合你。

此处的关键是将AutoCompleteTextView放入CoordinatorLayout并向其添加自定义CoordinatorLayout.Behavior

  1. 为您的班级创建合适的Behavior

    public class AutoCompleteTextViewBehaviour extends CoordinatorLayout.Behavior<AutoCompleteTextView> {
    
        public AutoCompleteTextViewBehaviour(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, AutoCompleteTextView child, View dependency) {
            return dependency instanceof Snackbar.SnackbarLayout;
        }
    }
    
  2. 覆盖方法layoutDependsOn

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, AutoCompleteTextView child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }
    
  3. 获取对AutoCompleteTextView弹出式视图的引用:

    不幸的是,我还没有找到一个简单的解决方案。但是可以通过反思来完成。

    @Nullable
    private View getPopupList(AutoCompleteTextView child) {
        try {
            Field popupField;
            Class clazz;
            if (child instanceof AppCompatAutoCompleteTextView) {
                clazz = child.getClass().getSuperclass();
            } else {
                clazz = child.getClass();
            }
            popupField = clazz.getDeclaredField("mPopup");
            popupField.setAccessible(true);
            ListPopupWindow popup = (ListPopupWindow) popupField.get(child);
            Field popupListViewField = popup.getClass().getDeclaredField("mDropDownList");
            popupListViewField.setAccessible(true);
            return (View) popupListViewField.get(popup);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
  4. 覆盖onDependentViewChanged方法:

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, final AutoCompleteTextView child, View dependency) {
        if (popupList == null) {
            popupList = getPopupList(child);
            if (popupList == null) {
                return super.onDependentViewChanged(parent, child, dependency);
            }
        }
        int dropdownBottom = child.getBottom() + child.getDropDownVerticalOffset() + popupList.getHeight();
        int snackBarTop = dependency.getTop();
        int difference = dropdownBottom - snackBarTop;
        if (difference > 0) {
            child.setDropDownHeight(popupList.getHeight() - difference);
            return true;
        } else {
            child.setDropDownHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        return super.onDependentViewChanged(parent, child, dependency);
    }
    
  5. 将行为应用于AutocompleteTextView中的.xml

    app:layout_behavior="com.example.package.AutoCompleteTextViewBehaviour"/>
    
  6. 当然这是一个非常基本的解决方案,例如没有动画列表高度,但我认为这是一个好的开始。这是完整的gist

答案 1 :(得分:5)

您可以计算并调整弹出窗口的高度作为替代。 在下图中,我将下拉高度设置为:

textView.viewTreeObserver.addOnGlobalLayoutListener {
  textView.dropDownHeight = snackbarView.top - textView.bottom
}

example

此计算适用于建议列表的高度足够长的情况。您可能希望将该属性设置为WRAP_CONTENT

据我所知,无法更改&#34; z-order&#34;除非您将SnackBar直接添加到WindowManagerAutoCompleteTextView内部使用ListPopupWindow来显示建议弹出窗口,ListPopupWindow的窗口类型为WindowManager.LayoutParams.TYPE_APPLICATION_PANEL = 1000,高于活动窗口类型WindowManager.LayoutParams.TYPE_APPLICATION = 2。

答案 2 :(得分:1)

在我的情况下,我可以使用setZ

Snackbar snackbar = Snackbar.make(container, text, Snackbar.LENGTH_LONG);
snackbar.getView().setZ(200);
snackbar.show();

答案 3 :(得分:0)

为什么不将android:dropDownHeight设置为固定的dp值?您甚至可以通过引用dimension资源将其定义为基于屏幕大小动态定义。这是一行代码,它解决了你的问题,易于维护和理解(在六个月内你会问自己,整个Behavior的东西用于什么)。

答案 4 :(得分:0)

我认为你必须考虑许多想法:

  • 必须有空间供所有人使用。键盘,快餐栏和自动填充Textview
  • 您无法更改键盘高度(通过您的应用),因此您必须将自动完成TextView的高度更改为快餐栏(位于键盘上方)上方

答案 5 :(得分:-1)

步骤1.实施新行为

需要检查操作设备是否支持小吃吧。

public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {
    private static final boolean SNACKBAR_BEHAVIOR_ENABLED;

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
        child.setTranslationY(translationY);
        return true;
    }

    static {
        SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
    }
}

步骤2.实现自定义视图,以便我们可以将MoveUpwardBehavior应用于它。

在这种情况下,我们让整个LinearLayout与snackbar交互。 如上所述,这很简单,只需将类传递给DefaultBehavior注释即可。

@CoordinatorLayout.DefaultBehavior(MoveUpwardBehavior.class)
public class CustomLinearLayout extends LinearLayout {
    public CustomLinearLayout(Context context) {
        super(context);
    }

    public CustomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

第3步。几乎完成!

将CustomLinearLayout添加到布局中。请记住,它应该包含在CoordinatorLayout中!

<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">
    <com.example.alisondemo.musicgenre.CustomLinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        ...
     </com.example.alisondemo.musicgenre.CustomLinearLayout>
</android.support.design.widget.CoordinatorLayout>

但....为什么我们甚至不必为FAB实施行为?

形成android.support.design.widget.FloatingActionButton类的源代码,如您所见:

@DefaultBehavior(FloatingActionButton.Behavior.class) 公共类FloatingActionButton扩展ImageView { ... 是的,它实际上已经实现了自己的行为。

结论

我们可以在任何视图中实现我们想要的任何行为。应该很有趣。 :)

你可以看到只是演示: http://alisonhuang-blog.logdown.com/posts/290009-design-support-library-coordinator-layout-and-behavior

完整的源代码现在在GitHub上 https://github.com/Alishuang/MusicGenre