仿UC客戶端的快速搜尋訊息通知效果

cxmscb發表於2016-08-16

仿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();
    }
}

完整專案程式碼:

UcTopNofitication

參考:

http://www.jianshu.com/p/634cd056b90c

相關文章