8

我想创建一个覆盖,如 HUD,它在我的应用程序活动堆栈(我的应用程序的任务)更改期间驻留在屏幕上。

我找到了几个使用 WindowManager 的示例,但如果需要,我无法确定正确 z-index 的参数化。要么弱化下一个活动将在我的叠加层上进行,要么强化叠加层是系统范围的叠加层,当应用程序进入后台时也可见。

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

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

--- 我的用例 --

我正在实现一个流程,其中包括一个为用户输入提供表单的活动。必须以相当复杂的方式处理用户输入,从而产生 +/- 10 个状态的可能结果。处理过程最多可能需要 10 分钟,并且取决于该过程的结果,我想显示相应的视图。在进程运行时,我打算让用户保持更新,但不能让他浏览应用程序(中止进程除外)。长期运行的每一个可能的结果都将在不同的活动中呈现。

我很清楚,有几种可能的方法(例如只有一项活动)。但该决定已经做出,超出了该问题的范围。我已经实现了一个使用系统 Windows 来显示该覆盖的解决方案。为了隐藏覆盖,我必须依靠 onStart、onStop 事件并解释“应用程序确实进入了后台”和“应用程序确实进入了前台”。这感觉很脏,我对那个解决方案不满意。我宁愿退后一步,在调用活动的顶部显示我的叠加层,并在完成过程后隐藏它并前进到显示结果的活动。

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

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

4

2 回答 2

12

你真的只有两个选择。

1)您可以创建一个以Theme.Dialog为主题的活动。这将在您的窗口顶部显示一个弹出窗口。您可以将对话框创建为无模式的(可以单击)。在我的快速测试中,我无法覆盖到我的屏幕边缘,尽管修改主题可能会解决这个问题。

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
    }
}

显现

    ....
    <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。我更喜欢这种方法。你是正确的,它可以是可见的并且在所有其他应用程序之上,但是,你可以控制它何时可见,何时不可见。我不会发布任何源代码,但我会给你一个总体的攻击计划。

创建服务时,使用 AIDL 绑定到它。这样,您就可以直接与服务对话,告诉它何时“隐藏”和“显示”覆盖。说到隐藏和显示,onPause 和 onResume 可以用来告诉服务隐藏和显示覆盖。最后,如果您需要在叠加层上接收点击事件,这将被证明是棘手的,因为触摸事件并不总是按照您期望的方式运行。

祝你好运。

于 2013-09-24T07:52:52.720 回答
8

我想你会感兴趣以下内容。你不需要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) { }

    };
}
于 2013-09-26T19:41:31.533 回答