服务与覆盖层 - 捕捉返回按钮按下

14

我该怎么做呢?

当前解决方案

我启动了一个透明的活动,它捕获后退按钮事件,将其转发到我的服务并在关闭自身之后。但是这个活动将在当前运行的活动中可见,因此这不是一个非常好的解决方案。

已看到的解决方案

我看到过一个应用程序,在没有捕获后退按钮事件的活动的情况下捕获了后退按钮事件 - 如果我显示当前运行的活动,则来自此应用程序的内容为空。

问题

这可以怎样做到呢?我阅读了很多帖子说这是不可能的,但我可以看到有一些应用程序以某种方式实现了这一点...

4个回答

12

我认为我找到了它的工作原理...不要在你的覆盖视图中使用WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,并且覆盖你视图的dispatchKeyEvent

 @Override
public boolean dispatchKeyEvent(KeyEvent event)
{
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
    {
        // handle back press
        // if (event.getAction() == KeyEvent.ACTION_DOWN)
        return true;
    }
    return super.dispatchKeyEvent(event);
}

5
服务类不要覆盖这样的方法。 - Ankesh kumar Jaisansaria
1
取决于你想要什么...我使用WindowManager.LayoutParams.TYPE_SYSTEM_ERROR作为我的覆盖层类型,以及WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH作为标志...这对于类似侧边栏的应用程序效果很好... - prom85
1
@prom85 你不应该使用TYPE_SYSTEM_ERROR,因为这可能会被误解为恶意软件。https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_NOT_TOUCH_MODAL 通常是最好的选择,因为它允许对视图进行聚焦,但不会阻止外部触摸事件,而FLAG_WATCH_OUTSIDE_TOUCH则需要指定要传递的外部触摸类型。 - Abandoned Cart
我重写了dispatchKeyEvent方法,但没有得到回调。我尝试使用TYPE_SYSTEM_OVERLAY、TYPE_PHONE以及FLAG_NO_FOCUSABLE标志。 - shantanu
@prom85 当您使用视图时如何覆盖 dispatchKeyEvent? - Abhiroj Panwar
显示剩余2条评论

6
我找到了解决这个问题的方法,它运行良好。
public class MyFooterService extends Service{
View myview;
WindowManager wm;
FrameLayout wrapper;
public MyFooterService() {

}
 @Override
public void onCreate() {
    Log.d(TAG, "onCreate called");
    LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            90,  //height of ur layout
            WindowManager.LayoutParams.TYPE_PHONE,
            0,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.BOTTOM ;
    params.x = 0;
    params.y = 0;
   wrapper = new FrameLayout(this) {
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
              // handle the back button code;
             return true;
            }
          return super.dispatchKeyEvent(event);
        }
       //if pressed home key,
      public void onCloseSystemDialogs(String reason) {
            //The Code Want to Perform.
            System.out.println("System dialog " + reason);
            if (reason.equals("homekey")) {
                // handle home button 
            }
        }

     };
   myview = li.inflate(R.layout.my_footer, wrapper);   // here set into your own layout
   wm.addView(myview, params);

}
}

如果需要关闭窗口,只需检查包装器(FrameLayout)的可见性。 - RejoylinLokeshwaran
对我来说可以运行。只需删除WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE。 - yarin

5
如果您在服务中的WindowManager上附加了一个叠加窗口,请为您的视图设置属性setFocusableInTouchMode(true),并添加一个按键监听器��您将接收到按键事件,就像这个例子中一样:
view.setFocusableInTouchMode(true);
view.setOnKeyListener(new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK) {
            stopSelf();
            return true;
        }
        return false;
    }
});

编辑,我没有使用好的Stack Overflow账户


1
这对我有效,但只有在我添加view.requestFocus();时才有效。 - Flyview

0

您可以捕捉返回按钮的点击事件。为此,您需要创建您的OverlayView的容器类。例如:创建类Overlay扩展某些ViewGroup类。然后,在该类中,填充您的xml布局并将其添加到Overlay.class ViewGroup中。然后在Overlay.class中覆盖dispatchKeyEvent(KeyEvent event)方法。就这样!

class Overlay extends FrameLayout{
  
  public Overlay(@NonNull Context context) {
        super(new ContextThemeWrapper(context, R.style.AppTheme));

        initView();
    }
    
    private void initView() {
      //inflate your xml here
      //than do: this.addView(<inflated view>);
      //And in the end add your Overlay to WindowManager (in Service class of course).
    }
    
     @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            //do staff here
            // and return True!
            return true;
        }
        return super.dispatchKeyEvent(event);
    }
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接