android 浮動視窗學習筆記及個人理解(仿360手機小幫手)

來源:互聯網
上載者:User

標籤:android   浮動視窗   

非常感謝原文作者

http://blog.csdn.net/guolin_blog/article/details/8689140

經自己理解

 

程式運行介面如:

1.程式入口介面

 



2.小浮動視窗

 

 

3.大浮動視窗

 

 

由可看出,可以看出我們基本需要:

1.一個主Activity

2.小浮動視窗view介面

3.大浮動視窗view介面

 

對於浮動視窗的管理我們還需要

4.一個Service(在後台監控管理浮動視窗的狀態)

5.視窗管理類(建立/消除浮動視窗)

 

代碼:

package com.ww.activity;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import com.ww.service.FloatWindowService;/** * Activity * 程式主入口 *  * @author wangwei * @Email [email protected] * */public class MainActivity extends Activity {private Button btnFloatWin;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);init();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}private void init(){btnFloatWin = (Button) findViewById(R.id.btnFloatWin);btnFloatWin.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 啟動浮動視窗ServiceIntent intent = new Intent(MainActivity.this, FloatWindowService.class);startService(intent);finish();}});}@Overrideprotected void onResume() {super.onResume();}/** * 列印日誌 * @param msg */private static void log(String msg) {Log.i("Test", msg);}}

