编程技术记录

世界你好!

我用Android手机装了个电商软件,抢购用。自己手机的状态栏不能显示秒级别的时间,只能精确到分钟。为了能准确的把握抢购时间,自己边学习边开发了一个时间显示悬浮窗。

WindowManager

参考文章
WindowManager可以在其他应用最上层,甚至手机桌面最上层显示窗口。

  • 使用Context.getSystemService(Context.WINDOW_SERVICE)来获取WindowManager。
  • API 17推出了Presentation,它将自动获取display的Context和WindowManager,可以方便地在另一个display上显示窗口
  • 使用WindowManager继承自基类的addView方法和removeView方法来显示和隐藏窗口
  • WindowManager实现悬浮窗需要声明权限,在manifest中添加如下权限:
  • 在MIUI上需要在设置中打开本应用的”显示悬浮窗”开关,并且重启应用,否则悬浮窗只能显示在本应用界面内,不能显示在手机桌面上。

具体过程

创建工程

用Android Studio创建一个Android Basic Activity工程

添加权限

修改AndroidManifest.xml,添加下面结构的数据

<?xml version="1.0" encoding="utf-8"?>
<manifest >
<!--    显示顶层浮窗权限  -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW">
    </uses-permission>
</manifest>

修改代码

给MainActivity添加两个属性

public class MainActivity extends AppCompatActivity {
    TextView textView; //用于显示时间
    Timer timer;//用于定时刷新时间
    ...
}

Android Basic Activity工程创建后,自带一个按钮,给按钮添加点击事件的处理


final View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
                // 类型 TYPE_SYSTEM_OVERLAY ,当悬浮窗口在其他App窗口上面时,不会隔断触摸事件,其他App能正常使用。
                //若要隔断触摸事件,可以使用TYPE_SYSTEM_ALERT
                params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
                // 设置flag
                int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
                // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
               // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
                // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按

                params.flags = flags;
                // 不设置这个弹出框的透明遮罩显示为黑色
                params.format = PixelFormat.TRANSLUCENT;
                params.width = 300;
                params.height = 50;
                params.gravity = Gravity.TOP;

                TextView top=new TextView(view.getContext());
                //控件字体位置位于左边
                top.setGravity(Gravity.LEFT);
                top.setText("悬浮窗口");

                WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
                windowManager.addView(top,params);

                textView = top;
                startTimer();//启动定时器(实现在后面)
            }
        };

FloatingActionButton fab = findViewById(R.id.fab);
//添加点击事件处理
fab.setOnClickListener(listener);

定时器刷新时间

public  void  startTimer(){

        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                final String dateString = formatter.format(currentTime);

                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(dateString);
                    }
                });

            }
        },1000,300);
    }

完整代码如下

package com.zxs.windonwtimer;

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.view.Gravity;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    TextView textView;
    Timer timer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        final View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
                // 类型
                params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
                // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
                // 设置flag
                int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
                // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
                // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
                // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
                // 不设置这个flag的话,home页的划屏会有问题
                params.flags = flags;
                // 不设置这个弹出框的透明遮罩显示为黑色
                params.format = PixelFormat.TRANSLUCENT;
                params.width = 300;//WindowManager.LayoutParams.MATCH_PARENT;
                params.height = 50;//WindowManager.LayoutParams.MATCH_PARENT;
                params.gravity = Gravity.TOP;

                TextView top=new TextView(view.getContext());
                //控件字体位置位于左边
                top.setGravity(Gravity.LEFT);
                top.setText("悬浮窗口");

                WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
                windowManager.addView(top,params);

                textView = top;
                startTimer();
            }
        };
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(listener);
    }

    public  void  startTimer(){

        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                final String dateString = formatter.format(currentTime);

                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(dateString);
                    }
                });

            }
        },1000,300);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

发表回复

© Beli. All Rights Reserved.