Android之仿IOS悬浮窗
生活随笔
收集整理的這篇文章主要介紹了
Android之仿IOS悬浮窗
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在一些場合里,我們使用懸浮窗會有很大的便利,比如IOS系統(tǒng)的懸浮窗,360或者其他手機(jī)衛(wèi)士的懸浮窗等等。
本篇博客,我們創(chuàng)造出兩個懸浮窗,通過點擊小懸浮窗打開或者關(guān)閉大懸浮窗。
代碼如下:
在這之前,我們需要在manifest中申請權(quán)限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
1
并且,懸浮窗這個權(quán)限我們需要手動在手機(jī)找到應(yīng)用權(quán)限管理,允許這個權(quán)限才行
?小懸浮窗的界面代碼float_normal_view.xml
大懸浮窗的界面代碼float_window_big.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/big_window_layout"android:layout_width="200dip"android:layout_height="100dip"android:background="@android:color/holo_green_dark"android:orientation="vertical"><Buttonandroid:id="@+id/close"android:layout_width="100dip"android:layout_height="40dip"android:layout_gravity="center_horizontal"android:layout_marginTop="12dip"android:text="關(guān)閉懸浮窗"/><Buttonandroid:id="@+id/back"android:layout_width="100dip"android:layout_height="40dip"android:layout_gravity="center_horizontal"android:text="主頁"/> </LinearLayout>入口activity(MainActivity ):
public class MainActivity extends Activity {MyWindowManager myWindowManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if(!Settings.canDrawOverlays(getApplicationContext())) {//啟動Activity讓用戶授權(quán)Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);intent.setData(Uri.parse("package:" + getPackageName()));startActivityForResult(intent,100);}}setContentView(R.layout.activity_main);myWindowManager = MyWindowManager.getInstance();myWindowManager.createNormalView(this.getApplicationContext());}}懸浮窗管理器MyWindowManager:
public class MyWindowManager {private FloatNormalView normalView;private Context mContext;private static MyWindowManager instance;private WindowManager windowManager;private MyWindowManager() {}public static MyWindowManager getInstance() {if (instance == null)instance = new MyWindowManager();return instance;}private WindowManager getWindowManager(Context context) {if (windowManager == null)windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);mContext=context;return windowManager;}/*** 判斷小懸浮窗是否存在** @return*/public boolean isNormalViewExists() {return normalView != null;}/*** 創(chuàng)建小型懸浮窗*/public void createNormalView(Context context) {if (normalView == null) {normalView = new FloatNormalView(context);}}/*** 移除懸浮窗** @param context*/public void removeNormalView(Context context) {if (normalView != null) {windowManager.removeView(normalView);normalView = null;}}FloatWindowBigView bigWindow;private WindowManager.LayoutParams bigWindowParams;public void createBigWindow(Context context) {WindowManager windowManager = getWindowManager(context);int screenWidth = windowManager.getDefaultDisplay().getWidth();int screenHeight = windowManager.getDefaultDisplay().getHeight();if (bigWindow == null) {bigWindow = new FloatWindowBigView(context);if (bigWindowParams == null) {bigWindowParams = new WindowManager.LayoutParams();bigWindowParams.x = screenWidth / 2 - FloatWindowBigView.viewWidth / 2;bigWindowParams.y = screenHeight / 2 - FloatWindowBigView.viewHeight / 2;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {bigWindowParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;}else {bigWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;}bigWindowParams.format = PixelFormat.RGBA_8888;bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP;bigWindowParams.width = FloatWindowBigView.viewWidth;bigWindowParams.height = FloatWindowBigView.viewHeight;}windowManager.addView(bigWindow, bigWindowParams);}}public void removeBigWindow(Context context) {if (bigWindow != null) {WindowManager windowManager = getWindowManager(context);windowManager.removeView(bigWindow);bigWindow = null;}} }小懸浮窗FloatNormalView:
public class FloatNormalView extends LinearLayout implements View.OnTouchListener {private final static String TAG="FloatNormalView";/*** 記錄小懸浮窗的寬度*/public static int viewWidth;/*** 記錄小懸浮窗的高度*/public static int viewHeight;/*** 記錄系統(tǒng)狀態(tài)欄的高度*/private static int statusBarHeight;/*** 用于更新小懸浮窗的位置*/private WindowManager windowManager;/*** 小懸浮窗的參數(shù)*/private WindowManager.LayoutParams mParams;/*** 記錄當(dāng)前手指位置在屏幕上的橫坐標(biāo)值*/private float xInScreen,xInitScreen;/*** 記錄當(dāng)前手指位置在屏幕上的縱坐標(biāo)值*/private float yInScreen,yInitScreen;/*** 記錄手指按下時在屏幕上的橫坐標(biāo)的值*/private float xDownInScreen;/*** 記錄手指按下時在屏幕上的縱坐標(biāo)的值*/private float yDownInScreen;/*** 記錄手指按下時在小懸浮窗的View上的橫坐標(biāo)的值*/private float xInView;/*** 記錄手指按下時在小懸浮窗的View上的縱坐標(biāo)的值*/private float yInView;public FloatNormalView(Context context) {super(context);windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);LayoutInflater.from(context).inflate(R.layout.float_normal_view, this);View view = findViewById(R.id.ll_float_normal);viewWidth = view.getLayoutParams().width;viewHeight = view.getLayoutParams().height;initLayoutParams();}OnClickListener circleClickListener=new OnClickListener() {@Overridepublic void onClick(View view) {MyWindowManager.getInstance().createBigWindow(getContext());MyWindowManager.getInstance().removeNormalView(getContext());}};/*** 初始化參數(shù)*/private void initLayoutParams() {//屏幕寬高int screenWidth = windowManager.getDefaultDisplay().getWidth();int screenHeight = windowManager.getDefaultDisplay().getHeight();mParams = new WindowManager.LayoutParams();// FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到后面的窗口// FLAG_NOT_FOCUSABLE 懸浮窗口較小時,后面的應(yīng)用圖標(biāo)由不可長按變?yōu)榭砷L按,不設(shè)置這個flag的話,home頁的劃屏?xí)袉栴}mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//懸浮窗默認(rèn)顯示的位置mParams.gravity = Gravity.START | Gravity.TOP;//指定位置mParams.x = screenWidth - viewWidth * 2;mParams.y = screenHeight / 2 + viewHeight * 2;//懸浮窗的寬高mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;mParams.format = PixelFormat.TRANSPARENT;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {mParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;}else {mParams.type = WindowManager.LayoutParams.TYPE_PHONE;}mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;windowManager.addView(this, mParams);}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i(TAG,"hsz--->onTouchEvent:"+event.getAction());switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 手指按下時記錄必要數(shù)據(jù),縱坐標(biāo)的值都需要減去狀態(tài)欄高度xInView =xInitScreen= event.getX();yInView =yInitScreen= event.getY();xDownInScreen = event.getRawX();yDownInScreen = event.getRawY() - getStatusBarHeight();xInScreen = event.getRawX();yInScreen = event.getRawY() - getStatusBarHeight();break;case MotionEvent.ACTION_MOVE:xInScreen = event.getRawX();yInScreen = event.getRawY() - getStatusBarHeight();// 手指移動的時候更新小懸浮窗的位置updateViewPosition();break;case MotionEvent.ACTION_UP:// 如果手指離開屏幕時,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,則視為觸發(fā)了單擊事件。if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {openOrCloseControlView();}Float distanceX=event.getX()-xInitScreen;Float distanceY=event.getY()-yInitScreen;if(distanceX==0 && distanceY==0){MyWindowManager.getInstance().createBigWindow(getContext());MyWindowManager.getInstance().removeNormalView(getContext());}break;default:break;}return true;}/*** 將小懸浮窗的參數(shù)傳入,用于更新小懸浮窗的位置。** @param params 小懸浮窗的參數(shù)*/public void setParams(WindowManager.LayoutParams params) {mParams = params;}/*** 更新小懸浮窗在屏幕中的位置。*/private void updateViewPosition() {mParams.x = (int) (xInScreen - xInView);mParams.y = (int) (yInScreen - yInView);windowManager.updateViewLayout(this, mParams);}/*** 用于獲取狀態(tài)欄的高度。** @return 返回狀態(tài)欄高度的像素值。*/private int getStatusBarHeight() {if (statusBarHeight == 0) {try {Class<?> c = Class.forName("com.android.internal.R$dimen");Object o = c.newInstance();Field field = c.getField("status_bar_height");int x = (Integer) field.get(o);statusBarHeight = getResources().getDimensionPixelSize(x);} catch (Exception e) {e.printStackTrace();}}return statusBarHeight;}@Overridepublic boolean onTouch(View v, MotionEvent event) {return false;} }大懸浮窗FloatWindowBigView:
public class FloatWindowBigView extends LinearLayout {/*** 記錄大懸浮窗的寬度*/public static int viewWidth;/*** 記錄大懸浮窗的高度*/public static int viewHeight;public FloatWindowBigView(final Context context) {super(context);LayoutInflater.from(context).inflate(R.layout.float_window_big, this);View view = findViewById(R.id.big_window_layout);viewWidth = view.getLayoutParams().width;viewHeight = view.getLayoutParams().height;Button close = (Button) findViewById(R.id.close);Button back = (Button) findViewById(R.id.back);close.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 點擊關(guān)閉懸浮窗的時候MyWindowManager.getInstance().removeBigWindow(context);MyWindowManager.getInstance().createNormalView(context);}});back.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 點擊主頁的時候,移除大懸浮窗,創(chuàng)建小懸浮窗Intent intent = new Intent(Intent.ACTION_MAIN);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.addCategory(Intent.CATEGORY_HOME);context.startActivity(intent);MyWindowManager.getInstance().removeBigWindow(context);MyWindowManager.getInstance().createNormalView(context);}});} }?
總結(jié)
以上是生活随笔為你收集整理的Android之仿IOS悬浮窗的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 纯干货!UG模具设计,实体分模思路分析
- 下一篇: 物资配送路径问题(一)