支持原创,欢迎转载:http://blog.csdn.net/sonken_0824/article/details/32111257
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) {
}
});
}
}
文章结尾Demo下载地址提供!