px,dp,sp单位转换工具类

时间:2023-03-10 06:31:09
px,dp,sp单位转换工具类

1.官方文档

1.1 通知相关全部、详细文档

  https://developer.android.com/guide/topics/ui/notifiers/notifications

1.2 通知官方示例

  https://github.com/googlesamples/android-Notifications

  https://github.com/googlesamples/android-NotificationChannels

1.3 自定义通知文档

  https://developer.android.com/training/notify-user/custom-notification

    1. NotificationCompat.BigPictureStyle,
    2. NotificationCompat.BigTextStyle
    3. NotificationCompat.InboxStyle ,
    4. NotificationCompat.MessagingStyle,
    5. NotificationCompat.MediaStyle  音乐播放.
  • setStyle(new NotificationCompat.DecoratedCustomViewStyle()) 使用自定义样式.
  • 何时用@style/TextAppearance.Compat.Notification.Title
  • avoid setting a background image on your RemoteViews object, because your text color may become unreadable.
  • 完全自定义时: use setCustomBigContentView(), but do not call setStyle().
  • setContent() 兼容4.1及以下.

1.4 通过通知栏启动activity的方式

  https://developer.android.com/training/notify-user/navigation  

  • 启动常规Activity(含任务栈,保留原来顺序),使用TaskStackBuilder
  • 启动特殊Activity ,intent设置 FLAG_ACTIVITY_NEW_TASK

1.5 通知组

  https://developer.android.com/training/notify-user/group

  • Note: Notification groups are not the same as notification channel groups.
  • Note: If your app sends four or more notifications and does not specify a group, the system automatically groups them together on Android 7.0 and higher.
  • 关键api : setGroup()  setGroupSummary(true)

1.6 渠道管理

  https://developer.android.com/training/notify-user/channels

  • 8.0通过渠道设置通知优先级
  • 如何打开通知设置页面. Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); 等等...
  • 删除渠道.
  • 创建渠道组及何时有必要使用渠道组.

1.7 应用图标的通知角标

  https://developer.android.com/training/notify-user/badges

  • 8.0开始的新特性.
  • 通过渠道参数设置开启这个功能
  • setNumber() 设置通知角标数.

2.自定义通知示例

样式大致这样

px,dp,sp单位转换工具类

2.1 自定义通知布局

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="64dp"> <ImageView
android:id="@+id/notify_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
app:srcCompat="@mipmap/notify_icon" /> <TextView
android:id="@+id/notify_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxEms="9"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="#333333"
android:layout_toRightOf="@+id/notify_icon"
android:layout_alignTop="@+id/notify_icon"
android:layout_alignBottom="@+id/notify_icon"
android:textSize="10sp" /> <TextView
android:id="@+id/notify_progress_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/notify_icon"
android:layout_alignLeft="@+id/notify_icon"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:gravity="left|center_vertical"
android:maxEms="9"
android:maxLines="1"
android:text="title"
android:layout_toLeftOf="@+id/notify_progress_status"
android:textAllCaps="false"
android:textColor="#333333"
android:textSize="12sp"
android:textStyle="bold" /> <ProgressBar
android:id="@+id/notify_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:layout_below="@+id/notify_progress_title"
android:layout_alignLeft="@+id/notify_progress_title"
android:layout_alignRight="@+id/notify_progress_status"
android:layout_marginTop="4dp"
android:progressDrawable="@drawable/notify_progress_bar" /> <TextView
android:id="@+id/notify_progress_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="25dp"
android:layout_alignBottom="@+id/notify_progress_title"
android:layout_alignTop="@+id/notify_progress_title"
android:layout_toLeftOf="@+id/notify_down_btn"
android:maxLines="1"
android:maxEms="9"
android:ellipsize="end"
android:textAllCaps="false"
android:textColor="#999999"
android:textSize="10sp"
android:gravity="center"
android:text="status" /> <ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:id="@+id/notify_down_btn"
android:background="@null"
android:layout_alignTop="@+id/notify_close_btn"
android:layout_marginRight="20dp"
android:layout_toLeftOf="@+id/notify_close_btn"
android:src="@mipmap/notify_start"
/> <ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:id="@+id/notify_close_btn"
android:layout_marginRight="15dp"
android:layout_alignTop="@+id/notify_progress_title"
android:src="@mipmap/notify_close"
android:background="@null"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="40dp"
android:layout_height="match_parent"
android:id="@+id/notify_close"
android:background="@color/hot_color"
android:layout_alignBottom="@+id/notify_progress"
android:layout_alignParentRight="true"
android:visibility="visible"
/>
<LinearLayout
android:id="@+id/notify_down"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_alignBottom="@+id/notify_close"
android:layout_toLeftOf="@+id/notify_close"
android:background="@color/hot_color"
android:src="@mipmap/notify_start"
android:orientation="vertical"
android:visibility="visible" /> </RelativeLayout>

