2

我编写了一个键盘动画来使控件(任何视图)跟随软键盘的滑入和滑出动画。在 Android 10 及更低版本中一切正常。

我从proandroiddev上的这篇(同时)过时的文章(在 Android 11 之前编写,不幸的是用 Kotlin 编写,而且它也不太关心已弃用的方法)中获得了这个想法,但翻译成 Java 效果很好 - 剩下的唯一问题是 Api30+

在 Android 11 中,当动画结束时,WindowInsetListener(或delayedTransition,我不知道是什么原因导致问题)似乎将偏移量加倍(即第二次将软键盘的完整高度添加到视图的边界)。

看看这两个 gif 显示的差异(对不起质量 - 我对视频录制不太深入)。

在两个设备上运行相同的代码。

左边是安卓10,右边是安卓11

安卓 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+ 中需要提供的附加标志或其他东西吗?

4

0 回答 0