0

我有这个自定义视图,它作为系统警报添加到 WindowManager,它应该用作全屏覆盖,以在应用程序运行时阻止手机的某些部分。

当覆盖显示它会阻塞电话窗口全屏时,这非常有用。现在我想支持旋转更改。

这部分也可以正常工作,我有 3 个布局文件,layout layout-landlayout-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 会将正在膨胀的视图添加到根视图,因此每次旋转都会膨胀一个新布局并将其添加到根视图,因此在 a 旋转之后 Overlay 类有超过 1 个子视图看法。OnClickListeners 会将位置 0 的子视图按钮绑定到类中的 OnClickListeners,它会显示在位置 1 或更高位置新膨胀的子视图。因此,在添加此检查并删除过时的视图后,OnClickListeners 再次工作。OverlayFrameLayout

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 回答
0
Assuming you have not restricted the Restarting of activity due to change in
the orientation. When a device s configuration gets changed in your case    
Orientation, its user interface has to be updated according to the new   
configuration. 

Being the primary component for interaction, it can be updated with some      
attributes to handle changes. Default behavior of Activity when device gets 
rotated is it gets destroyed and restarted again. This may be your issue.

To handle the rotation of activity use android:configChanges = "orientation"  
attribute in manifest for your activity.
于 2015-08-03T14:02:07.757 回答