如何在 android 系统状态栏中显示文本
How do I show text in android system status bar
我正在尝试为 Android 牛轧糖开发一个应用程序,我想在 android 服务例程生成的状态栏中显示一些 info/text。所以我的问题是,我不知道如何在状态栏中显示文本。
我添加了一张示例图片来说明我的意思(红色圆圈)。
我知道这是可能的,因为我在 Play 商店的电池监视器应用程序中看到了它。
我已经试过了NotificationCombat.Builder,但我认为这不是正确的方法。也许是叠加层,但搜索后我没有找到任何东西。
有人可以告诉我怎么做或给我提示吗?
编辑:这是我的 NotificationCompat.Builder
测试代码
MainActivity.java
import android.app.Notification;
import android.app.NotificationManager;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
public class MainActivity extends AppCompatActivity
{
private final int NOTIFICATION_ID = 10;
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Value");
mBuilder.setContentText("123");
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
mBuilder.setOngoing(true);
mBuilder.setAutoCancel(false);
//Intent resultIntent = new Intent(this, MainActivity.class);
//PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//mBuilder.setContentIntent(resultPendingIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(NOTIFICATION_ID, notification);
}
}
activity_main.xml
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000000"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:weightSum="100" >
<TextView
android:id="@+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
结果:
您可以在此处的文档中找到答案:https://developer.android.com/reference/android/support/v4/app/NotificationCompat.html
编辑::
好吧,答案在文档中。然而,经过大量的研究和挖掘,似乎社区之间的共识是这对任何应用程序都是不可能的。只有特定的图标可以放置在状态栏的右侧(即时钟、天气、系统信息等)。
很抱歉,没有比这更令人兴奋的答案了,但至少您可以停止为自己无法弄明白的原因而苦恼。
编辑 2::
显然,棒棒糖之前的设备可以访问允许您使用系统图标的私有 api(再次考虑警报图标)。之后,这些 api 被删除了。 Whosebug post 相当广泛地涵盖了整个情况。
编辑 3::
如果您可以将图标放在状态栏的左侧,您可以像这样将文本转换为位图:
TextView textView = new TextView(activity.getContext());
textView.setText("Hello World");
textView.setDrawingCacheEnabled(true);
textView.destroyDrawingCache();
textView.buildDrawingCache();
Bitmap bitmap = getTransparentBitmapCopy(textView.getDrawingCache());
private Bitmap getTransparentBitmapCopy(Bitmap source) {
int width = source.getWidth();
int height = source.getHeight();
Bitmap copy = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
source.getPixels(pixels, 0, width, 0, 0, width, height);
copy.setPixels(pixels, 0, width, 0, 0, width, height);
return copy;
}
我确实找到了解决方案,关键字是 overlay with a floating window.
int statusBarHeight = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) statusBarHeight = getResources().getDimensionPixelSize(resourceId);
final WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
statusBarHeight,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, // Allows the view to be on top of the StatusBar
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, // Keeps the button presses from going to the background window and Draws over status bar
PixelFormat.TRANSLUCENT);
parameters.gravity = Gravity.TOP | Gravity.CENTER;
LinearLayout ll = new LinearLayout(this);
ll.setBackgroundColor(Color.TRANSPARENT);
LinearLayout.LayoutParams layoutParameteres = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
ll.setLayoutParams(layoutParameteres);
TextView tv = new TextView(this);
ViewGroup.LayoutParams tvParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
tv.setLayoutParams(tvParameters);
tv.setTextColor(Color.WHITE);
tv.setGravity(Gravity.CENTER);
tv.setText("123");
ll.addView(tv);
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(ll, parameters);
嗯,我做到了。我用的是把text
转成图标然后显示在状态栏上的方式。一些成员试图覆盖 android 不允许的状态栏(SDK>=22),我不知道这是否对某些人有用。但是将 text
转换为图标非常适合我。 在 Oreo
上进行了测试
伪代码
- 将文本转换为
Bitmap
- 然后将
Bitmap
转换成图标。
- 在状态栏上显示该图标。
输出
代码如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
displayNotification("5F");
}
public void displayNotification(String text) {
Notification.Builder builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
builder = new Notification.Builder(this, CHANNEL_ID);
}
//convert text to bitmap
Bitmap bitmap = createBitmapFromString(text.trim());
//setting bitmap to staus bar icon.
builder.setSmallIcon(Icon.createWithBitmap(bitmap));
builder.setContentTitle("Simple Notification");
builder.setContentText("This is a simple notification");
builder.setPriority(Notification.PRIORITY_MAX);
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
notificationManagerCompat.notify(NOTIFICATION_ID, builder.build());
createNotificationChannel();
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (VERSION.SDK_INT >= VERSION_CODES.O) {
CharSequence name = "testing";
String description = "i'm testing this notification";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
assert notificationManager != null;
notificationManager.createNotificationChannel(channel);
}
}
private Bitmap createBitmapFromString(String inputNumber) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(100);
paint.setTextAlign(Paint.Align.CENTER);
Rect textBounds = new Rect();
paint.getTextBounds(inputNumber, 0, inputNumber.length(), textBounds);
Bitmap bitmap = Bitmap.createBitmap(textBounds.width() + 10, 90,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(inputNumber, textBounds.width() / 2 + 5, 70, paint);
return bitmap;
}
如果有人知道更好的方法请提及
我正在尝试为 Android 牛轧糖开发一个应用程序,我想在 android 服务例程生成的状态栏中显示一些 info/text。所以我的问题是,我不知道如何在状态栏中显示文本。
我添加了一张示例图片来说明我的意思(红色圆圈)。 我知道这是可能的,因为我在 Play 商店的电池监视器应用程序中看到了它。
我已经试过了NotificationCombat.Builder,但我认为这不是正确的方法。也许是叠加层,但搜索后我没有找到任何东西。
有人可以告诉我怎么做或给我提示吗?
编辑:这是我的 NotificationCompat.Builder
测试代码MainActivity.java
import android.app.Notification;
import android.app.NotificationManager;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
public class MainActivity extends AppCompatActivity
{
private final int NOTIFICATION_ID = 10;
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Value");
mBuilder.setContentText("123");
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
mBuilder.setOngoing(true);
mBuilder.setAutoCancel(false);
//Intent resultIntent = new Intent(this, MainActivity.class);
//PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//mBuilder.setContentIntent(resultPendingIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(NOTIFICATION_ID, notification);
}
}
activity_main.xml
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000000"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:weightSum="100" >
<TextView
android:id="@+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
结果:
您可以在此处的文档中找到答案:https://developer.android.com/reference/android/support/v4/app/NotificationCompat.html
编辑:: 好吧,答案在文档中。然而,经过大量的研究和挖掘,似乎社区之间的共识是这对任何应用程序都是不可能的。只有特定的图标可以放置在状态栏的右侧(即时钟、天气、系统信息等)。
很抱歉,没有比这更令人兴奋的答案了,但至少您可以停止为自己无法弄明白的原因而苦恼。
编辑 2:: 显然,棒棒糖之前的设备可以访问允许您使用系统图标的私有 api(再次考虑警报图标)。之后,这些 api 被删除了。 Whosebug post 相当广泛地涵盖了整个情况。
编辑 3:: 如果您可以将图标放在状态栏的左侧,您可以像这样将文本转换为位图:
TextView textView = new TextView(activity.getContext());
textView.setText("Hello World");
textView.setDrawingCacheEnabled(true);
textView.destroyDrawingCache();
textView.buildDrawingCache();
Bitmap bitmap = getTransparentBitmapCopy(textView.getDrawingCache());
private Bitmap getTransparentBitmapCopy(Bitmap source) {
int width = source.getWidth();
int height = source.getHeight();
Bitmap copy = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
source.getPixels(pixels, 0, width, 0, 0, width, height);
copy.setPixels(pixels, 0, width, 0, 0, width, height);
return copy;
}
我确实找到了解决方案,关键字是 overlay with a floating window.
int statusBarHeight = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) statusBarHeight = getResources().getDimensionPixelSize(resourceId);
final WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
statusBarHeight,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, // Allows the view to be on top of the StatusBar
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, // Keeps the button presses from going to the background window and Draws over status bar
PixelFormat.TRANSLUCENT);
parameters.gravity = Gravity.TOP | Gravity.CENTER;
LinearLayout ll = new LinearLayout(this);
ll.setBackgroundColor(Color.TRANSPARENT);
LinearLayout.LayoutParams layoutParameteres = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
ll.setLayoutParams(layoutParameteres);
TextView tv = new TextView(this);
ViewGroup.LayoutParams tvParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
tv.setLayoutParams(tvParameters);
tv.setTextColor(Color.WHITE);
tv.setGravity(Gravity.CENTER);
tv.setText("123");
ll.addView(tv);
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(ll, parameters);
嗯,我做到了。我用的是把text
转成图标然后显示在状态栏上的方式。一些成员试图覆盖 android 不允许的状态栏(SDK>=22),我不知道这是否对某些人有用。但是将 text
转换为图标非常适合我。 在 Oreo
伪代码
- 将文本转换为
Bitmap
- 然后将
Bitmap
转换成图标。 - 在状态栏上显示该图标。
输出
代码如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
displayNotification("5F");
}
public void displayNotification(String text) {
Notification.Builder builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
builder = new Notification.Builder(this, CHANNEL_ID);
}
//convert text to bitmap
Bitmap bitmap = createBitmapFromString(text.trim());
//setting bitmap to staus bar icon.
builder.setSmallIcon(Icon.createWithBitmap(bitmap));
builder.setContentTitle("Simple Notification");
builder.setContentText("This is a simple notification");
builder.setPriority(Notification.PRIORITY_MAX);
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
notificationManagerCompat.notify(NOTIFICATION_ID, builder.build());
createNotificationChannel();
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (VERSION.SDK_INT >= VERSION_CODES.O) {
CharSequence name = "testing";
String description = "i'm testing this notification";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
assert notificationManager != null;
notificationManager.createNotificationChannel(channel);
}
}
private Bitmap createBitmapFromString(String inputNumber) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(100);
paint.setTextAlign(Paint.Align.CENTER);
Rect textBounds = new Rect();
paint.getTextBounds(inputNumber, 0, inputNumber.length(), textBounds);
Bitmap bitmap = Bitmap.createBitmap(textBounds.width() + 10, 90,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(inputNumber, textBounds.width() / 2 + 5, 70, paint);
return bitmap;
}
如果有人知道更好的方法请提及