2

コントロール (任意のビュー) がソフトキーボードのスライドインおよびスライドアウト アニメーションに従うように、キーボード アニメーションを作成しました。Android 10 以下では、すべて正常に動作します。

私はproandroiddevのこの(その間の)時代遅れの記事(Android 11より前に書かれ、残念ながらKotlinで書かれており、廃止されたメソッドについてもあまり気にしません)からアイデアを取りましたが、Javaへの変換はうまくいきました-残っている唯一の問題はApi30+にあります

Android 11 では、アニメーションが終了すると、WindowInsetListener(または、delayedTransition問題の原因がわからない) がオフセットを 2 倍にしているように見えます (つまり、ビューの境界にもう一度ソフトキーボードの高さ全体を追加します)。

違いを示すこれらの 2 つの gif を参照してください (品質については申し訳ありません - 私はビデオ録画にあまり詳しくありません)。

両方のデバイスで同じコードが実行されています。

左がAndroid 10、右がAndroid 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