仿UC客戶端的快速搜尋訊息通知效果
仿UC效果:無需許可權提示,實現快速搜尋懸浮窗
一、效果Gif:
效果說明:點選按鈕啟動Service 監聽剪下板。複製之後,在螢幕頂部顯示一個“快速搜尋”懸浮窗來顯示剪貼簿內容。點選懸浮窗後的操作可自定義 / 懸浮窗可自動消失。
二、WindowManager 的使用
通過WindowManager 的使用來構建我們的懸浮窗,設計模式為建造者模式。
/**
* Created by cxm on 2016/8/15.
*/
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationCompat;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
public class UcNotification {
private static final int DISMISS_INTERVAL = 3000;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowParams;
private View mContentView;
private Context mContext;
// 標記懸浮窗是否顯示
private boolean isShowing = false;
// 自定義的監聽介面
private OnClickNotificationListener mOnClickNotificationListener;
private TextView mTvContent;
public UcNotification(Builder builder) {
mContext = builder.getContext();
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowParams = new WindowManager.LayoutParams();
//設定視窗型別
mWindowParams.type = WindowManager.LayoutParams.TYPE_TOAST;// 系統提示window
mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
mWindowParams.width = WindowManager.LayoutParams.MATCH_PARENT;
mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
mWindowParams.alpha = 0.95f;
//設定進入和退出動畫
mWindowParams.windowAnimations = R.style.NotificationAnim;
//設定視窗起點位置
mWindowParams.x = 0;
mWindowParams.y = 0;
setContentView(mContext, builder);
}
private static final int HIDE_WINDOW = 0;
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case HIDE_WINDOW:
dismiss();
break;
}
return true;
}
});
/***
* 設定內容檢視
*
* @param context
*/
private void setContentView(Context context, Builder builder) {
mContentView = LayoutInflater.from(context).inflate(R.layout.layout_notification, null);
mTvContent = (TextView) mContentView.findViewById(R.id.tv_content);
//取出builder中的內容
setOnClickNotificationListener(builder.listener);
setContent(builder.content);
mContentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnClickNotificationListener.onClickThenDismiss(mTvContent.getText().toString());
dismiss();
}
});
}
private void setOnClickNotificationListener(OnClickNotificationListener listener) {
mOnClickNotificationListener = listener;
}
public void show() {
if (!isShowing) {
isShowing = true;
mWindowManager.addView(mContentView, mWindowParams);
autoDismiss();
}
}
public void dismiss() {
if (isShowing) {
resetState();
mWindowManager.removeView(mContentView);
}
}
/**
* 重置狀態
*/
private void resetState() {
isShowing = false;
}
/**
* 自動隱藏通知
*/
private void autoDismiss() {
mHandler.removeMessages(HIDE_WINDOW);
mHandler.sendEmptyMessageDelayed(HIDE_WINDOW, DISMISS_INTERVAL);
}
public void setContent(String content) {
mTvContent.setText(content);
}
@Override
public void onClick(View view) {
Toast.makeText(mContext,"clicked : "+mTvContent.getText().toString(),Toast.LENGTH_SHORT).show();
dismiss();
}
public static class Builder {
private Context context;
private String content = "";
private OnClickNotificationListener listener;
public Context getContext() {
return context;
}
public Builder setContext(Context context) {
this.context = context;
return this;
}
public Builder setOnClickNotificationListener(OnClickNotificationListener listener){
this.listener = listener;
return this;
}
public Builder setContent(String content) {
this.content = content;
return this;
}
public UcNotification build() {
if (null == context)
throw new IllegalArgumentException("The context is Null.");
return new UcNotification(this);
}
}
//懸浮窗點選介面
public interface OnClickNotificationListener {
void onClickThenDismiss(String clipString);
}
}
三、Service 的使用
通過Service的使用來監聽剪貼簿的變化,這裡為了防止onPrimaryClipChanged()的重複多次呼叫,使用了剪貼簿內容字串的比較判斷。
import android.app.Service;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
public class ClipboardService extends Service {
private ClipboardManager clipboardManager;
private String clipString;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
if(clipboardManager==null){
clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
}
if (clipString==null){
clipString = "";
}
clipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
@Override
public void onPrimaryClipChanged() {
CharSequence text = clipboardManager.getPrimaryClip().getItemAt(0).getText();
if(text!=null) {
String s =text.toString();
if (!TextUtils.equals(s, clipString)) {
final UcNotification notification =
new UcNotification.Builder()
.setContext(ClipboardService.this)
.setContent(s)
.setOnClickNotificationListener(new UcNotification.OnClickNotificationListener() {
@Override
public void onClickThenDismiss(String clipString) {
Toast.makeText(ClipboardService.this, "clicked:" + clipString, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(ClipboardService.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ClipboardService.this.startActivity(intent);
}
}).build();
notification.show();
}
clipString = s;
}
}
});
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
完整專案程式碼:
參考:
相關文章
- 4.1.7.2.5 與快速應用程式通知整合的Oracle客戶端Oracle客戶端
- 搜尋引擎ElasticSearch18_ElasticSearch的客戶端操作2Elasticsearch客戶端
- IM撤回訊息-iOS客戶端實現iOS客戶端
- 仿WanAndroid客戶端Flutter版NaNAndroid客戶端Flutter
- SseEmitter 伺服器向客戶端推送訊息MIT伺服器客戶端
- 快速實現客戶查重效果
- im客戶端生成訊息序列號演算法客戶端演算法
- 訊息中介軟體客戶端消費控制實踐客戶端
- 使用Java客戶端傳送訊息和消費的應用Java客戶端
- 搜尋外貿客戶軟體推薦
- Spring Boot 整合 WebSocket 實現服務端推送訊息到客戶端Spring BootWeb服務端客戶端
- 神了!兩個高仿 BiliBili 客戶端!客戶端
- 《ElasticSearch6.x實戰教程》之複雜搜尋、Java客戶端(下)ElasticsearchJava客戶端
- 《ElasticSearch6.x實戰教程》之簡單搜尋、Java客戶端(上)ElasticsearchJava客戶端
- springboot2整合websocket,實現服務端推送訊息到客戶端Spring BootWeb服務端客戶端
- Laravel——訊息通知Laravel
- Laravel 訊息通知Laravel
- 完整仿寫鴻洋WanAndroid網站客戶端NaNAndroid網站客戶端
- 使用Alfred快速搜尋npm包資訊AlfredNPM
- netty建立數萬客戶端連線,並主動發訊息Netty客戶端
- Spring Boot+Socket實現與html頁面的長連線,客戶端給伺服器端發訊息,伺服器給客戶端輪詢傳送訊息,附案例原始碼Spring BootHTML客戶端伺服器原始碼
- 騰訊 客戶端開發 QT客戶端QT
- React 伺服器端渲染和客戶端渲染效果對比React伺服器客戶端
- 如何實現從 Redis 中訂閱訊息轉發到 WebSocket 客戶端RedisWeb客戶端
- 使用swoole作為MQTT客戶端並接收實現即時訊息推送MQQT客戶端
- [譯]如何在Service Worker和網頁客戶端之間傳送訊息網頁客戶端
- 實現客戶端與服務端的HTTP通訊客戶端服務端HTTP
- 為什麼從伺服器與客戶端不能接收訊息NetMQ框架?伺服器客戶端MQ框架
- 基於WebSocket的modbus通訊(二)- 客戶端Web客戶端
- Flutter 仿寫的掘金客戶端Flutter客戶端
- 關於客戶端資訊流思考客戶端
- 看視訊必備:YouTube客戶端客戶端
- electron+vue 仿微信客戶端聊天|electron 仿微信介面|electron 聊天例項Vue客戶端
- JavaScript 搜尋關鍵字高亮效果JavaScript
- 訊息通知系統記錄
- 鴻蒙傳送訊息通知鴻蒙
- redis學習(七) 訊息通知Redis
- Python socket的客戶端Python客戶端
- 4.2.14 啟用客戶端快速連線故障轉移客戶端