注意事项:

  • 参考官方文档,考虑不同屏幕大小,通知栏的高度限制为:收起时为64dp,展开时为256dp
  • notify根布局目前(sdk api 28)还不能用约束布局。
  • 布局内不能出现 <View ....>
  • ImageView不要使用 app:srcCompat,用 android:src

2.2 初始化

     NotificationManagerCompat   mNotificationManager;
RemoteViews notifyView;
NotificationCompat.Builder builder; private void initNotify() {
//1.得到 NotificationManagerCompat mNotificationManager = NotificationManagerCompat.from(getApplicationContext());
//2.构造Notify上的View
notifyView = new RemoteViews(getPackageName(), R.layout.notify); //自定义notify上按钮的事件
Intent downIntent = new Intent(getApplicationContext(), NotifyReceiver.class);
downIntent.setAction(NotifyReceiver.DOWN_ACTION);
//用广播接收按钮事件,也可以用服务组件或者activity PendingIntent有一系列函数可选。
PendingIntent down = PendingIntent.getBroadcast(getApplicationContext(), , downIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notifyView.setOnClickPendingIntent(R.id.notify_down, down); Intent closeIntent = new Intent(getApplicationContext(), NotifyReceiver.class);
closeIntent.setAction(NotifyReceiver.CLOSE_ACTION); PendingIntent close = PendingIntent.getBroadcast(getApplicationContext(), , closeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notifyView.setOnClickPendingIntent(R.id.notify_close, close); //3.构造Notify,设置通知的参数
String channelId = getString(R.string.notify_id);//在 strings.xml中定义
builder = new NotificationCompat.Builder(getApplicationContext(),channelId); //点击整个通知栏时,响应通知的应用组件。
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent notifyIntent = PendingIntent.getActivity(getApplicationContext(), , intent, PendingIntent.FLAG_UPDATE_CURRENT); //设置通知栏参数
builder.setWhen(System.currentTimeMillis())
.setPriority(NotificationCompat.PRIORITY_MAX) //优先级.
.setAutoCancel(true)
.setOngoing(false)
.setContentIntent(notifyIntent)
.setCustomContentView(notifyView) //完全自定义,不调用.setStyle()
.setContent(notifyView) //兼容4.1及以下
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
.setOnlyAlertOnce(true)
.setSmallIcon(R.mipmap.notify_logo);
}
  • 初始notify上自定义的view,重点在按钮事件
  • 如果在一定时间内通知的频繁,系统会忽略其中的一部分.
  • OnlyAlterOnce保证频频调用时,声音等警示事件只1次.
  • RemoteViews和NotificationCompat.Builder 保存成成员变量是因为notify的频次高,不用每次都构造.

2.3 发出通知

     public synchronized void showDownloadingNotify() {
//4.根据业务逻辑控制notify上控件的状态
//...这里略
int icon = downloading ? R.mipmap.notify_pause : R.mipmap.notify_start; int pro = (int) (downloaded * 100.00F / total);
Log.e(TAG, "showDownloadingNotify: downloading progress = " + pro); notifyView.setTextViewText(R.id.notify_progress_title, title);
notifyView.setTextViewText(R.id.notify_progress_status,getString(R.string.downloading_downloaded) + " " + pro + "%" );
notifyView.setImageViewResource(R.id.notify_down_btn, icon);
notifyView.setProgressBar(R.id.notify_progress,, pro,false); Notification notify = builder.build(); //5.发出通知
String channelId = getString(R.string.notify_id);//在 strings.xml中定义
mNotificationManager.notify(Integer.valueOf(channelId), notify);
}

  注意控制发出通知的频率,不要太快,如:

         if(last < ){
last = SystemClock.elapsedRealtime() / ;
}
long now = SystemClock.elapsedRealtime() / ;
if (now - last > ){
last = now;
showDownloadingNotify();
}

2.4 接收通知按钮事件的组件

本示例中使用的是广播,也可以用服务和activity

 public class NotifyReceiver extends BroadcastReceiver {
public final static String DOWN_ACTION = "com.cnblogs.sjjg.notifications.intent.action.DownClick";
public final static String CLOSE_ACTION = "com.cnblogs.sjjg.notifications.intent.action.CloseClick"; @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.e("NotifyReceiver", "onReceive: action = " + action);
switch (action) {
case DOWN_ACTION:
//处理第1个按钮事件,开始下载
break;
case CLOSE_ACTION:
//处理第2个按钮事件,关闭通知
break;
default:
break;
}
}
}

在AndroidManifest.xml中注册

      ...
<receiver
android:name=".main.NotifyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.cnblogs.sjjg.notifications.intent.action.DownClick" />
<action android:name="com.cnblogs.sjjg.notifications.intent.action.CloseClick" />
</intent-filter>
</receiver>
...

2.5 取消通知

  取消的id要与发出的id相同。

     public void cancelNotify(){
String channelId = getString(R.string.notify_id);
mNotificationManager.cancel(Integer.valueOf(channelId));
}

3.android 8.0适配

3.1 变化

  • 必须将各个通知放入特定渠道中,否则不显示.一个应用可以有多个渠道.
  • 用户可以按渠道关闭通知,而非关闭来自某个应用的所有通知。
  • 包含有效通知的应用将在主屏幕/启动器屏幕上相应应用图标的上方显示通知“标志”。
  • 用户可以从抽屉式通知栏中暂停某个通知。可以为通知设置自动超时时间。
  • 可以设置通知的背景颜色。
  • 部分与通知行为相关的 API 从 Notification 移至了 NotificationChannel。例如,在搭载 Android 8.0 及更高版本的设备中,使用 NotificationChannel.setImportance(),而非 NotificationCompat.Builder.setPriority()

3.2 创建通知渠道

选择适当时机,创建渠道.

    @RequiresApi(api = Build.VERSION_CODES.O)
private void createNotifyChannel(){
NotificationManager nm = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = getString(R.string.notify_id);
NotificationChannel channel = nm.getNotificationChannel(channelId);
if (channel == null){
channel = new NotificationChannel(channelId, "Downloader", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.setImportance(NotificationManager.IMPORTANCE_DEFAULT);
channel.setShowBadge(true);
nm.createNotificationChannel(channel);
}
}

3.3 检测通知权限是否打开

        NotificationManagerCompat mNotificationManager;
mNotificationManager = NotificationManagerCompat.from(getContext());
boolean enable = mNotificationManager.areNotificationsEnabled();
if (!enable){
//打开通知权限
...
}

3.4 打开通知权限

         final int NOTIFY_PER = ;
Intent intent = new Intent();
Context context = getContext();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName());
}else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH){
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra("app_package", context.getPackageName());
intent.putExtra("app_uid", context.getApplicationInfo().uid);
}else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT){
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + context.getPackageName()));
}else{
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
}
startActivityForResult(intent, NOTIFY_PER);