package com.ww.view;import android.content.Context;import android.graphics.Rect;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.TextView;import com.ww.activity.R;import com.ww.bean.MyWindowManager;/** * 小浮動視窗視圖 * 小浮動視窗可在螢幕上自由拖動(除狀態列部分) * @author wangwei * */public class FloatWindowSmallView extends LinearLayout {// 小浮動視窗(視圖)寬、小浮動視窗(視圖)高、狀態列高public static int viewWidth, viewHeigth, statusBarHeight;// android 視窗管理器private WindowManager windowManager;// 視窗管理器參數private WindowManager.LayoutParams mParams;// 移動時對應螢幕的x,y座標;private float xInScreen, yInScreen;// 按下時對應螢幕的x,y座標;private float xDownInScreen, yDownInScreen;// 按下時對應small_window_layout View中的x,y座標private float xInView, yInView;TextView percentView;public FloatWindowSmallView(Context context) {super(context);windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);/* * 尋找res/layout/下的XML檔案 * 對於一個沒有被載入或者想要動態載入的介面,使用LayoutInflater.inflate()來載入 */LayoutInflater.from(context).inflate(R.layout.float_window_small, this);View view = findViewById(R.id.small_window_layout);/* * viewWidth 計算方式  * float_window_small ID:small_window_layout的 width heigth 為 60dp 25dp * 簡單計算出像素方法,螢幕密度為160的裝置 1dp=1px  * 我當前使用模擬器像素為480*800 螢幕密度為240(螢幕密度計算方式 根號內 長(像素)平方 + 寬(像素)平方 除 螢幕英寸 )  * 240/160=1.5  * 所以對應的像素為 60dp * 1.5 = 90px *  * viewHeight 計算方式(與上相同) * 25dp * 1.5 = 37.5px */ viewWidth = view.getLayoutParams().width;viewHeigth = view.getLayoutParams().height;percentView = (TextView) findViewById(R.id.tvPercent);percentView.setText("XXX");}/** * 觸摸事件 * 小浮動視窗 * 1.按下時 擷取各種x,y座標 * >> 擷取view中的x,y座標 *         擷取按下時在螢幕中的x,y座標 *         擷取移動時在螢幕中的x,y座標 *          * 2.移動時 * >> 更新view的位置 *  * 3.鬆開時 * >> 判斷按下與移動的x,y座標是否相等,如果相等表示未移動view位置,開啟大的浮動視窗 *  *  */@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 1xInView = event.getX();yInView = event.getY();xDownInScreen = event.getRawX();yDownInScreen = event.getRawY() - getStatusBarHeight();xInScreen = event.getRawX();yInScreen = event.getRawY() - getStatusBarHeight();break;case MotionEvent.ACTION_MOVE:// 2xInScreen = event.getRawX();// 不能移動到狀態列地方yInScreen = event.getRawY() - getStatusBarHeight();updateViewPosition();break;case MotionEvent.ACTION_UP:// 3if(xDownInScreen == xInScreen && yDownInScreen == yInScreen){openBigWindow();}break;default:break;}return true;}/** * 設定viewLayout的參數 *  * @param params */public void setParams(WindowManager.LayoutParams params){mParams = params;}/** * 更新view位置 * 主要用來設定x,y座標,用來改變view位置 */private void updateViewPosition(){mParams.x = (int) (xInScreen - xInView);mParams.y = (int) (yInScreen - yInView);windowManager.updateViewLayout(this, mParams);}/** * 開啟大視窗 * 移動小視窗視圖 */private void openBigWindow(){MyWindowManager.createBigWindow(getContext());MyWindowManager.removeSmallWindow(getContext());}/** * 擷取狀態列高度 * 這裡包含了兩種擷取方式  * 1.使用反射方式擷取內部API * 2.使用正常API介面擷取(推薦) *  * @return */private int getStatusBarHeight(){Rect frame = new Rect();this.getWindowVisibleDisplayFrame(frame);// 狀態列高度statusBarHeight = frame.top;/* * 擷取應用的標題列高度 * 因沒有應用介面,所以下面代碼會擷取失敗,在此項目中也無需擷取該值 */// int contentTop = this.findViewById(Window.ID_ANDROID_CONTENT).getTop();// int titleBarHeight = contentTop - top;// log("titleBarHeight>>>"+titleBarHeight);/* * 使用反射的方法調用內部API擷取狀態列高度 * 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 = field.getInt(o);statusBarHeight = getResources().getDimensionPixelOffset(x);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}*/log("statusBarHeight >> "+statusBarHeight);return statusBarHeight;}/** * 列印日誌 * @param msg */private static void log(String msg) {Log.i("Test", msg);}}

<pre name="code" class="java">package com.ww.bean;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import android.app.ActivityManager;import android.content.Context;import android.graphics.PixelFormat;import android.graphics.Point;import android.util.Log;import android.view.Gravity;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.TextView;import com.ww.activity.R;import com.ww.view.FloatWindowBigView;import com.ww.view.FloatWindowSmallView;/** * 視窗管理 * @author wangwei * */public class MyWindowManager {// 大浮動視窗private static FloatWindowSmallView smallWindow;// 小浮動視窗private static FloatWindowBigView bigWindow;// 小浮動視窗參數、大浮動視窗參數 private static LayoutParams smallWindowParams, bigWindowParams;// 視窗管理 private static WindowManager mWindowManager;private static ActivityManager mActivityManager;/** * 建立小浮動視窗 * @param context */public static void createSmallWindow(Context context){WindowManager windowManager = getWindowManager(context);/* * 擷取螢幕width和height 像素方法 * minSdkVersion 13 以上使用此方法 */Point p = new Point();getWindowManager(context).getDefaultDisplay().getSize(p);int screenWidth = p.x;int screenHeigth = p.y;/* * 另一種擷取螢幕width和height 像素方法(已淘汰) * int screenWidth = windowManager.getDefaultDisplay().getWidth();int screenHeigth = windowManager.getDefaultDisplay().getHeight();*/if(smallWindow == null){smallWindow = new FloatWindowSmallView(context);if(smallWindowParams  == null){smallWindowParams = new LayoutParams();// 它置於所有應用程式之上,狀態列之下smallWindowParams.type = LayoutParams.TYPE_PHONE;// 位元影像格式smallWindowParams.format = PixelFormat.RGBA_8888;/* * 行為選項,預設為 none * 當前視窗可以獲得焦點 | 不接受觸控螢幕事件 * 不接受浮動視窗之外的點擊事件 */smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;// 浮動視窗停靠smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP;// 浮動視窗寬smallWindowParams.width = FloatWindowSmallView.viewWidth;// 浮動視窗高smallWindowParams.height = FloatWindowSmallView.viewHeigth;// 浮動視窗x座標smallWindowParams.x = screenWidth;// 浮動視窗y座標smallWindowParams.y = screenHeigth / 2;}smallWindow.setParams(smallWindowParams);// 將小浮動視窗及浮動視窗參數添加視窗中windowManager.addView(smallWindow, smallWindowParams);}}/** * 移動小浮動視窗 * @param context */public static void removeSmallWindow(Context context){if(smallWindow != null){WindowManager windowManager = getWindowManager(context);windowManager.removeView(smallWindow);smallWindow = null;}}/** * 建立大浮動視窗 * @param context */public static void createBigWindow(Context context){WindowManager windowManager = getWindowManager(context);int screenWidth = windowManager.getDefaultDisplay().getWidth();int screenHeigth = windowManager.getDefaultDisplay().getHeight();if(bigWindow == null){bigWindow = new FloatWindowBigView(context);if(bigWindowParams == null){/* * 參數說明與建立小浮動視窗類別似 * 詳見createSmallWindow */bigWindowParams = new LayoutParams();bigWindowParams.x = screenWidth / 2 - FloatWindowBigView.viewWidth / 2;bigWindowParams.y = screenHeigth / 2 - FloatWindowBigView.viewHeight / 2;bigWindowParams.type = LayoutParams.TYPE_PHONE;bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP;bigWindowParams.width = FloatWindowBigView.viewWidth;bigWindowParams.height = FloatWindowBigView.viewHeight;}windowManager.addView(bigWindow, bigWindowParams);}}/** * 移動大浮動視窗 * @param context */public static void removeBigWindow(Context context){if(bigWindow != null){WindowManager windowManager = getWindowManager(context);windowManager.removeView(bigWindow);bigWindow = null;}}/** * 更新記憶體使用量率 * @param context */public static void updateUsedPercent(Context context){if(smallWindow != null){TextView percentView = (TextView) smallWindow.findViewById(R.id.tvPercent);percentView.setText(getUsedPercentValue(context));}}/** * 判斷小浮動視窗或大浮動視窗是否顯示  * @return */public static boolean isWindowShowing(){return smallWindow !=null || bigWindow != null;}/** * 擷取 WindowManager 對象 * @param context * @return */private static WindowManager getWindowManager(Context context){if(mWindowManager == null){mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);}return mWindowManager;}/** * 擷取 ActivityManager 對象 * @param context * @return */private static ActivityManager getActivityManager(Context context){if(mActivityManager == null){mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);}return mActivityManager;}/** * 擷取 記憶體 使用率 * @param context * @return 記憶體佔用百分比 */public static String getUsedPercentValue(Context context){String dir = "/proc/meminfo";try {FileReader fr = new FileReader(dir);BufferedReader br = new BufferedReader(fr, 2048);String memoryLine = br.readLine();String subMemoryLine = memoryLine.substring(memoryLine.indexOf("MemTotal"));br.close();// 總記憶體long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll("\\D+", ""));// 當前剩餘記憶體long availableSize = getAvailableMemory(context) / 1024;//log(totalMemorySize + "----" + availableSize);// 已用記憶體百分比int percent = (int)((totalMemorySize - availableSize) / (float)totalMemorySize * 100);return percent + "%";} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return "懸浮窗";}/** * 擷取 當前剩餘記憶體  *  * 想使用mi.totalMem擷取總記憶體,但報錯,不知道為何 *  * @param context * @return */private static long getAvailableMemory(Context context){ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();getActivityManager(context).getMemoryInfo(mi);return mi.availMem;}/** * 列印日誌 * @param msg */private static void log(String msg) {Log.i("Test", msg);}}



package com.ww.service;import java.util.ArrayList;import java.util.List;import java.util.Timer;import java.util.TimerTask;import android.app.ActivityManager;import android.app.ActivityManager.RunningTaskInfo;import android.app.Service;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.os.Handler;import android.os.IBinder;import android.util.Log;import com.ww.bean.MyWindowManager;/** * Service * 浮動視窗Service  * 使用定時任務監控管理浮動視窗的狀態 * 大小浮動視窗的建立移動及視窗位置管理 *  * @author wangwei * */public class FloatWindowService extends Service {private Handler handler = new Handler();private Timer timer;@Overridepublic IBinder onBind(Intent intent) {return null;}/** * 啟動服務(服務啟動時) * 調度定時任務 */@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {if(timer == null){timer = new Timer();timer.scheduleAtFixedRate(new RefreshTask(), flags, startId);}return super.onStartCommand(intent, flags, startId);}/** * 服務登出(服務停止時) * 1.取消定時任務高度 * 2.將timer定時器設定為null */@Overridepublic void onDestroy() {super.onDestroy();timer.cancel();timer = null;}/** *  * 定時任務執行線程 * 有三種情況 * 1.當前在HOME介面,並且浮動視窗(大視窗和小視窗)沒有顯示 * >> 建立小視窗 *  * 2.當前不在HOME介面,並且浮動視窗(大視窗或小視窗)已顯示 * >> 移動小視窗或大視窗 *  * 3.當前在HOME介面,並且浮動視窗(大視窗或小視窗)已顯示 * >> 更新視窗位置 *  * @author wangwei * @date 2014-6-13 */class RefreshTask extends TimerTask{@Overridepublic void run() {if(isHome() && !MyWindowManager.isWindowShowing()){// 1 handler.post(new Runnable() {@Overridepublic void run() {MyWindowManager.createSmallWindow(getApplicationContext());}});}else if(!isHome() && MyWindowManager.isWindowShowing()){// 2handler.post(new Runnable() {@Overridepublic void run() {MyWindowManager.removeSmallWindow(getApplicationContext());MyWindowManager.removeBigWindow(getApplicationContext());}});}else if(isHome() && MyWindowManager.isWindowShowing()){// 3handler.post(new Runnable() {@Overridepublic void run() {MyWindowManager.updateUsedPercent(getApplicationContext());}});}}}/** * 是否在Home介面  * @return */private boolean isHome(){// Activity管理器ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);/* * 獲得當前正在啟動並執行任務  * 返回最多任務數 * mActivityManager.getRunningTasks(maxNum);   * 這裡1就夠了 得到的即為當前正在運行(可見)的任務 */List<RunningTaskInfo> listRti = mActivityManager.getRunningTasks(1);return getHomes().contains(listRti.get(0).topActivity.getPackageName());}/** * 得到所有的Home介面 * @return Home應用的包名 */private List<String> getHomes(){List<String> names = new ArrayList<String>();// 包管理器PackageManager packageManager = this.getPackageManager();Intent intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);// 尋找出屬於案頭應用的列表 List<ResolveInfo> listRi = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo ri : listRi) {names.add(ri.activityInfo.packageName);}return names;}/** * 列印日誌 * @param msg */private static void log(String msg) {Log.i("Test", msg);}}




如需要原碼,可在評論下留下郵箱地址

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.