能否在Notification中旋转ImageView?现有实现报错求解决方案
这个问题我之前也碰到过——RemoteViews对可调用的View方法有严格的白名单限制,setRotation(int)并不在支持列表里,所以直接调用就会抛出你看到的RemoteViews$ActionException。
先复盘下你的问题场景:
你尝试通过RemoteViews更新通知里的ImageView旋转角度,代码如下:
RemoteViews notificationLayoutExpanded = new RemoteViews(packageName, R.layout.notification_expanded); // ... notificationLayoutExpanded.setInt(R.id.notification_arrow, "setRotation", 90);抛出异常:
android.widget.RemoteViews$ActionException: view: android.widget.ImageView doesn't have method: setRotation(int)
下面给你几个经过验证的可行解决思路:
方案1:用LevelListDrawable配合setImageLevel(兼容性最强)
这是最推荐的方案,几乎兼容所有Android版本。你只需要准备对应旋转角度的图片资源,然后创建一个LevelListDrawable:<!-- res/drawable/arrow_rotate_level.xml --> <level-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/arrow_0" android:minLevel="0" android:maxLevel="0"/> <item android:drawable="@drawable/arrow_90" android:minLevel="90" android:maxLevel="90"/> <item android:drawable="@drawable/arrow_180" android:minLevel="180" android:maxLevel="180"/> <item android:drawable="@drawable/arrow_270" android:minLevel="270" android:maxLevel="270"/> </level-list>把通知布局里ImageView的
android:src设置为这个drawable,之后通过RemoteViews调用setImageLevel切换角度:// 切换到90度的箭头 notificationLayoutExpanded.setInt(R.id.notification_arrow, "setImageLevel", 90);setImageLevel是RemoteViews明确支持的ImageView方法,完全不会有兼容性问题。方案2:自定义兼容RemoteViews的ImageView(API 16+)
如果你不想准备多张图片,可以自定义一个ImageView,暴露一个RemoteViews能调用的方法:public class RotatableImageView extends ImageView { public RotatableImageView(Context context) { super(context); } public RotatableImageView(Context context, AttributeSet attrs) { super(context, attrs); } public RotatableImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } // 必须是public方法,参数为int,这样RemoteViews才能调用 public void setRotateAngle(int angle) { super.setRotation(angle); } }在通知布局里使用这个自定义View,然后调用:
notificationLayoutExpanded.setInt(R.id.notification_arrow, "setRotateAngle", 90);注意这个方案需要API 16及以上,而且自定义View不能是内部类,要放在公共包下,确保通知进程能正确加载它。
方案3:用缩放模拟旋转(仅适合特定角度)
如果你只需要90/180这类垂直/水平翻转的角度,可以用RemoteViews支持的setScaleX、setScaleY配合setPivotX、setPivotY模拟旋转:// 先设置旋转中心为ImageView的中心点 notificationLayoutExpanded.setFloat(R.id.notification_arrow, "setPivotX", getResources().getDimensionPixelSize(R.dimen.arrow_width)/2f); notificationLayoutExpanded.setFloat(R.id.notification_arrow, "setPivotY", getResources().getDimensionPixelSize(R.dimen.arrow_height)/2f); // 模拟90度旋转(这个效果需要根据你的图片调整) notificationLayoutExpanded.setFloat(R.id.notification_arrow, "setScaleX", 0f); notificationLayoutExpanded.setFloat(R.id.notification_arrow, "setScaleY", 1f);这个方案局限性很大,只适合特定场景,不推荐作为通用解决方案。
内容的提问来源于stack exchange,提问作者Jacek

