0

アプリの実行中に電話の特定の部分をブロックするフルスクリーン オーバーレイとして機能するシステム アラートとして WindowManager に追加されているこのカスタム ビューがあります。

これは、オーバーレイが表示されているときに電話ウィンドウのフルスクリーンをブロックするときにうまく機能します。今、ローテーションの変更をサポートしたいと考えています。

この部分も正常に動作します.3つのレイアウトファイルがlayout layout-landありlayout-h600dp-land、電話を回転させると正しいレイアウトに変わります. これで私が抱えている問題は、onConfigurationChanged(Configuration newConfig)呼び出された後、レイアウトを再び膨らませることです。すべてのクリックリスナーがなくなったため、ビューのボタンはクリックに反応しません。ボタンをタップすると、ボタンの押された状態が変化しますが、onClickListeners はトリガーされません。向きを変更する前は、すべてのボタンが機能します。私は Butterknife を使用して onClicklisteners と findViewById のボイラープレート コードを減らしてきましたが、すでにそれを findViewById に変更し、ビューに手動で clicklistener を追加しても違いはありません。

そして今、いくつかのコードです。サービスはビューをウィンドウマネージャーに追加します

public class OverlayService extends Service {

    public void showOverlay() {
        startForeground();
        mUiHandler.post(new Runnable() {
            @Override
            public void run() {
                if (!DrivingOverlay.isShowing()) {
                    if (mOverlay == null) {
                        mOverlay = new Overlay(OverlayService.this);
                        mOverlay.setTag(OVERLAY_TAG);
                        mOverlay.setId(R.id.overlay);
                    }
                addView(mOverlay);
            }
        });
    }

    private void addView(@NonNull final View view) {
        try {
            final WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            windowManager.addView(view, Overlay.LAYOUT_PARAMS);
        } catch (IllegalStateException error) {
            Log.e(TAG, Log.getStackTraceString(error));
        }
    }
}

オーバーレイであるカスタム ビュー。

public class Overlay extends FrameLayout {
    private static boolean sIsOverlayShowing;
    public static final WindowManager.LayoutParams LAYOUT_PARAMS = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_FULLSCREEN
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
            PixelFormat.TRANSLUCENT);

    public Overlay(Context context) {
        super(context);
        init(context);
    }

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

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public Overlay(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    protected void init(Context context) {
        inflate(context, R.layout.driving_overlay, this);
        if (!isInEditMode()) {
            ButterKnife.bind(this);
        }
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged");
        init(getContext());
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        setIsOverlayShowing(true);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        setIsOverlayShowing(false);
    }

    @Override
    public void onViewAttachedToWindow(View v) {
        setIsOverlayShowing(true);
    }

    @Override
    public void onViewDetachedFromWindow(View v) {
        setIsOverlayShowing(false);
    }

    public static boolean isShowing() {
        return sIsOverlayShowing;
    }

    public static void setIsOverlayShowing(boolean isOverlayShowing) {
        sIsOverlayShowing = isOverlayShowing;
    }
}
4

2 に答える 2

1

最後にそれを理解しました。

inflate(context, R.layout.driving_overlay, this)init を呼び出すと、この場合はインフレートされているビューがルート ビューに追加さOverlayれるFrameLayoutため、各ローテーションは新しいレイアウトをインフレートしてルート ビューに追加するため、ローテーションの後、Overlay クラスには複数の子がありました。見る。OnClickListeners は、位置 0 の子ビュー ボタンをクラスの OnClickListeners にバインドし、位置 1 以上で新しくインフレートされた子ビューを表示します。したがって、これをチェックして古いビューを削除すると、OnClickListeners が再び機能するようになります。

protected void init(Context context) {
        if (getChildCount() >= 1) {
            removeViewAt(0);
        }
        final View view = inflate(context, R.layout.driving_overlay, this);
        if (!isInEditMode()) {
            ButterKnife.bind(this, view);
        }
}
于 2015-08-03T14:45:33.563 に答える