2022-10-10 Android 在其他应用上的悬浮窗View
生活随笔
收集整理的這篇文章主要介紹了
2022-10-10 Android 在其他应用上的悬浮窗View
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、在samsung android8.0 真機(jī)運(yùn)行效果圖如下
二、廢話不多說,直接上代碼
? ? 1、代碼架構(gòu)
? ? 2、java/com/example/suspendedwindow/MainActivity.java
package com.example.suspendedwindow;import androidx.appcompat.app.AppCompatActivity;import java.util.Timer; import java.util.TimerTask;import android.annotation.SuppressLint; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast;/*** 倒計(jì)時(shí)60s懸浮窗** @author zy**/ public class MainActivity extends Activity {protected static final String TAG = "CountDownActivity";protected static final int TIME = 1;private Context context = MainActivity.this;private TextView tv_time;private Button cancle;private static Timer countDown = null;private int mValue = 60;private int statusBarHeight;// 狀態(tài)欄高度WindowManager wm;WindowManager.LayoutParams params ;View countDownView;private boolean viewAdded = false;// 透明窗體是否已經(jīng)顯示//private WindowManager.LayoutParams layoutParams ;Handler post = new Handler();LinearLayout commonCardContainer;LinearLayout.LayoutParams params_window;int width = 10;boolean lock = false ;int remeberx = 0;int remebery = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/*** 點(diǎn)擊顯示懸浮窗** @param*/@SuppressLint("WrongConstant")public void show(View v) {wm = (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE); // 注意:這里必須是全局的context// 判斷UI控件是否存在,存在則移除,確保開啟任意次應(yīng)用都只有一個(gè)懸浮窗if (countDownView != null) {wm.removeView(countDownView);}/*params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); */params = new WindowManager.LayoutParams();params.width = WindowManager.LayoutParams.WRAP_CONTENT;params.height = WindowManager.LayoutParams.WRAP_CONTENT;params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;// 系統(tǒng)級別的窗口params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;//| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY// params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;// 居中顯示// params.gravity = Gravity.CENTER;//params.gravity = Gravity.RIGHT|Gravity.BOTTOM; //懸浮窗開始在右下角顯示params.gravity = Gravity.LEFT | Gravity.TOP;// 設(shè)置背景透明params.format = PixelFormat.TRANSPARENT;countDownView = new View(getApplicationContext()); // 不依賴activity的生命周期countDownView = View.inflate(getApplicationContext(),R.layout.countdown_weight, null);cancle = (Button) countDownView.findViewById(R.id.cancle);tv_time = (TextView) countDownView.findViewById(R.id.tv_time);tv_time.setText("60");wm.addView(countDownView, params);viewAdded = true;/*** 監(jiān)聽窗體移動事件*/countDownView.setOnTouchListener(new View.OnTouchListener() {float[] temp = new float[] { 0f, 0f };public boolean onTouch(View v, MotionEvent event) {Log.i(TAG, "temp[0]:" + temp[0]+" temp[1]:" + temp[1] + " X:" + event.getX()+" Y:"+event.getY() + " RawX:"+event.getRawX() + " RawY:"+event.getRawY());if(lock)return true;int eventaction = event.getAction();switch (eventaction) {case MotionEvent.ACTION_DOWN: // 按下事件,記錄按下時(shí)手指在懸浮窗的XY坐標(biāo)值temp[0] = event.getX();temp[1] = event.getY();break;case MotionEvent.ACTION_MOVE:refreshView((int) (event.getRawX() - temp[0]),(int) (event.getRawY() - temp[1]));break;}return true;}});// 設(shè)置“取消”倒計(jì)時(shí)按鈕的監(jiān)聽cancle.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {/*Log.e(TAG, "取消倒計(jì)時(shí)");wm.removeView(countDownView);countDownView = null;countDown.cancel();mValue = 999;*/ /*ImageView twenty_four_hour = (ImageView) countDownView.findViewById(R.id.img);LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) twenty_four_hour.getLayoutParams();lp.width = ++lp.width;twenty_four_hour.setLayoutParams(lp);Log.i(TAG, "lp.width:"+lp.width); */lock = !lock;if(lock){Toast.makeText(MainActivity.this, "Locked", Toast.LENGTH_SHORT).show();params.flags = 0 ;refresh();}else {Toast.makeText(MainActivity.this, "Unocked", Toast.LENGTH_SHORT).show();params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;refresh();}}});// 添加倒計(jì)時(shí)功能countDown = new Timer();countDown.schedule(new TimerTask() {@Overridepublic void run() {mValue--;post.post(drawCount);if (mValue == 0) {// 執(zhí)行關(guān)機(jī)操作(這里可以使任意其他操作,根據(jù)自己的需求)Log.e(TAG, "關(guān)機(jī)");wm.removeView(countDownView);countDownView = null;// 取消定時(shí)countDown.cancel();finish();}}}, 0, 1000);// refreshView(295, 949);finish();}private void refreshView(int x, int y) {// 狀態(tài)欄高度不能立即取,不然得到的值是0if (statusBarHeight == 0) {View rootView = countDownView.getRootView();Rect r = new Rect();rootView.getWindowVisibleDisplayFrame(r);statusBarHeight = r.top;}params.x = x;// y軸減去狀態(tài)欄的高度,因?yàn)闋顟B(tài)欄不是用戶可以繪制的區(qū)域,不然拖動的時(shí)候會有跳動params.y = y - statusBarHeight;// STATUS_HEIGHT;Log.i(TAG, " x:"+x+" y:"+y+" params.x:"+params.x+" params.y:" +params.y +" statusBarHeight:"+statusBarHeight);// params.x = 1080- params.x;// params.y = 1920- params.y;//params.x = 311 ;//params.y = 1114 ;remeberx = params.x;remebery = params.y;refresh(); /*ImageView twenty_four_hour = (ImageView) countDownView.findViewById(R.id.img);LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) twenty_four_hour.getLayoutParams();twenty_four_hour.setLayoutParams(lp);Log.i(TAG, "lp.width:"+lp.width);*/}/*** 添加懸浮窗或者更新懸浮窗 如果懸浮窗還沒添加則添加 如果已經(jīng)添加則更新其位置*/private void refresh() {// 如果已經(jīng)添加了就只更新viewif (viewAdded) {wm.updateViewLayout(countDownView, params);} else {wm.addView(countDownView, params);viewAdded = true;}}/*** 模擬其他操作* @param view*/public void other(View view) {Toast.makeText(context, "別的操作", Toast.LENGTH_SHORT).show();ImageView twenty_four_hour = (ImageView) findViewById(R.id.img);RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) twenty_four_hour.getLayoutParams();lp.width = lp.width + 1;twenty_four_hour.setLayoutParams(lp);Log.i(TAG, "lp.width:"+lp.width+ " topMargin:"+lp.topMargin);// startActivity(new Intent(context, NewActivity.class));}Runnable drawCount = new Runnable() {@Overridepublic void run() {tv_time.setText(Integer.toString(mValue));}};@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "倒計(jì)時(shí)結(jié)束");}; }? ? 3、res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><ImageViewandroid:id="@+id/img"android:layout_width="152px"android:layout_height="wrap_content"android:layout_marginTop="126px"android:text="60"android:textColor="#ff0000"android:background="@drawable/background"android:textSize="25dp" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="show"android:text="點(diǎn)擊顯示彈窗" /><Buttonandroid:layout_alignParentBottom="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="other"android:text="別的操作" /></RelativeLayout>? ? 4、res/layout/countdown_weight.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/twenty_four_hour"android:layout_gravity="center"android:gravity="center_horizontal"android:orientation="vertical"android:padding="10dp" ><ImageViewandroid:id="@+id/img"android:layout_width="433px"android:layout_height="290px"android:text="60"android:textColor="#ff0000"android:background="@drawable/background"android:textSize="25dp" /><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="60"android:textColor="#ff0000"android:textSize="25dp" /><Buttonandroid:id="@+id/cancle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="取消"android:textSize="25dp"android:textColor="#000" /><!-- android:background="@drawable/xml_sel_button_bg" --></LinearLayout></FrameLayout>? ? 5、申請權(quán)限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />? ? 6、遇到的一個(gè)坑
?
三、參考文章
(664條消息) Android懸浮窗看這篇就夠了_AndroidLMY的博客-CSDN博客_android 懸浮窗
(664條消息) Android懸浮窗的坑_android_cai_niao的博客-CSDN博客_android studio 懸浮窗
(664條消息) Android常用控件之懸浮窗_dztai的博客-CSDN博客_安卓懸浮窗
(664條消息) Android懸浮窗的實(shí)現(xiàn)--可以置頂,可以設(shè)置優(yōu)先級的view_兮誰與歌的博客-CSDN博客_倒計(jì)時(shí)懸浮窗
總結(jié)
以上是生活随笔為你收集整理的2022-10-10 Android 在其他应用上的悬浮窗View的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql5.7.20中文,ubuntu
- 下一篇: android image设置adjus