Notification的幾種基本使用方法,大家肯定都已經爛熟於心,我也不必多說.給一個鏈接:https://zhuanlan.zhihu.com/p/25841482 接下來我想說的是android5.0 後的彈出通知, 網上的方法是: 但上面的做法並不能在android5.0以下的設備上使通知彈 ...
Notification的幾種基本使用方法,大家肯定都已經爛熟於心,我也不必多說.給一個鏈接:https://zhuanlan.zhihu.com/p/25841482
接下來我想說的是android5.0 後的彈出通知,
網上的方法是:
//第一步:實例化通知欄構造器Notification.Builder:
Notification.Builder builder =new Notification.Builder(MainActivity.this);//實例化通知欄構造器Notification.Builder,參數必填(Context類型),為創建實例的上下文 //第二步:獲取狀態通知欄管理: NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);//獲取狀態欄通知的管理類(負責發通知、清除通知等操作) //第三步:設置通知欄PendingIntent(點擊動作事件等都包含在這裡): Intent push =new Intent(MainActivity.this,MainActivity.class);//新建一個顯式意圖,第一個參數 Context 的解釋是用於獲得 package name,以便找到第二個參數 Class 的位置 //PendingIntent可以看做是對Intent的包裝,通過名稱可以看出PendingIntent用於處理即將發生的意圖,而Intent用來用來處理馬上發生的意圖 //本程式用來響應點擊通知的打開應用,第二個參數非常重要,點擊notification 進入到activity, 使用到pendingIntent類方法,PengdingIntent.getActivity()的第二個參數,即請求參數,實際上是通過該參數來區別不同的Intent的,如果id相同,就會覆蓋掉之前的Intent了 PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.this,0,push,0); //第四步:對Builder進行配置: builder .setContentTitle("My notification")//標題 .setContentText("Hello World!")// 詳細內容 .setContentIntent(contentIntent)//設置點擊意圖 .setTicker("New message")//第一次推送,角標旁邊顯示的內容 .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher))//設置大圖標 .setDefaults(Notification.DEFAULT_ALL);//打開呼吸燈,聲音,震動,觸發系統預設行為 /*Notification.DEFAULT_VIBRATE //添加預設震動提醒 需要VIBRATE permission Notification.DEFAULT_SOUND //添加預設聲音提醒 Notification.DEFAULT_LIGHTS//添加預設三色燈提醒 Notification.DEFAULT_ALL//添加預設以上3種全部提醒*/ //.setLights(Color.YELLOW, 300, 0)//單獨設置呼吸燈,一般三種顏色:紅,綠,藍,經測試,小米支持黃色 //.setSound(url)//單獨設置聲音 //.setVibrate(new long[] { 100, 250, 100, 250, 100, 250 })//單獨設置震動 //比較手機sdk版本與Android 5.0 Lollipop的sdk if(android.os.Build.VERSION.SDK_INT>= android.os.Build.VERSION_CODES.LOLLIPOP) { builder /*android5.0加入了一種新的模式Notification的顯示等級,共有三種: VISIBILITY_PUBLIC只有在沒有鎖屏時會顯示通知 VISIBILITY_PRIVATE任何情況都會顯示通知 VISIBILITY_SECRET在安全鎖和沒有鎖屏的情況下顯示通知*/ .setVisibility(Notification.VISIBILITY_PUBLIC) .setPriority(Notification.PRIORITY_DEFAULT)//設置該通知優先順序 .setCategory(Notification.CATEGORY_MESSAGE)//設置通知類別 //.setColor(context.getResources().getColor(R.color.small_icon_bg_color))//設置smallIcon的背景色 .setFullScreenIntent(contentIntent, true)//將Notification變為懸掛式Notification .setSmallIcon(R.drawable.ic_launcher);//設置小圖標 } else{ builder .setSmallIcon(R.drawable.ic_launcher);//設置小圖標 } //第五步:發送通知請求: Notification notify = builder.build();//得到一個Notification對象 mNotifyMgr.notify(1,notify);//發送通知請求 }
但上面的做法並不能在android5.0以下的設備上使通知彈出,因此下麵的做法是自己重寫Notification(網上查找的一些資料,來源忘記了,不好意思)
如果需要使通知自動顯示,那麼就需要我們在接收到通知後重新定義通知的界面,並使其載入顯示在Window界面上,這點需要讀者瞭解Window的載入機制.
其實簡單點來說,就是通過windowManager的僅有的三個方法(載入,更新,刪除)來實現的.如果有大神熟悉這方面的知識可以分享分享.
自定義Notification的思路:
1.繼承重寫NotificationCompat,Builder來實現類似的Notification
2.自定義通知界面
3.自定義NotificationManager,發送顯示通知
廢話不多說,先上主要代碼:
1 public class HeadsUp { 2 3 private Context context; 4 /** 5 * 出現時間 單位是 second 6 */ 7 private long duration= 3; 8 /** 9 * 10 */ 11 private Notification notification; 12 13 private Builder builder; 14 15 private boolean isSticky=false; 16 17 18 private boolean activateStatusBar=true; 19 20 private Notification silencerNotification; 21 /** 22 * 間隔時間 23 */ 24 private int code; 25 private CharSequence titleStr; 26 private CharSequence msgStr; 27 private int icon; 28 private View customView; 29 private boolean isExpand; 30 private HeadsUp(Context context) { 31 this.context=context; 32 } 33 public static class Builder extends NotificationCompat.Builder { 34 private HeadsUp headsUp; 35 public Builder(Context context) { 36 super(context); 37 headsUp=new HeadsUp(context); 38 } 39 public Builder setContentTitle(CharSequence title) { 40 headsUp.setTitle(title); 41 super.setContentTitle(title); //狀態欄顯示內容 42 return this; 43 } 44 public Builder setContentText(CharSequence text) { 45 headsUp.setMessage(text); 46 super.setContentText(text); 47 return this; 48 } 49 public Builder setSmallIcon(int icon) { 50 headsUp.setIcon(icon); 51 super.setSmallIcon(icon); 52 return this; 53 } 54 public HeadsUp buildHeadUp(){ 55 headsUp.setNotification(this.build()); 56 headsUp.setBuilder(this); 57 return headsUp; 58 } 59 public Builder setSticky(boolean isSticky){ 60 headsUp.setSticky(isSticky); 61 return this; 62 } 63 } 64 65 public Context getContext() { 66 return context; 67 } 68 69 public long getDuration() { 70 return duration; 71 } 72 73 public Notification getNotification() { 74 return notification; 75 } 76 77 protected void setNotification(Notification notification) { 78 this.notification = notification; 79 } 80 81 public View getCustomView() { 82 return customView; 83 } 84 85 public void setCustomView(View customView) { 86 this.customView = customView; 87 } 88 89 public int getCode() { 90 return code; 91 } 92 93 protected void setCode(int code) { 94 this.code = code; 95 } 96 97 protected Builder getBuilder() { 98 return builder; 99 } 100 101 private void setBuilder(Builder builder) { 102 this.builder = builder; 103 } 104 105 106 public boolean isSticky() { 107 return isSticky; 108 } 109 110 public void setSticky(boolean isSticky) { 111 this.isSticky = isSticky; 112 } 113 114 }View Code
1 public class HeadsUpManager { 2 3 private WindowManager wmOne; 4 private FloatView floatView; 5 private Queue<HeadsUp> msgQueue; 6 private static HeadsUpManager manager; 7 private Context context; 8 9 private boolean isPolling = false; 10 11 private Map<Integer, HeadsUp> map; 12 private NotificationManager notificationManager=null; 13 14 public static HeadsUpManager getInstant(Context c) { 15 16 if (manager == null) { 17 manager = new HeadsUpManager(c); 18 19 } 20 return manager; 21 22 } 23 24 private HeadsUpManager(Context context) { 25 this.context = context; 26 map = new HashMap<Integer, HeadsUp>(); 27 msgQueue = new LinkedList<HeadsUp>(); 28 wmOne = (WindowManager) context 29 .getSystemService(Context.WINDOW_SERVICE); 30 31 notificationManager= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 32 } 33 34 public void notify(HeadsUp headsUp) { 35 36 37 if (map.containsKey(headsUp.getCode())) { 38 msgQueue.remove(map.get(headsUp.getCode())); 39 } 40 map.put(headsUp.getCode(), headsUp); 41 msgQueue.add(headsUp); 42 43 if (!isPolling) { 44 poll(); 45 } 46 } 47 public synchronized void notify(int code,HeadsUp headsUp) { 48 headsUp.setCode(code); 49 notify(headsUp); 50 51 } 52 public synchronized void cancel(HeadsUp headsUp) { 53 cancel(headsUp.getCode()); 54 } 55 56 57 private synchronized void poll() { 58 if (!msgQueue.isEmpty()) { 59 HeadsUp headsUp = msgQueue.poll(); 60 map.remove(headsUp.getCode()); 61 62 // if ( Build.VERSION.SDK_INT < 21 || headsUp.getCustomView() != null ){ 63 isPolling = true; 64 show(headsUp); 65 System.out.println("自定義notification"); 66 // }else { 67 // //當 系統是 lollipop 以上,並且沒有自定義佈局以後,調用系統自己的 notification 68 // isPolling = false; 69 // notificationManager.notify(headsUp.getCode(),headsUp.getBuilder().setSmallIcon(headsUp.getIcon()).build()); 70 // System.out.println("調用系統notification"); 71 // } 72 73 } else { 74 isPolling = false; 75 } 76 } 77 private void show(HeadsUp headsUp) { 78 floatView = new FloatView(context, 20); 79 WindowManager.LayoutParams params = FloatView.winParams; 80 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 81 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 82 |WindowManager.LayoutParams.FLAG_FULLSCREEN 83 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 84 params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 85 params.width = WindowManager.LayoutParams.MATCH_PARENT; 86 params.height = WindowManager.LayoutParams.WRAP_CONTENT; 87 params.format = -3; 88 params.gravity = Gravity.CENTER | Gravity.TOP; 89 params.x = floatView.originalLeft; 90 params.y = 10; 91 params.alpha = 1f; 92 wmOne.addView(floatView, params); 93 ObjectAnimator a = ObjectAnimator.ofFloat(floatView.rootView, "translationY", -700, 0); 94 a.setDuration(600); 95 a.start(); 96 floatView.setNotification(headsUp); 97 if(headsUp.getNotification()!=null){ 98 notificationManager.notify(headsUp.getCode(), headsUp.getNotification()); 99 } 100 } 101 102 public void cancel(){ 103 104 if(floatView !=null && floatView.getParent()!=null) { 105 106 floatView.cancel(); 107 } 108 } 109 110 protected void dismiss() { 111 if (floatView.getParent()!=null) { 112 wmOne.removeView(floatView); 113 floatView.postDelayed(new Runnable() { 114 @Override 115 public void run() { 116 poll(); 117 } 118 }, 200); 119 } 120 121 } 122 123 protected void animDismiss(){ 124 if(floatView !=null && floatView.getParent()!=null){ 125 126 ObjectAnimator a = ObjectAnimator.ofFloat(floatView.rootView, "translationY", 0, -700); 127 a.setDuration(700); 128 a.start(); 129 130 a.addListener(new Animator.AnimatorListener() { 131 @Override 132 public void onAnimationStart(Animator animator) { 133 134 } 135 @Override 136 public void onAnimationEnd(Animator animator) { 137 138 dismiss(); 139 } 140 @Override 141 public void onAnimationCancel(Animator animator) { 142 } 143 @Override 144 public void onAnimationRepeat(Animator animator) { 145 146 } 147 }); 148 } 149 150 } 151 152 protected void animDismiss(HeadsUp headsUp){ 153 if(floatView.getHeadsUp().getCode()==headsUp.getCode()){ 154 animDismiss(); 155 } 156 157 } 158 public void cancel(int code) { 159 if (map.containsKey(code)) { 160 msgQueue.remove(map.get(code)); 161 } 162 if(floatView!=null && floatView.getHeadsUp().getCode()==code){ 163 animDismiss(); 164 } 165 166 } 167 public void close() { 168 cancelAll(); 169 manager = null; 170 } 171 public void cancelAll() { 172 msgQueue.clear(); 173 if (floatView!=null && floatView.getParent()!=null) { 174 animDismiss(); 175 } 176 } 177 }View Code
1 public class FloatView extends LinearLayout { 2 private float rawX = 0; 3 private float rawY=0; 4 private float touchX = 0; 5 private float startY = 0; 6 public LinearLayout rootView; 7 public int originalLeft; 8 public int viewWidth; 9 private float validWidth; 10 private VelocityTracker velocityTracker; 11 private int maxVelocity; 12 private Distance distance; 13 14 private ScrollOrientationEnum scrollOrientationEnum=ScrollOrientationEnum.NONE; 15 16 public static WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(); 17 18 public FloatView(final Context context, int i) { 19 super(context); 20 LinearLayout view = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.notification_bg, null); 21 maxVelocity= ViewConfiguration.get(context).getScaledMaximumFlingVelocity(); 22 rootView = (LinearLayout) view.findViewById(R.id.rootView); 23 addView(view); 24 viewWidth = context.getResources().getDisplayMetrics().widthPixels; 25 validWidth=viewWidth/2.0f; 26 originalLeft = 0; 27 28 } 29 30 public void setCustomView(View view) { 31 rootView.addView(view); 32 } 33 34 35 @Override 36 protected void onFinishInflate() { 37 super.onFinishInflate(); 38 } 39 40 41 private HeadsUp headsUp; 42 private long cutDown; 43 private Handler mHandle=null; 44 private CutDownTime cutDownTime; 45 private class CutDownTime extends Thread{ 46 47 @Override 48 public void run() { 49 super.run(); 50 51 52 while (cutDown>0){ 53 try { 54 Thread.sleep(1000); 55 cutDown--; 56 } catch (InterruptedException e) { 57 e.printStackTrace(); 58 } 59 } 60 61 if(cutDown==0) { 62 mHandle.sendEmptyMessage(0); 63 } 64 65 66 } 67 }; 68 69 70 71 public HeadsUp getHeadsUp() { 72 return headsUp; 73 } 74 75 private int pointerId; 76 public boolean onTouchEvent(MotionEvent event) { 77 rawX = event.getRawX(); 78 rawY=event.getRawY(); 79 acquireVelocityTracker(event); 80 cutDown= headsUp.getDuration(); 81 switch (event.getAction()) { 82 case MotionEvent.ACTION_DOWN: 83 touchX = event.getX(); 84 startY = event.getRawY(); 85 pointerId=event.getPointerId(0); 86 break; 87 case MotionEvent.ACTION_MOVE: 88 switch (scrollOrientationEnum){ 89 case NONE: 90 if(Math.abs((rawX - touchX))>20) { 91 scrollOrientationEnum=ScrollOrientationEnum.HORIZONTAL; 92 93 }else if(startY-rawY>20){ 94 scrollOrientationEnum=ScrollOrientationEnum.VERTICAL; 95 96 } 97 98 break; 99 case HORIZONTAL: 100 updatePosition((int) (rawX - touchX)); 101 break; 102 case VERTICAL: 103 if(startY-rawY>20) { 104 cancel(); 105 } 106 break; 107 } 108 109 break; 110 case MotionEvent.ACTION_UP: 111 velocityTracker.computeCurrentVelocity(1000,maxVelocity); 112 int dis= (int) velocityTracker.getYVelocity(pointerId); 113 if(scrollOrientationEnum==ScrollOrientationEnum.NONE){ 114 if(headsUp.getNotification().contentIntent!=null){ 115 116 try { 117 headsUp.getNotification().contentIntent.send(); 118 cancel(); 119 } catch (PendingIntent.CanceledException e) { 120 e.printStackTrace(); 121 } 122 } 123 break; 124 } 125 126 127 int toX; 128 if(preLeft>0){ 129 toX= (int) (preLeft+Math.abs(dis)); 130 }else{ 131 toX= (int) (preLeft-Math.abs(dis)); 132 } 133 if (toX <= -validWidth) { 134 float preAlpha=1-Math.abs(preLeft)/validWidth; 135 preAlpha=preAlpha>=0?preAlpha:0; 136 translationX(preLeft,-(validWidth+10),preAlpha,0); 137 } else if (toX <= validWidth) { 138 float preAlpha=1-Math.abs(preLeft)/validWidth; 139 preAlpha=preAlpha>=0?preAlpha:0; 140 translationX(preLeft,0,preAlpha,1); 141 142 }else{ 143 float preAlpha=1-Math.abs(preLeft)/validWidth; 144 preAlpha=preAlpha>=0?preAlpha:0; 145 translationX(preLeft, validWidth + 10, preAlpha, 0); 146 } 147 preLeft = 0; 148 scrollOrientationEnum=ScrollOrientationEnum.NONE; 149 break; 150 } 151 152 return super.onTouchEvent(event); 153 154 } 155 /** 156 * 157 * @param event 向VelocityTracker添加MotionEvent