Android_WindowManager_實現類似360流量懸浮框

1.示意圖

2.過程實現

這裡主要用到WindowManager類,通過WindowManager的addView(View view, WindowManager.LayoutParams params)方法可以在窗體中添加view對象,如果希望浮動窗體隨手指一塊移動,應該修改params參數並通過windowManager對象的updateViewLayout()方法完成更新,並配合service!對於WindowManager.LayoutParams這裡不做介紹,不瞭解的朋友可以網上查~

 


 

/**
 * 
 * @author zimo2013
 * @see https://blog.csdn.net/zimo2013
 *
 */
public class MyService extends Service {

	private MyWindowManager windowManager;
	/*
	 * 這裡使用線程池,比如訪問網絡數據的實時更新,主要完成於懸浮框的通信,可根據需要實現,這裡並沒有實現
	 */
	private ScheduledExecutorService threadPool;

	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (windowManager == null) {
			windowManager = MyWindowManager
					.getInstance(getApplicationContext());
		}

		if (threadPool == null) {
			threadPool = Executors.newScheduledThreadPool(1);
			threadPool.scheduleAtFixedRate(command, 0, 1, TimeUnit.SECONDS);
		}
		//開啟懸浮框
		windowManager.show();
		return super.onStartCommand(intent, flags, startId);
	}
	private Runnable command = new Runnable() {
		@Override
		public void run() {
			// 在該方法中,定時更新ui,比如訪問網絡數據的實時更新,主要完成於懸浮框的通信,這裡暫不實現
			System.out.println(run());
			
		}
	};

	public void onDestroy() {
		super.onDestroy();

		if (threadPool != null) {
			threadPool.shutdown();
			threadPool = null;
		}
	}
}
/**
 * 單例設計
 * 
 * @author zimo2013
 * @see https://blog.csdn.net/zimo2013
 * 
 */
public class MyWindowManager {

	private static MyWindowManager manager;

	private MyWindowManager() {
	}

	private static WindowManager winManager;
	private static Context context;
	private LayoutParams params;
	private LayoutParams paramsContent;
	/**
	 * 顯示的浮動窗體
	 */
	private FloatView floatView;
	/**
	 * 點擊浮動窗體後的詳細信息
	 */
	private FloatContentView floatContentView;

	// 屏幕的尺寸
	private static int displayWidth;
	private static int displayHeight;

	/**
	 * @param context
	 *            ApplicationContext
	 * @return
	 */
	public static synchronized MyWindowManager getInstance(Context context) {
		if (manager == null) {
			MyWindowManager.context = context;
			winManager = (WindowManager) context
					.getSystemService(Context.WINDOW_SERVICE);
			displayWidth = winManager.getDefaultDisplay().getWidth();
			displayHeight = winManager.getDefaultDisplay().getHeight();

			manager = new MyWindowManager();
		}
		return manager;
	}

	/**
	 * 顯示懸浮框
	 */
	public void show() {
		floatView = getView();
		if (floatView.getParent() == null) {
			winManager.addView(floatView, params);
		}
	}

	/**
	 * 點擊懸浮框後的顯示的實時詳細流量信息
	 */
	public void showContent() {
		winManager.addView(getContentView(), paramsContent);

		// 先移除懸浮框
		winManager.removeView(floatView);
		floatView = null;
	}

	// 移動懸浮框
	public void move(View view, int delatX, int deltaY) {
		if (view == floatView) {
			params.x += delatX;
			params.y += deltaY;
			// 更新floatView
			winManager.updateViewLayout(view, params);
		}
	}

	/**
	 * 移除懸浮框
	 */
	public void dismiss() {
		winManager.removeView(floatContentView);
		floatContentView = null;
	}

	public void back() {
		winManager.addView(getView(), params);

		winManager.removeView(floatContentView);
		floatContentView = null;
	}

	/**
	 * 是否實時更新流量數據,主要用於流量懸浮框是否實時更新流量數據
	 * 
	 * @return
	 */
	public boolean isUpdate() {
		if (floatContentView == null) {
			return false;
		}
		return true;
	}

	/**
	 * 得到懸浮框view
	 * 
	 * @return
	 */
	public FloatView getView() {
		if (floatView == null) {
			floatView = new FloatView(context);
		}
		if (params == null) {
			params = new LayoutParams();
			params.type = LayoutParams.TYPE_PHONE;
			params.format = PixelFormat.RGBA_8888;
			params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
					| LayoutParams.FLAG_NOT_FOCUSABLE;
			params.gravity = Gravity.LEFT | Gravity.TOP;

			// 須指定寬度高度信息
			params.width = floatView.mWidth;
			params.height = floatView.mHeight;

			params.x = displayWidth - floatView.mWidth;
			params.y = displayHeight / 2;
		}
		return floatView;
	}

