【问题标题】:How to create a notification with a custom view , but with an native look & feel?如何使用自定义视图创建通知,但具有原生外观?
【发布时间】:2014-11-02 13:28:05
【问题描述】:

背景

我需要制作一个自定义的大样式通知,底部大约有 3 张图像,顶部有一个标题和图像和 2 个文本视图。

类似的东西:

上部区域需要看起来与原生通知完全一样,以使其在两者之间有一个很好的过渡。

底部区域在放置哪些照片方面是动态的(使用位图)。

问题

一旦我使用了自定义视图,它实际上包含了整个布局,包括上部区域。

我尝试过的

我想到了 2 个解决方案:

  1. 创建一个位图,其中包含 3 个图像,然后使用BigPictureStyle 为它。问题是它在某些情况下可能会裁剪图像的内容,并且如果您转到横向,图像之间的间距将无法很好地显示(我已经检查过:您不能设置多个布局,例如一个一个用于横向,一个用于纵向)。

为了创建位图,我可以使用这样的东西:

    final int widthScreen = getResources().getDisplayMetrics().widthPixels;
    final int width = Math.min(widthScreen, (int) convertDpToPixels(this, 256));
    final Bitmap outputBitmap = Bitmap.createBitmap(width, width / 3, Config.ARGB_8888);
    final Canvas canvas = new Canvas(outputBitmap);
    final int[] imagesResIds = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3 };
    final Paint paint = new Paint();
    for (int i = 0; i < 3; ++i) {
        final Bitmap b = BitmapFactory.decodeResource(getResources(), imagesResIds[i]);
        canvas.drawBitmap(b, null, new Rect(i * (width / 3), 0, (i + 1) * (width / 3) - 1, width / 3 - 1), paint);
    }
    return outputBitmap;

由于某种原因,它不能很好地显示图像,但你明白了......

我还尝试在 #2 上放大视图,并绘制位图。它可以工作,但在某些设备和配置(甚至横向)上效果不佳。

  1. 使用 RemoteViews,然后在 ImageViews 上设置图像。问题是我需要模仿顶部区域看起来很原生,但即使我找到它,也不能保证它在所有设备和 Android 版本上看起来都很好(对吧?)。另外,我可能需要获取每个 Android 版本的本机通知布局。使用水平 listView 也可以,但它不存在。

这是通知底部区域的示例布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="128dp"
    android:gravity="center_horizontal"
    android:orientation="horizontal" >

    <ImageView
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <ImageView
        android:layout_width="128dp"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/pic1" />

    <ImageView
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <ImageView
        android:layout_width="128dp"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/pic2" />

    <ImageView
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <ImageView
        android:layout_width="128dp"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/pic3" />

    <ImageView
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

</LinearLayout>

我发现了什么

The documentation 关于在自定义布局上使用样式非常模糊,告诉你要小心并在多个 Android 设备上试用:

注意:使用自定义通知布局时,请特别注意 确保您的自定义布局适用于不同的设备 方向和决议。虽然此建议适用于所有视图 布局,这对于通知尤其重要,因为空间 在通知抽屉里是非常有限的。不要做你的定制 布局过于复杂,请务必在各种配置中进行测试。

样式文本也是如此:

始终为自定义通知的文本使用样式资源。这 通知的背景颜色可能因不同设备而异 和版本,使用样式资源可以帮助您解决这个问题。 从 Android 2.3 开始,系统为标准定义了样式 通知布局文本。如果您在应用程序中使用相同的样式 以 Android 2.3 或更高版本为目标,您将确保您的文本是 在显示背景下可见。

他们不告诉使用什么,哪种样式或颜色或任何东西......

问题

是否可以创建这样的通知?我该如何处理?

您对如何做到这一点还有其他想法吗?

是否也可以使用限定符设置不同的布局(我没有成功)?

另外,也许是最重要的问题:我如何在自定义视图上使用通知的默认样式?我说的不仅是标题和副标题 textViews(可能使用“android:TextAppearance.StatusBar.EventContent.Title”和“android:TextAppearance.StatusBar.EventContent”样式),还包括通知的任何部分:图标右边的文字,动作,...


编辑:在搜索了一段时间关于通知的样式后,我在 Android 源代码中的“styles.xml”中找到了这个:

