如何正确地实现具有动态绘制内容的Android小部件?

16

我想要为我的第一个超级棒的Android项目创建一个主屏幕小部件,它会显示那些孩子们最近都在狂热追捧的Arc Clocks时钟。

根据RemoteViews的限制,我认为在实际布局中使用一个ImageView,然后在更新时创建一个或两个ShapeDrawable并将它们绘制到新创建的Bitmap上,然后将该位图设置为ImageView的源,是将其实际绘制在屏幕上的适当方式。

然而,这个过程中有一些我不明白的地方。以下是我尝试使用的代码来更新小部件。屏幕上没有任何绘制内容。ImageView有一个占位符图像,只需设置其src属性即可。当我不运行代码将其更新为我的绘图时,占位符图像仍保持在原位。所以,我知道这段代码正在做某些事情,只是显然不是正确的事情。

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);

ShapeDrawable drawable = new ShapeDrawable(new ArcShape(0, 360));
drawable.getPaint().setColor(0xffff0000);
drawable.getPaint().setStrokeWidth(5.0f);
drawable.setIntrinsicWidth(100);
drawable.setIntrinsicHeight(100);
drawable.draw(canvas);

views.setImageViewBitmap(R.id.ImageView01, bitmap);     
appWidgetManager.updateAppWidget(appWidgetId, views);

我知道这事不可能那么简单。所以,我是否朝着正确的方向前进?


更新

好吧,也许那些信息太多了。我真正想问的问题是:

如果我想在小部件上绘制形状,我应该使用ImageView并从我的ShapeDrawable创建位图,还是有更合适的方法可以在受RemoteViews限制的小部件中进行绘制?


你是说当试图在其上绘制东西时,占位符仍然存在吗? - sandos
不,占位图像会消失。最终屏幕上不会有任何可视化内容。但是,我仍然可以长按小部件并将其删除。 - MojoFilter
3个回答

8

实际上,SDK中有一个名为AnalogClock的小部件与您试图完成的功能非常相似。

这是一个扩展了View并带有@RemoteView注释的类。它在Intent.ACTION_TIME_TICKIntent.ACTION_TIME_CHANGED上注册接收器,并通过重写onDraw方法来绘制自身。请查看源代码。标准的闹钟应用程序将this view作为可以添加到主屏幕的小部件公开

我认为这是实现你所描述的内容的好方法(如果不是最好的),显然效果很好。


哦,太酷了。我原本以为你不能扩展一个视图并将其添加到 RemoteView 中,因为只有非常特定的类型被允许在 RemoteView 中使用,即使是子类也不行。如果只需要这样做,那么我想我应该能够轻松搞定。我会试一试的。 - MojoFilter
这是给我留下印象的文档:http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout - MojoFilter
我已经尝试过了,不幸的是,据我所知,您无法对视图进行子类化并将其添加到RemoteView中使用的布局中。它适用于AnalogClock视图的唯一原因是AnalogClock是那些明确允许的组件之一。 - MojoFilter
2
但是你知道如何使用@RemoteView创建自定义视图后代吗?我尝试创建自己的视图,但小部件在加载时崩溃了。 - Vadim
1
一样的情况。我认为它只在SDK中对视图可用。 - christoff
1
[AnalogClock] 类在 API 级别 23 中已被弃用。此小部件不再受支持。 - bogl

5

这很好用:

Paint p = new Paint(); 
p.setAntiAlias(true);
p.setStyle(Style.STROKE);
p.setStrokeWidth(8);
p.setColor(0xFFFF0000);

Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawArc(new RectF(10, 10, 90, 90), 0, 270, false, p);

RemoteViews views = new RemoteViews(updateService.getPackageName(), R.layout.main);
views.setImageViewBitmap(R.id.canvas, bitmap);

ComponentName componentName = new ComponentName(updateService, DashboardAppWidgetProvider.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(updateService);
appWidgetManager.updateAppWidget(componentName, views);

我猜你原来的代码问题只是画弧的方式不对,所以没有显示出来。
另外,你可以在市场上搜索“arc clock”找到一个内存占用很小且可自定义的“弧形时钟”!

0
为创建自定义组件,我会扩展View或View的任何子类,并重写onDraw(Canvas canvas)方法来进行绘制。在canvas对象上,您可以调用drawLine()、drawArc()、drawPicture()、drawPoints()、drawText()、drawRect()等方法。 这里有更多详细信息。 这是Canvas的API。 我相信您可以将自定义视图添加到远程视图中,以便制作小部件。

1
我非常确定这就是整个问题所在。如果我能够简单地创建一个视图的子类,那就太简单了。然而,用于与小部件通信的RemoteViews只能包含一组非常特定的元素。 - MojoFilter

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