Android剪切板(ClipBoardManager)复制的内容,可以粘贴到任何地方,对于一些词典,翻译工具等app具有较高的使用价值。有道词典在3.6版本后就使用到该功能,本文来剖析具体的实现过程。
首先看一下有道词典的效果图:
SDK使用说明,API 11以上请导入包:android.content.ClipboardManager。
具体实现流程如下:
a.开启后台监听服务。
在服务创建的过程中,启动剪切板,设置内容监听器。
- final ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- cm.addPrimaryClipChangedListener(new OnPrimaryClipChangedListener() {
- @Override
- public void onPrimaryClipChanged() {
- ClipData data = cm.getPrimaryClip();
- Item item = data.getItemAt(0);
- Intent mIntent = new Intent();
- mIntent.setAction("com.cybertron.dict.ClipBoardReceiver");
- mIntent.putExtra("clipboardvalue", item.getText().toString());
- sendBroadcast(mIntent);
- }
- });
这里要注意的是API11后,1.获取剪切板内容的操作均在ClipData中;2.这里的监听接口OnPrimaryClipChangedListener,是添加而不是设置。当剪切板内容发生改变时,回调执行onPrimaryClipChanged方法,如果设备有多个这样的监听的话,该方法会执行多次,但影响不大。
b.获取剪切板内容,启动浮动窗口。
剪切板内容发生改变后,可以通过发送广播或服务的方式进行数据传输。本文通过的是前者的方式,广播接收器接收到传值后再启动浮动窗口的服务。
浮动窗口接收传值并显示,并可以拖动。具体实现参考:
- public class FloatingWindowService extends Service{
- public static final String OPERATION = "operation";
- public static final int OPERATION_SHOW = 100;
- public static final int OPERATION_HIDE = 101;
- private boolean isAdded = false; // 是否已增加悬浮窗
- private static WindowManager wm;
- private static WindowManager.LayoutParams params;
- private View floatView;
- private float startX = 0;
- private float startY = 0;
- private float x;
- private float y;
- private String copyValue;
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- createFloatView();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
- @Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
- if (intent != null) {
- int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
- switch (operation) {
- case OPERATION_SHOW:
- if (!isAdded) {
- wm.addView(floatView, params);
- isAdded = true;
- }
- break;
- case OPERATION_HIDE:
- if (isAdded) {
- wm.removeView(floatView);
- isAdded = false;
- }
- break;
- }
- copyValue = intent.getStringExtra("copyValue");
- setupCellView(floatView);
- Log.e(this.getClass().getSimpleName(), "=====copyValue :"+copyValue);
- }
- }
- /**
- * 创建悬浮窗
- */
- private void createFloatView() {
- LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- floatView = layoutInflater.inflate(R.layout.dict_popup_window, null);
- wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
- params = new WindowManager.LayoutParams();
- // 设置window type
- params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
- /*
- * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE; 那么优先级会降低一些,
- * 即拉下通知栏不可见
- */
- params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
- // 设置Window flag
- params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- /*
- * 下面的flags属性的效果形同“锁定”。 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
- * wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL |
- * LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE;
- */
- // 设置悬浮窗的长得宽
- params.width = getResources().getDimensionPixelSize(R.dimen.float_width);
- params.height = WindowManager.LayoutParams.WRAP_CONTENT;
- params.gravity = Gravity.LEFT | Gravity.TOP;
- params.x = 0;
- params.y = 0;
- // 设置悬浮窗的Touch监听
- floatView.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- x = event.getRawX();
- y = event.getRawY();
- switch(event.getAction()){
- case MotionEvent.ACTION_DOWN:
- startX = event.getX();
- startY = event.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- params.x = (int)( x - startX);
- params.y = (int) (y - startY);
- wm.updateViewLayout(floatView, params);
- break;
- case MotionEvent.ACTION_UP:
- startX = startY = 0;
- break;
- }
- return true;
- }
- });
- wm.addView(floatView, params);
- isAdded = true;
- }
- /**
- * 设置浮窗view内部子控件
- * @param rootview
- */
- private void setupCellView(View rootview) {
- ImageView closedImg = (ImageView) rootview.findViewById(R.id.float_window_closed);
- TextView titleText = (TextView) rootview.findViewById(R.id.float_window_title);
- titleText.setText(copyValue);
- closedImg.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (isAdded) {
- wm.removeView(floatView);
- isAdded = false;
- }
- }
- });
- floatView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- }
- });
- }
- }