Android獲取剪下板內容(仿有道複製查詞功能)
阿新 • • 發佈:2019-02-09
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) { } }); } }