我编写了一个键盘动画来使控件(任何视图)跟随软键盘的滑入和滑出动画。在 Android 10 及更低版本中一切正常。
我从proandroiddev上的这篇(同时)过时的文章(在 Android 11 之前编写,不幸的是用 Kotlin 编写,而且它也不太关心已弃用的方法)中获得了这个想法,但翻译成 Java 效果很好 - 剩下的唯一问题是 Api30+
在 Android 11 中,当动画结束时,WindowInsetListener
(或delayedTransition
,我不知道是什么原因导致问题)似乎将偏移量加倍(即第二次将软键盘的完整高度添加到视图的边界)。
看看这两个 gif 显示的差异(对不起质量 - 我对视频录制不太深入)。
在两个设备上运行相同的代码。
左边是安卓10,右边是安卓11
这是监听器:
class WindowInsetsListener implements View.OnApplyWindowInsetsListener {
private final KeyboardAnimationListener animationListener;
private int previousOffset = 0;
WindowInsetsListener(KeyboardAnimationListener animationListener) {
this.animationListener = animationListener;
}
@Override
public WindowInsets onApplyWindowInsets(View decorView, WindowInsets insets) {
WindowInsets result = insets;
int offset = insets.getSystemWindowInsetBottom() < insets.getStableInsetBottom() ?
insets.getSystemWindowInsetBottom() :
insets.getSystemWindowInsetBottom() - insets.getStableInsetBottom();
if (offset != previousOffset && animationListener.animate(decorView, offset)) {
previousOffset = offset;
result = consumeBottomInset(insets);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return WindowInsets.CONSUMED;
}
}
return decorView.onApplyWindowInsets(result);
}
private WindowInsets consumeBottomInset(WindowInsets insets) {
Rect insetRect = new Rect(
insets.getSystemWindowInsetLeft(),
insets.getSystemWindowInsetTop(),
insets.getSystemWindowInsetRight(),
Math.min(insets.getSystemWindowInsetBottom(), insets.getStableInsetBottom()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Insets newInsets = Insets.of(insetRect);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return new WindowInsets.Builder().
setInsets(WindowInsets.Type.systemBars(), newInsets).build();
} else {
return new WindowInsets.Builder().
setSystemWindowInsets(newInsets).build();
}
} else {
return insets.replaceSystemWindowInsets(insetRect);
}
}
这是我从监听器调用的动画方法:
@Override
public boolean animate(@NonNull View view, int offset) {
ViewGroup group = getGroup(view); // searches the hierarchy up until it finds the group
if (group != null) {
TransitionManager.beginDelayedTransition(group, bounds);
setBottomPadding(view, offset);
return true;
}
return false;
}
protected void setBottomPadding(View view, int offset) {
view.setPadding(
view.getPaddingLeft(),
view.getPaddingTop(),
view.getPaddingRight(),
offset);
}
我试图通过版本尊重所有弃用。尤其是Android的这一部分在每个版本中都发生了变化。但是,即使我取出 Api 29 和 30 的“新”实现,并且当我使用不推荐使用的.replaceSystemWindowInsets
方法时,效果也保持不变。
任何人都知道 Api 30+ 中需要提供的附加标志或其他东西吗?