	/**
	 * 得到實時流量懸浮框view
	 * 
	 * @return
	 */
	public View getContentView() {
		if (floatContentView == null) {
			floatContentView = new FloatContentView(context);
		}
		if (paramsContent == null) {
			paramsContent = new LayoutParams();
			paramsContent.type = LayoutParams.TYPE_PHONE;
			paramsContent.format = PixelFormat.RGBA_8888;
			paramsContent.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
					| LayoutParams.FLAG_NOT_FOCUSABLE;
			paramsContent.gravity = Gravity.LEFT | Gravity.TOP;

			// 須指定寬度高度信息
			paramsContent.width = floatContentView.mWidth;
			paramsContent.height = floatContentView.mHeight;

			paramsContent.x = (displayWidth - floatContentView.mWidth) / 2;
			paramsContent.y = (displayHeight - floatContentView.mHeight) / 2;
		}
		return floatContentView;
	}
}
public class FloatView extends LinearLayout {
	private TextView tvInfo;
	private MyWindowManager manager;

	public int mWidth;
	public int mHeight;

	private int preX;
	private int preY;
	private int x;
	private int y;
	private boolean isMove;

	public FloatView(Context context) {
		this(context, null);
	}

	public FloatView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 填充佈局,並添加至
		LayoutInflater.from(context).inflate(R.layout.float_view, this);
		tvInfo = (TextView) findViewById(R.id.tv_info);

		//寬高
		mWidth = tvInfo.getLayoutParams().width;
		mHeight = tvInfo.getLayoutParams().height;

		manager = MyWindowManager.getInstance(context);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			preX = (int) event.getRawX();
			preY = (int) event.getRawY();
			isMove = false;
			break;
		case MotionEvent.ACTION_MOVE:
			x = (int) event.getRawX();
			y = (int) event.getRawY();
			manager.move(this, x - preX, y - preY);
			isMove = true;
			preX = x;
			preY = y;
			break;
		case MotionEvent.ACTION_UP:
			if (!isMove) {//是否是移動,主要是區分click
				//顯示懸浮框詳細流量信息
				manager.showContent();
			}
			break;
		}
		return super.onTouchEvent(event);
	}
}
public class FloatContentView extends LinearLayout implements OnClickListener {

	public int mWidth;
	public int mHeight;
	private MyWindowManager manager;
	private PackageManager pkgManager;
	private LayoutInflater inflater;
	private TrafficAdapter adapter;

	private Button btCLose;
	private Button btBack;
	private ListView listView;

	public FloatContentView(Context context) {
		this(context, null);
	}

	public FloatContentView(Context context, AttributeSet attrs) {
		super(context, attrs);
		pkgManager = context.getPackageManager();
		// 填充佈局,並添加至
		inflater = LayoutInflater.from(context);

		inflater.inflate(R.layout.float_content_view, this);
		manager = MyWindowManager.getInstance(context);

		ViewGroup.LayoutParams params = findViewById(R.id.content)
				.getLayoutParams();
		mWidth = params.width;
		mHeight = params.height;

		btCLose = (Button) findViewById(R.id.bt_close);
		btBack = (Button) findViewById(R.id.bt_back);
		listView = (ListView) findViewById(R.id.list);

		btCLose.setOnClickListener(this);
		btBack.setOnClickListener(this);

		adapter = new TrafficAdapter();
		listView.setAdapter(adapter);
		//消息,主要完成流量的實時更新
		handler.sendEmptyMessage(0);
	}

	// 主要用於實時更新
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			// 更新流信息
			if (manager.isUpdate()) {
				adapter.notifyDataSetChanged();
				handler.sendEmptyMessageDelayed(0, 2 * 1000);
			}
		}
	};

	@Override
	public void onClick(View v) {
		if (v == btCLose) {
			manager.dismiss();
		} else if (v == btBack) {
			manager.back();
		}
	}

	private class TrafficAdapter extends BaseAdapter {

		private List infos;

		TrafficAdapter() {
			Intent intent = new Intent();
			intent.setAction(Intent.ACTION_MAIN);
			intent.addCategory(Intent.CATEGORY_LAUNCHER);
			//根據意圖,查詢得到與之對應的list信息
			infos = pkgManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
		}

		@Override
		public int getCount() {
			return infos.size();
		}

		@Override
		public Object getItem(int position) {
			return infos.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null) {
				convertView = inflater.inflate(R.layout.item, null);
				convertView.setTag(new ViewHolder(convertView));
			}
			ViewHolder holder = (ViewHolder) convertView.getTag();

			ResolveInfo info = infos.get(position);
			holder.tvPkgName.setText(info.loadLabel(pkgManager).toString());
			try {
				//得到uid
				int uid = pkgManager.getPackageInfo(info.activityInfo.packageName,
						0).applicationInfo.uid;
				//TrafficStats查詢具體流量數據
				holder.tvRcvSize.setText(SizeFormaterUtil.getDataSize(TrafficStats
						.getUidRxBytes(uid)));
				holder.tvSndSize.setText(SizeFormaterUtil.getDataSize(TrafficStats
						.getUidTxBytes(uid)));
			} catch (NameNotFoundException e) {
				e.printStackTrace();
			}
			return convertView;
		}

	}

	private class ViewHolder {
		TextView tvPkgName;
		TextView tvRcvSize;
		TextView tvSndSize;

		public ViewHolder(View view) {
			tvPkgName = (TextView) view.findViewById(R.id.tv_name);
			tvRcvSize = (TextView) view.findViewById(R.id.tv_rcv);
			tvSndSize = (TextView) view.findViewById(R.id.tv_snd);
		}
	}

}

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *