如何使用自定义视图创build通知,但具有原生外观和感觉?

背景

我需要做一个自定义的,大型的通知,底部有大约3张图片,顶部有一个标题和图片以及两个文字浏览。

类似的东西:

在这里输入图像说明

上面的区域需要看起来像原生通知,使它们之间有一个很好的转换。

底部区域是dynamic的,在哪些照片放在那里(使用位图)。

问题

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

我试过了

我想到了2个解决scheme:

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

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

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的意见,并画一个位图。 它工作,但在一些设备和configuration(甚至风景),它不工作。

  1. 使用RemoteViews,然后在ImageView上设置图像。 问题是,我需要模仿顶级区域看起来本土,但即使我find它,也不能保证它会在所有设备和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> 

我发现了什么

有关在自定义布局上使用样式的文档非常模糊,只是要小心并在多个Android设备上进行尝试:

注意:当您使用自定义通知布局时,请特别注意确保您的自定义布局可以使用不同的设备方向和分辨率。 虽然此build议适用于所有View布局,但对于通知来说尤其重要,因为通知抽屉中的空间非常有限。 不要让你的自定义布局太复杂,一定要以各种configuration进行testing。

样式文本也一样:

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

他们不知道要用什么样的颜色或什么

这个问题

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

你有什么其他的想法可以做到这一点?

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

另外,也许最重要的问题是:如何在自定义视图上使用通知的默认样式? 我不仅在谈论标题和字幕textViews(可能使用“android:TextAppearance.StatusBar.EventContent.Title”和“android:TextAppearance.StatusBar.EventContent”样式),但对于任何部分的通知:图标在右边的文字,行动,… … –


编辑:search了一会儿关于风格的通知,我发现这在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”的风格,因为它是一个图标,但它是一个文本的外观。 再加上它是空的

无论如何,之后,我发现了下一个布局文件,名为“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,并设置文本和图像),但它看起来不太好:

在这里输入图像说明

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


编辑:可悲的是,它决定使用自定义视图解决scheme(#2),但我无法find足够的信息,如何使一切看起来本机,所以我不得不做一些“逆向工程”代码以及通知的外观。

如果任何人有完整的信息如何使它看起来很好所有的Android版本(和ROM),请让我知道。

Solutions Collecting From Web of "如何使用自定义视图创build通知,但具有原生外观和感觉?"

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

创build通知:

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

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

输出:

产量