<style name="TextAppearance.StatusBar.Icon">
</style>
<!-- Notification content styles -->
<style name="TextAppearance.StatusBar.EventContent">
    <item name="textColor">#999999</item>
    <item name="textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Title">
    <item name="textColor">#ffffff</item>
    <item name="fontFamily">sans-serif-light</item>
    <item name="textSize">@dimen/notification_title_text_size</item>
    <item name="textStyle">bold</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Line2">
    <item name="textSize">@dimen/notification_subtext_size</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Info">
    <item name="textSize">@dimen/notification_subtext_size</item>
    <item name="textColor">#999999</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Time">
    <item name="textSize">@dimen/notification_subtext_size</item>
    <item name="textColor">#999999</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Emphasis">
    <item name="textColor">#CCCCCC</item>
</style>

奇怪的是有一个名为“TextAppearance.StatusBar.Icon”的样式,因为它是一个图标,但它是一个 textAppearance。再加上它是空的......

无论如何,在那之后,我找到了下一个布局文件,名为“notification_intruder_content.xml”,但我不确定是否可以复制它,因为操作系统之间(甚至不同 rom 之间)的情况可能会发生变化:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="4dp"
    >
    <ImageView android:id="@+id/icon"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:scaleType="center"
        android:padding="4dp"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="40dp"
        android:orientation="vertical"
        >
        <TextView android:id="@+id/title"
            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal"
            />
        <TextView android:id="@+id/text"
            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginTop="-4dp"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal"
            />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/actions"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:orientation="horizontal"
        android:visibility="gone"
        >
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
            android:id="@+id/action0"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:visibility="gone"
            />
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
            android:id="@+id/action1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:visibility="gone"
            />
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
            android:id="@+id/action2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:visibility="gone"
            />
    </LinearLayout>
</FrameLayout>

我尝试过使用它(只是更改了 id,并设置了文本和图像),但它看起来一点也不好看:

不仅如此,触摸它时,我看不到触摸普通通知的效果,所以背景也可能是错误的。


编辑:遗憾的是,决定使用自定义视图解决方案(#2),但我找不到足够的信息来说明如何让一切看起来都是原生的,所以我不得不做一些“逆向工程”查看 Android 的代码以及通知的外观。

如果有人知道如何使它在所有 Android 版本(和 rom)上看起来都很好,请告诉我。

【问题讨论】:

  • 我也有同样的问题,你是怎么解决的?我已经在谷歌上搜索了一段时间,但找不到任何标准参考。
  • 我们继续前进。根本没做过……

标签: android android-layout android-custom-view android-notifications remoteview


【解决方案1】:

我没有得到确切的输出,试试这个

创建通知:

public void CustomNotification() {
        //dynamic layer
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.HORIZONTAL);

        LayoutParams llLP = new LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        ll.setLayoutParams(llLP);
        ImageView imageView = new ImageView(this);
        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        imageView.setLayoutParams(lp);
        imageView.setImageResource(R.drawable.v1);

        ll.addView(imageView);
        ImageView imageView1 = new ImageView(this);

        imageView1.setLayoutParams(lp);
        imageView1.setImageResource(R.drawable.v2);

        ll.addView(imageView1);
        //create a dynamic layout to bitmap
        Bitmap bp = convertViewToDrawable(ll);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this).setSmallIcon(R.drawable.ic_launcher)
                .setTicker("Dummy App ").setAutoCancel(true)
                .setContentIntent(null);
        NotificationCompat.BigPictureStyle bigPicStyle = new NotificationCompat.BigPictureStyle();
        bigPicStyle.bigPicture(bp);
        bigPicStyle.setBigContentTitle("My Title");
        builder.setStyle(bigPicStyle);

        NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationmanager.notify(100, builder.build());

    }

创建位图视图

public static Bitmap convertViewToDrawable(View view) {
        int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        view.measure(spec, spec);
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        Bitmap b = Bitmap.createBitmap(view.getMeasuredWidth(),
                view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        c.translate(-view.getScrollX(), -view.getScrollY());

        view.draw(c);
        view.setDrawingCacheEnabled(true);
        Bitmap cacheBmp = view.getDrawingCache();
        Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
        view.destroyDrawingCache();
        return viewBmp;

    }

输出:

【讨论】:

  • 是的,这与我后来所做的类似,但结果大致相同。尝试改变方向。它看起来不会很好。另外,它们不是正方形。办公室决定,因为他们想要更多定制的东西(比如底部的一些文本),我需要使用另一个解决方案,带有定制视图。可悲的是,我没有找到足够的信息来说明如何让它看起来像原生的。他们不在乎:(
猜你喜欢
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
相关资源
最近更新 更多