編輯:關於Android編程
仿360安全衛士懸浮窗
雖然360安全衛士很流氓,但是我相信安裝的人不在少數,它有一個讓人很憂傷的功能,就是即時你關閉了360安全衛士,你手機的左邊距或者右邊距會有一個蟲蟲一樣的東西,美其名曰:幫助用戶清理內存的,今天我們就來講一下360懸浮窗怎麼玩,還是先貼圖:
雖然丑了點,但主要在功能,想做漂亮,你們自己找美工P圖吧! 說道懸浮窗,大家可能想到很多方法可以實現,但是怎樣才能讓它在退出Activity之後依然存在呢,首先還是講思路,我們需要解決三大問題: 一、我們必須要想到一個載體,類似狀態欄中的通知,是不是想到了,這個載體就是service,service的生命周期保證了懸浮窗不會隨著Activity退出而被干掉。 二、我們必須要保證懸浮窗能夠顯示在launch上,這裡我給大家推薦一個好東西,WindowManager,他能幫助你很好的解決這個問題。 三、如何獲取內存使用信息,這一點我已經在上一章講過,就不多說了,自己去看:內存獲取 問題解決了,我們就開始貼代碼部分吧(直接復制可用):public class FwService extends Service { private static ActivityManager mActivityManager; //定義浮動窗口布局 LinearLayout mFloatLayout; WindowManager.LayoutParams wmParams; //創建浮動窗口設置布局參數的對象 static WindowManager mWindowManager; Button mFloatView; private static final String TAG = "FwService"; @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.i(TAG, "oncreat"); createFloatView(); //Toast.makeText(FxService.this, "create FxService", Toast.LENGTH_LONG); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } private int width, height; private void createFloatView() { wmParams = new LayoutParams(); mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE); //獲取屏幕的高度 DisplayMetrics dm = new DisplayMetrics(); mWindowManager.getDefaultDisplay().getMetrics(dm); width = dm.widthPixels; height = dm.heightPixels; //設置window type wmParams.type = LayoutParams.TYPE_PHONE; //設置圖片格式,效果為背景透明 wmParams.format = PixelFormat.RGBA_8888; //設置浮動窗口不可聚焦(實現操作除浮動窗口外的其他可見窗口的操作) wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL; //調整懸浮窗顯示的停靠位置為右側側置頂,方便實現觸摸滑動 wmParams.gravity = Gravity.LEFT | Gravity.TOP; // 以屏幕左上角為原點,設置x、y初始值 wmParams.x = width; wmParams.y = height/2; //設置懸浮窗口長寬數據 wmParams.width = LinearLayout.LayoutParams.WRAP_CONTENT; wmParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; LayoutInflater inflater = LayoutInflater.from(getApplication()); //獲取浮動窗口視圖所在布局 mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null); //添加mFloatLayout mWindowManager.addView(mFloatLayout, wmParams); mFloatView = (Button) mFloatLayout.findViewById(R.id.float_id); // int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); // int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); // //設置layout大小 // mFloatLayout.measure(w, h); Log.i(TAG, "Width/2--->" + mFloatView.getMeasuredWidth() / 2); Log.i(TAG, "Height/2--->" + mFloatView.getMeasuredHeight() / 2); mFloatView.setText(getUsedPercentValue(getApplicationContext())); //設置監聽浮動窗口的觸摸移動 mFloatView.setOnTouchListener(new OnTouchListener() { float dx, dy, mx, my; float moveX, moveY; //這裡用於up和move不沖突 boolean isMove; @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub //getRawX是觸摸位置相對於屏幕的坐標,getX是相對於按鈕的坐標 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //記住手按下的位置 dx = event.getRawX(); dy = event.getRawY(); // mx = v.getWidth()/2; // my = v.getHeight()/2; //計算手相對控件本身按下的位置 mx = event.getX(); my = event.getY(); isMove = false;//這裡需要設置默認值為false,避免up部分出bug return false; case MotionEvent.ACTION_MOVE: //計算手移動的距離 int x = Math.abs((int) (event.getRawX() - dx)); int y = Math.abs((int) (event.getRawY() - dy)); //如果x和y距離都小於5,說明用戶並沒打算移動,只是手觸摸時產生的move if (x < 5 || y < 5) { isMove = false; return false; } else { isMove = true; } //計算控件移動的距離 x = (int) (event.getRawX() - mx); y = (int) (event.getRawY() - my); wmParams.x = x; //25為狀態欄的高度 wmParams.y = y; //刷新 mWindowManager.updateViewLayout(mFloatLayout, wmParams); return true; case MotionEvent.ACTION_UP: //這裡要注意邊界問題 float finalX = event.getRawX(); float finalY = event.getRawY(); //控制上邊距 if (finalY < v.getHeight()) { moveX = 0; moveY = finalX - my; } //下邊距 if (finalY > height - v.getHeight()) { moveX = finalX - mx; moveY = finalY - v.getHeight(); } //判斷控件改停留在左邊距還是右邊距 if (finalX - v.getWidth() / 2 < width / 2) { moveX = 0; moveY = finalY - my; } else if (finalX - v.getWidth() / 2 > width / 2) { moveX = width - v.getWidth(); moveY = finalY - my; } wmParams.x = (int) moveX; wmParams.y = (int) moveY; if (isMove) { mWindowManager.updateViewLayout(mFloatLayout, wmParams); } return isMove;//false為down,true為move default: break; } //這裡return ture,說明本次事件已經被處理,不會傳給父親 return false; } }); mFloatView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Toast.makeText(FwService.this, "onClick", Toast.LENGTH_SHORT).show(); } }); } /** * 計算已使用內存的百分比,並返回。 * * @param context * 可傳入應用程序上下文。 * @return 已使用內存的百分比,以字符串形式返回。 */ public static String getUsedPercentValue(Context context) { //內存信息文件(CPU信息文件:/proc/cpuinfo)這兩個文件是linux系統用來存儲內存和CPU信息的 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(); //獲取總的內存,這裡需要注意的是replaceAll支持正則表達式"\\D"代表所有的字母字符,只保留數字部分 long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll("\\D+", "")); //獲取當前可用內存 long availableSize = getAvailableMemory(context) / 1024; int percent = (int) ((totalMemorySize - availableSize) / (float) totalMemorySize * 100); return percent + "%"; } catch (IOException e) { e.printStackTrace(); } return "懸浮窗"; } /** * 獲取當前可用內存,返回數據以字節為單位。 * * @param context * 可傳入應用程序上下文。 * @return 當前可用內存。 */ private static long getAvailableMemory(Context context) { ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); getActivityManager(context).getMemoryInfo(mi); long currentMemory = mi.availMem; return currentMemory; } /** * 如果ActivityManager還未創建,則創建一個新的ActivityManager返回。否則返回當前已創建的ActivityManager。 * * @param context * 可傳入應用程序上下文。 * @return ActivityManager的實例,用於獲取手機可用內存。 */ private static ActivityManager getActivityManager(Context context) { if (mActivityManager == null) { mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); } return mActivityManager; } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (mFloatLayout != null) { mWindowManager.removeView(mFloatLayout); } } }至於如何調用,那就再簡單不過了:
Intent intent = new Intent(MainActivity.this, FwService.class); startService(intent);講到這裡就基本講完了,主要還是思路,下一章我將為大家講述仿360懸浮窗的進階篇,代碼部分會更優化。我的博客只要是功能模塊的,都會給源碼,看完博客內容的當然是免費,如果想奉獻點積分給我,也可以去我的CSDN下載欄去下載
大概去年的這個時候,有跟大家分享簡潔天氣這個應用。該應用一開始使用的是中國天氣網的數據,但是,由於需要重復多次請求服務器獲取信息才能滿足我們的需求,因此,後來我偷偷的將天
Android 實現 IOS相機滑動控件IOS相比於Android,動畫效果是一方面優勢,IOS相機切換時滑動的動畫很不錯,看著是有一個3D的效果,而且變化感覺很自然。A
導語 本文主要是圍繞android直播助手的功能做了一些研究,因為之前對Android多媒體相關的內容知之甚少,只有概念,於是查閱了相關資料並做以總結。由於我對音視頻相關
仿QQ側滑刪除效果圖1.自定義listviewpublic class DragDelListView extends ListView { private boole