3.5 接收打开结果

     @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
final int NOTIFY_PER = ;
if (requestCode == NOTIFY_PER){
NotificationManagerCompat notifyMgr = NotificationManagerCompat.from(getContext());
boolean enable = notifyMgr.areNotificationsEnabled();
Log.e("MainPresenter", "onActivityResult: request notify = " + enable );
if (!enable){
Snackbar.make(more,"通知功能没有打开,无法在通知栏上显示进度!",Snackbar.LENGTH_SHORT).show();
}
}
}

4.系统自带通知栏

      fun showNotify(warning: Warning){
var mgr = NotificationManagerCompat.from(applicationContext)
var notifyId = getString(R.string.notify_id) var content = warning.oldie.name + " " + warning.getTypeString()
var builder = NotificationCompat.Builder(applicationContext,notifyId)
var intent = Intent(applicationContext, MainActivity::class.java)
var pendingIntent = PendingIntent.getActivity(this, , intent, );
builder.setContentIntent(pendingIntent);
builder.setWhen(System.currentTimeMillis())
.setPriority(NotificationCompat.PRIORITY_MAX) //优先级.
.setAutoCancel(true)
.setOngoing(false) //常驻通知栏
.setContentText(content)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.warning))
.setContentTitle("监护警报")
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
.setOnlyAlertOnce(true)
.setSmallIcon(R.mipmap.icon)
var notify = builder.build()
mgr.notify(notifyId.toInt(),notify)
}
fun cancelNotify(){
var mgr = NotificationManagerCompat.from(applicationContext) val channelId = getString(R.string.notify_id) mgr.cancel(channelId.toInt())
}