如何在Android系统状态栏中显示文本

12

我正在尝试开发一个适用于Android Nougat的应用程序,并希望从Android服务程序生成一些信息/文本在状态栏中显示。所以我的问题是,我不知道如何在状态栏中显示文本。

我添加了一张示例图片以准确说明我的意思(红色圆圈)。 我知道这是可能的,因为我在Play Store上的一个电池监视器应用中看到过。

Sample

我已经尝试使用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>

结果:

结果1

结果2


可能是[在Android中显示状态栏通知文本]的重复问题(https://dev59.com/XoPba4cB1Zd3GeqPpDa_)。希望这就是你要找的。 - Guruprasad J Rao
我已经阅读并尝试过了,但这不是我正在寻找的。 我不需要向下滑动的通知,我需要在状态栏中直接显示文本。 我尝试使用 NotificationCompat.Builder 中的 setSmallIcon(int icon),但它需要一个 int 资源,因此无法使用文本转换为位图/图像。 - Matze
@Matze,你的问题解决了吗? - Shoaib Kakal
3个回答

5

我找到了一个解决方案,关键词是覆盖层浮动窗口

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);

3
我遇到了以下错误 android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl-- permission denied for window type 2010,你有什么想法或解决方法吗? - Snake
1
错误:窗口类型2010的权限被拒绝。 - Shoaib Kakal

4

我使用了将text转换成图标,然后在状态栏上显示的方法。有些成员试图覆盖状态栏,但Android不允许(SDK>=22),我不知道这对其他人是否有效。但将text转换为图标对我来说完美运作。在Oreo上测试过了。

伪代码:

  1. 将文本转换为Bitmap
  2. 然后将Bitmap转换为图标。
  3. 在状态栏上显示该图标。

输出

enter image description here

以下是代码:

 @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;
    }

如果有更好的方法,请务必提出


很好的想法。我已经实现了它并且它正在工作。但唯一的问题是我经常遇到糟糕的通知崩溃。我搜索了一下,发现 builder.setSmallIcon() 的参数应该是 PNG。你知道如何将位图转换为 PNG 并传递给 builder.setSmallIcon() 吗? - SemicolonSpace
我需要为更大的文本做什么?例如,我想打印“androiddeveloper”而不是5F。 - Vahit Keskin
@VahitKeskin,你不能展示那个,相反你应该使用浮动小部件。 - Shoaib Kakal
那么我该如何在状态栏中显示它的浮动属性呢?你能给个例子吗?@ShoaibKakal - Vahit Keskin
你可以创建一个自定义的矩形浮动小部件并将其显示在状态栏顶部。这是一个 Messenger 浮动小部件的示例 https://github.com/sonusurender/Floating_Widget_Chat_Head_Demo - Shoaib Kakal

0

您可以在文档中找到答案,链接在这里:https://developer.android.com/reference/android/support/v4/app/NotificationCompat.html

编辑: 好吧,答案在文档中。然而,在经过大量的研究和挖掘后,社区的共识似乎是并非所有应用程序都可以实现此功能。只有特定的图标可以放置在状态栏的右侧(例如时钟、天气、系统信息等)。

很抱歉没有更令人兴奋的答案,但至少您可以停止为什么无法解决问题而感到紧张了。

编辑2: 显然,早期的设备可以访问私有API,允许您使用系统图标(再次考虑闹钟图标)。之后,这些API被删除了。这个stackoverflow 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;
 }

你能具体一点吗?我尝试使用NotificationCompat.Builder,但它没有按照需要的方式工作(如上面的示例图片)。 - Matze
请随意发布您的代码和结果图片。 - anomeric
我编辑了我的帖子,所以你能看到我的代码。请告诉我文档中我漏掉的部分。 - Matze
就像我之前说的,NotificationCompat 不是正确的方法,但是有一种可行的方法,在应用程序 Battery Monitor (GLGJing) 中有演示。也许有人可以使用覆盖布局来实现它。我不确定这是否是正确的方法,但 ActionBarOverlayLayout 是一个可能性吗?我读到了一些关于它的东西,但并不多,而且在 Android 文档中我没有找到真正有用的信息。 - Matze
您所寻找的功能是不可能实现的。我会编辑我的答案以进一步澄清。 - anomeric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接