如何在 Widget 中使用 Glide 更新 ImageView contentDescription
How to update ImageView contentDescription with Glide in a Widget
我有一个 Android 主屏幕小部件,其布局基本上是 ImageView
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_ultraviolet_widget_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:gravity="center">
<ImageView
android:id="@+id/iv_ultraviolet_widget_image"
android:layout_width="@dimen/widget_size"
android:layout_height="@dimen/widget_size"
android:src="@drawable/ic_uvi_loading" />
</RelativeLayout>
ImageView
将随时间更新为“当前”值,使用以下代码用图像(可绘制对象)表示:
/**
* Updates ultraviolet index widget view.
*/
@JvmStatic
private fun updateWidgetViews(context: Context, appWidgetId: Int, @DrawableRes drawableId: Int) {
val widgetView = RemoteViews(context.packageName, R.layout.ultraviolet_widget)
// Set an Intent to launch MainActivity when clicking on the widget
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
widgetView.setOnClickPendingIntent(R.id.rl_ultraviolet_widget_layout, pendingIntent)
val appWidgetTarget = AppWidgetTarget(context, R.id.iv_ultraviolet_widget_image, widgetView, appWidgetId)
Glide
.with(context)
.asBitmap() // This is needed because AppWidgetTarget is a Bitmap target. See: https://github.com/bumptech/glide/issues/2717#issuecomment-351791721
.transition(BitmapTransitionOptions.withCrossFade())
.load(drawableId)
.into(appWidgetTarget)
pushWidgetUpdate(context, appWidgetId, widgetView)
}
/**
* Pushes update for a given widget.
*/
@JvmStatic
fun pushWidgetUpdate(context: Context, appWidgetId: Int, remoteViews: RemoteViews) {
val manager = AppWidgetManager.getInstance(context)
// Remember to check always for null in platform types (types ended in !).
// See:
manager?.let {
manager.updateAppWidget(appWidgetId, remoteViews)
Timber.d("Widget %d was updated", appWidgetId)
}
}
我的问题是如何同时更新小部件 ImageView
中的 contentDescription
属性 以及每次更新的描述并使用 Glide,以便我的小部件更易于访问并且它可以与 TalkBack 一起使用。我已经搜索过了,但我还没有找到 Glide 和远程视图的任何示例。
提前致谢,
哈维
您可以在加载图片时为 Glide 添加监听器。因此,当加载图像成功时,您更新 imageView 的 contentDescription。
您可以在此处阅读如何向 Gilde 添加侦听器:https://github.com/codepath/android_guides/wiki/Displaying-Images-with-the-Glide-Library#loading-errors
GlideApp.with(context)
.load("http://via.placeholder.com/300.png")
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
// log exception
Log.e("TAG", "Error loading image", e);
return false; // important to return false so the error placeholder can be placed
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
// load image success, update the contentDescription here
return false;
}
})
.into(ivImg);
感谢@Nguyễn Quang Thọ 的帮助,我找到了解决方案。首先,我在 Kotlin 中创建了一个数据 class(一个元组)用于保存可绘制对象及其关联的字符串:
data class UltravioletImageContents(@DrawableRes val drawableId: Int, val contentDescription: String)
其次,我使用 Glide 结果侦听器添加了 contentDescription 更新并将更改推送到我的 updateWidgetViews
函数中的小部件。
@JvmStatic
private fun updateWidgetViews(context: Context, appWidgetId: Int, ultravioletImageContents: UltravioletImageContents) {
val widgetView = RemoteViews(context.packageName, R.layout.ultraviolet_widget)
// Set an Intent to launch MainActivity when clicking on the widget
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
widgetView.setOnClickPendingIntent(R.id.rl_ultraviolet_widget_layout, pendingIntent)
// Set image
val appWidgetTarget = AppWidgetTarget(context, R.id.iv_ultraviolet_widget_image, widgetView, appWidgetId)
Glide
.with(context)
.asBitmap() // This is needed because AppWidgetTarget is a Bitmap target. See: https://github.com/bumptech/glide/issues/2717#issuecomment-351791721
.transition(BitmapTransitionOptions.withCrossFade())
.load(ultravioletImageContents.drawableId)
.listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: com.bumptech.glide.request.target.Target<Bitmap>?, isFirstResource: Boolean): Boolean {
Timber.e(e, "Drawable cannot be loaded and set in widget image view")
return false // Important to return false so the error placeholder can be placed
}
override fun onResourceReady(resource: Bitmap?, model: Any?, target: com.bumptech.glide.request.target.Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
// Set contentDescription in order to enable accessibility and be usable with TalkBack
widgetView.setContentDescription(R.id.iv_ultraviolet_widget_image, ultravioletImageContents.contentDescription)
pushWidgetUpdate(context, appWidgetId, widgetView)
return false
}
})
.into(appWidgetTarget)
}
最后,我想指出 pushWidgetUpdate
已移入 onResourceReady
,因为我认为在没有图像的情况下更新我的小部件没有意义(但是,也许,我遗漏了一些东西)。
我有一个 Android 主屏幕小部件,其布局基本上是 ImageView
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_ultraviolet_widget_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:gravity="center">
<ImageView
android:id="@+id/iv_ultraviolet_widget_image"
android:layout_width="@dimen/widget_size"
android:layout_height="@dimen/widget_size"
android:src="@drawable/ic_uvi_loading" />
</RelativeLayout>
ImageView
将随时间更新为“当前”值,使用以下代码用图像(可绘制对象)表示:
/**
* Updates ultraviolet index widget view.
*/
@JvmStatic
private fun updateWidgetViews(context: Context, appWidgetId: Int, @DrawableRes drawableId: Int) {
val widgetView = RemoteViews(context.packageName, R.layout.ultraviolet_widget)
// Set an Intent to launch MainActivity when clicking on the widget
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
widgetView.setOnClickPendingIntent(R.id.rl_ultraviolet_widget_layout, pendingIntent)
val appWidgetTarget = AppWidgetTarget(context, R.id.iv_ultraviolet_widget_image, widgetView, appWidgetId)
Glide
.with(context)
.asBitmap() // This is needed because AppWidgetTarget is a Bitmap target. See: https://github.com/bumptech/glide/issues/2717#issuecomment-351791721
.transition(BitmapTransitionOptions.withCrossFade())
.load(drawableId)
.into(appWidgetTarget)
pushWidgetUpdate(context, appWidgetId, widgetView)
}
/**
* Pushes update for a given widget.
*/
@JvmStatic
fun pushWidgetUpdate(context: Context, appWidgetId: Int, remoteViews: RemoteViews) {
val manager = AppWidgetManager.getInstance(context)
// Remember to check always for null in platform types (types ended in !).
// See:
manager?.let {
manager.updateAppWidget(appWidgetId, remoteViews)
Timber.d("Widget %d was updated", appWidgetId)
}
}
我的问题是如何同时更新小部件 ImageView
中的 contentDescription
属性 以及每次更新的描述并使用 Glide,以便我的小部件更易于访问并且它可以与 TalkBack 一起使用。我已经搜索过了,但我还没有找到 Glide 和远程视图的任何示例。
提前致谢,
哈维
您可以在加载图片时为 Glide 添加监听器。因此,当加载图像成功时,您更新 imageView 的 contentDescription。
您可以在此处阅读如何向 Gilde 添加侦听器:https://github.com/codepath/android_guides/wiki/Displaying-Images-with-the-Glide-Library#loading-errors
GlideApp.with(context)
.load("http://via.placeholder.com/300.png")
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
// log exception
Log.e("TAG", "Error loading image", e);
return false; // important to return false so the error placeholder can be placed
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
// load image success, update the contentDescription here
return false;
}
})
.into(ivImg);
感谢@Nguyễn Quang Thọ 的帮助,我找到了解决方案。首先,我在 Kotlin 中创建了一个数据 class(一个元组)用于保存可绘制对象及其关联的字符串:
data class UltravioletImageContents(@DrawableRes val drawableId: Int, val contentDescription: String)
其次,我使用 Glide 结果侦听器添加了 contentDescription 更新并将更改推送到我的 updateWidgetViews
函数中的小部件。
@JvmStatic
private fun updateWidgetViews(context: Context, appWidgetId: Int, ultravioletImageContents: UltravioletImageContents) {
val widgetView = RemoteViews(context.packageName, R.layout.ultraviolet_widget)
// Set an Intent to launch MainActivity when clicking on the widget
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
widgetView.setOnClickPendingIntent(R.id.rl_ultraviolet_widget_layout, pendingIntent)
// Set image
val appWidgetTarget = AppWidgetTarget(context, R.id.iv_ultraviolet_widget_image, widgetView, appWidgetId)
Glide
.with(context)
.asBitmap() // This is needed because AppWidgetTarget is a Bitmap target. See: https://github.com/bumptech/glide/issues/2717#issuecomment-351791721
.transition(BitmapTransitionOptions.withCrossFade())
.load(ultravioletImageContents.drawableId)
.listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: com.bumptech.glide.request.target.Target<Bitmap>?, isFirstResource: Boolean): Boolean {
Timber.e(e, "Drawable cannot be loaded and set in widget image view")
return false // Important to return false so the error placeholder can be placed
}
override fun onResourceReady(resource: Bitmap?, model: Any?, target: com.bumptech.glide.request.target.Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
// Set contentDescription in order to enable accessibility and be usable with TalkBack
widgetView.setContentDescription(R.id.iv_ultraviolet_widget_image, ultravioletImageContents.contentDescription)
pushWidgetUpdate(context, appWidgetId, widgetView)
return false
}
})
.into(appWidgetTarget)
}
最后,我想指出 pushWidgetUpdate
已移入 onResourceReady
,因为我认为在没有图像的情况下更新我的小部件没有意义(但是,也许,我遗漏了一些东西)。