Google Inbox 如何显示覆盖键盘的小吃栏?
Posted
技术标签:
【中文标题】Google Inbox 如何显示覆盖键盘的小吃栏?【英文标题】:How does Google Inbox show a snackbar covering the keyboard? 【发布时间】:2018-01-27 09:04:26 【问题描述】:Google Inbox 如何在键盘上方(覆盖、分层)显示快餐栏?这不是默认行为,我已经使用基本协调器布局、键盘打开和小吃栏进行了测试:默认行为是在键盘后面显示小吃栏。关于这个问题有很多答案:'How do I show thesnackbar above the keyboard',但我还没有找到如何重现 Google 自己的 Inbox 应用程序的snackbar行为。
你能告诉我如何做到这一点吗?
【问题讨论】:
我尝试将小吃店视图的高度(默认为 6)设置为较大的数字,但这无济于事。我尝试了高达 5000 的海拔高度! 我假设他们必须使用覆盖窗口(例如,TYPE_SYSTEM_OVERLAY
pre-8.0,TYPE_APPLICATION_OVERLAY
on 8.0+)。我不使用 Google Inbox,所以我无法测试这种情况。但是,如果 Inbox 在 8.0+ 上没有这种行为,但在 7.1 及更早版本上却有,那么它很可能是覆盖,因为overlays cannot overlay the IME on 8.0+。
elevations
仅影响您的应用程序布局内部。我认为创建具有不同上下文的 Snakebar 可能有一些技巧。
@CommonsWare 它出现在 android 7.1(有问题的屏幕截图)和 8.0(我当前的手机)上。
“很少有应用程序应该使用此权限;这些 [覆盖] 窗口旨在与用户进行系统级交互。” (developer.android.com/reference/android/…)。我的用例没有使使用此权限合法化:我想在快餐栏打开时向我的用户提供反馈,并且我支持在键盘上方没有空间放置快餐栏的小屏幕。此外,我在 Google Inbox 中看到了这种小吃店行为,所以我认为这对我来说是一个很好的解决方案。还没有运气,看来是这样。
【参考方案1】:
Inbox 不使用标准的 Snackbar,也不使用覆盖窗口,它使用自定义视图。我反编译了 APK 以验证它们是如何实现这种效果的,并尝试重现一个最小的示例。
首先新建一个布局custom_snackbar.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="#323232"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:id="@+id/text"
android:layout_
android:layout_
android:layout_weight="1"
android:gravity="center_vertical"
android:text="Marked done"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/button"
android:layout_
android:layout_
android:background="@android:color/transparent"
android:gravity="center_vertical"
android:minWidth="48dp"
android:text="undo"
android:textAllCaps="true"
android:textColor="#a1c2fa"/>
</LinearLayout>
然后创建这些方法来显示和关闭自定义 Snackbar:
private View customSnackbar;
private void showCustomSnackbar(final Context context)
customSnackbar = LayoutInflater.from(context).inflate(R.layout.custom_snackbar, null, false);
customSnackbar.findViewById(R.id.button).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//action implementation
);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.format = PixelFormat.TRANSLUCENT;
lp.gravity = Gravity.BOTTOM;
lp.flags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
customSnackbar.setLayoutParams(lp);
WindowManager windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
if (windowManager != null)
windowManager.addView(customSnackbar, customSnackbar.getLayoutParams());
Point m = new Point();
windowManager.getDefaultDisplay().getSize(m);
int childMeasureSpecWidth = ViewGroup.getChildMeasureSpec(View.MeasureSpec.makeMeasureSpec(m.x, View.MeasureSpec.EXACTLY), 0, lp.width);
int childMeasureSpecHeight = ViewGroup.getChildMeasureSpec(View.MeasureSpec.makeMeasureSpec(m.y, View.MeasureSpec.EXACTLY), 0, lp.height);
customSnackbar.measure(childMeasureSpecWidth, childMeasureSpecHeight);
customSnackbar.setTranslationY(customSnackbar.getMeasuredHeight());
customSnackbar.animate()
.setDuration(300)
.translationX(0.0f)
.translationY(0.0f);
private void dismissCustomSnackbar(final Context context)
customSnackbar.animate()
.setDuration(300)
.translationX(0.0f)
.translationY(customSnackbar.getMeasuredHeight())
.withEndAction(new Runnable()
@Override
public void run()
WindowManager windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
if (windowManager != null)
windowManager.removeView(customSnackbar);
);
这是得到的结果:
【讨论】:
我不太喜欢WindowManager
...但是为什么它会出现在 IME 上?我认为 Android 8.0 中关于WindowManager
-add windows 的更改应该可以防止这种事情发生。无论如何,干得好!
Android 8.0 的限制似乎只适用于TYPE_APPLICATION_OVERLAY
类型。在此示例中,视图具有默认类型 TYPE_APPLICATION
。
谢谢,太棒了。我稍后会在我的应用程序中尝试这个,如果出现任何怪癖或边缘情况,我会在此处报告。我也猜想有可能以常规方式构建一个Snackbar
,然后,如果键盘是打开的,而不是定期显示它,使用这种方法将它显示在键盘前面。这样,这种自定义的快餐栏行为可以适应不同的键盘情况。以上是关于Google Inbox 如何显示覆盖键盘的小吃栏?的主要内容,如果未能解决你的问题,请参考以下文章