Android:在窗口上覆盖任务的活动

我想在我的应用程序活动堆栈(我的应用程序的任务)发生更改时在屏幕上创build一个叠加层,就像HUD一样。

我发现了一些使用WindowManager的例子,但是如果你想的话,我无法弄清楚正确的z-index的参数化。 要么弱化下一个活动会覆盖我的覆盖层,要么覆盖层是系统覆盖层,当应用移动到后台时也是可见的。

我的目标是在属于我的应用程序或任务的所有活动之上显示一个视图(应用程序将是首选)。 我知道,应用程序和任务是Android上的两个不同的东西…

我明确不想要的是使用系统范围的窗口,需要android.permission.SYSTEM_ALERT_WINDOW

—我的用例 –

我正在实现一个包含提供用户input表单的活动的stream程。 用户input必须以相当复杂的方式处理,产生+/- 10个状态的可能结果。 处理过程可能需要10分钟,根据该过程的结果,我想显示相应的视图。 当进程运行时,我打算让用户更新,但不能让他导航应用程序(除了中止进程)。 长期运行的每一个可能的结果都将以不同的活动呈现出来。

我很清楚,有几种可能的方法(例如只有一个活动)。 但是,这个决定已经被制定出来,并且不在这个问题的范围之内。 我已经实现了一个使用系统窗口来显示覆盖的解决scheme。为了隐藏覆盖,我必须计入onStart,onStop事件并解释“应用程序已移到后台”和“应用程序已移到前台”。 这感觉很脏,我不满意这个解决scheme。 我宁愿退后一步,在调用活动之上显示我的覆盖图,并在完成该过程时隐藏它并前进到显示结果的活动。

我尝试的另一件事是将视图从一个活动移到另一个活动。 但是这显示了我不喜欢的animation的一些闪烁和中断。

我将不胜感激,如果我们可以专注于是否有可能在应用程序/任务窗口而不是在系统或活动窗口内显示视图;)

Solutions Collecting From Web of "Android:在窗口上覆盖任务的活动"

我认为以下将是你感兴趣的。 你将不需要android.permission.SYSTEM_ALERT_WINDOW 。 该代码是为应用程序类。

评论应该有助于你理解逻辑。 代码应该可以直接使用。

 public class YourApplication extends Application { // Popup to show persistent view PopupWindow pw; // View held by Popup LinearLayout ll; @Override public void onCreate() { super.onCreate(); // Register for Activity Lifecyle Callbacks registerActivityLifecycleCallbacks(new YourCallBack()); // Initialize the view ll = new LinearLayout(this); ll.setLayoutParams(new LayoutParams(100, 100)); ll.setBackgroundColor(Color.BLUE); // Initialize popup pw = new PopupWindow(ll, 100, 100); // Set popup's window layout type to TYPE_TOAST Method[] methods = PopupWindow.class.getMethods(); for(Method m: methods){ if(m.getName().equals("setWindowLayoutType")) { try{ m.invoke(pw, WindowManager.LayoutParams.TYPE_TOAST); }catch(Exception e){ e.printStackTrace(); } break; } } } @Override public void onTerminate() { super.onTerminate(); if (pw != null && pw.isShowing()) { pw.dismiss(); } }; private final class YourCallBack implements ActivityLifecycleCallbacks { int numOfRunning = 0; @Override public void onActivityCreated(Activity arg0, Bundle arg1) { } @Override public void onActivityDestroyed(Activity arg0) { } @Override public void onActivityPaused(Activity arg0) { // An activity has been paused // Decrement count, but wait for a certain // period of time, in case another activity // from this application is being launched numOfRunning--; // Delay: 100 ms // If no activity's onResumed() was called, // its safe to assume that the application // has been paused, in which case, dismiss // the popup new Handler().postDelayed(new Runnable() { @Override public void run() { if (numOfRunning == 0) { pw.dismiss(); } } }, 100L); } @Override public void onActivityResumed(Activity arg0) { // If no activities were running, show the popup if (numOfRunning == 0) { pw.showAtLocation(ll, Gravity.BOTTOM, 0, 0); } // Now, one activity is running numOfRunning++; } @Override public void onActivitySaveInstanceState(Activity arg0, Bundle arg1) { } @Override public void onActivityStarted(Activity arg0) { } @Override public void onActivityStopped(Activity arg0) { } }; } 

你真的只有两个select。

1)您可以创build一个主题为Theme.Dialog的活动。 这将在您的窗口上显示一个popup窗口。 您可以创build对话框为无模式(可以点击)。 在我的快速testing中,我无法覆盖到屏幕的边缘,虽然修改主题可以解决这个问题。

MainActivity.java

 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button test = (Button) this.findViewById(R.id.test); test.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ((Button) v).setBackgroundColor(Color.RED); } }); Intent i = new Intent(this, SecondActivity.class); startActivity(i); } } 

SecondActivity.java

 public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second_main); Window window = getWindow(); window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); window.setGravity(Gravity.BOTTOM); } @Override public void onBackPressed() { //Override to prevent back button from closing the second activity dialog } } 

performance

  .... <activity android:name="com.example.control.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.example.control.SecondActivity" android:theme="@android:style/Theme.Dialog" android:label="@string/app_name" > .... </activity> .... 

2)第二个选项是使用SYSTEM_ALERT_WINDOW。 我更喜欢这种方法。 你是正确的,它可以是可见的,并在每一个其他的应用程序的顶部,但是,你可以控制什么时候是可见的,什么时候没有。 我不打算发布任何源代码,但我会给你一个攻击的总体计划。

当您创build服务时,使用AIDL绑定到它。 这样你就可以直接和服务对话,告诉它什么时候“隐藏”和“显示”叠加。 说到隐藏和显示,onPause和onResume可以用来告诉服务隐藏和显示覆盖。 最后,如果您需要在您的叠加层上接收点击事件,那么触摸事件并不总是按照您期望的那样进行,这将certificate是棘手的。

祝你好运。

希望这可以帮助

 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.windowAnimations = android.R.style.Animation_Toast; layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; layoutParams.format = PixelFormat.TRANSLUCENT; LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.your_layout, null); windowManager.addView(layout, layoutParams);