在学习如何加载,调整大小,缩放图像以及如何通过多个方面影响图像管理之后,我们将介绍一个非常高级的优化:Tag()。
Picasso提供对许多图片请求进行分组,以便一起管理它们。
Picasso的Tag()
在上一篇博文中,您已经了解了如何确定某些图片的优先级。
这可能是不够的,我们有时还需要同时取消,暂停或恢复多个图像。
如果您的视图快速变化,则取消之前过期屏幕上的图片的所有请求并启动新视图的图片将非常有用。
Picasso用tag()来描述这个功能。
tag(Object object)将任何Java对象作为参数。 因此,您可以基于几乎任何逻辑构建您的图像组。
图像组具有以下选项:
- 使用pauseTag()暂停请求
- 使用resumeTag()恢复请求
- 使用cancelTag()取消请求。
每当你需要暂停或取消加载一个或多个图像,就应用一个Tag,然后调用相应的方法。
这听起来有点抽象,所以让我们看一个例子。
现在,让我们考虑下面的情况:用户正在搜索一个旧的消息,并用快速向下滚动屏幕。 ListView旨在快速回收和重用这些项目。 如果你正确实现了适配器,这将是一个顺利的过程。 然而,因为用户快速的滚动列表,Picasso将尝试为每一行开始一个请求,然后又必须立即取消它。
我们应该想到一种方法让它会更有效地暂停图像加载,直到滚动任务完成。 用户不会注意到任何差异,但您的应用程序显著减少了请求量。
实现很容易。
首先,向您的Picasso请求添加标签:
Picasso
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.tag("Profile ListView") // can be any Java object
.into(imageViewWithTag);
然后,您可以基于(例如ListView的)滚动状态,使用此标记暂停和恢复请求。
例如,Picasso的示例应用程序现在具有以下滚动侦听器:
ublic class SampleScrollListener implements AbsListView.OnScrollListener {
...
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Picasso picasso = Picasso.with(context);
if (scrollState == SCROLL_STATE_IDLE ||
scrollState == SCROLL_STATE_TOUCH_SCROLL) {
picasso.resumeTag(someTag);
} else {
picasso.pauseTag(someTag);
}
}
...
}
最后,将侦听器设置给ListView:
ListView listView = (ListView)findViewById(R.id.listView);
listView.setOnScrollListener(onScrollListener);
当ListView滚动状态更改为fling时,它将暂停所有请求。 当滚动状态返回到空闲或常规滚动位置时,它将恢复请求。
cancelTag()
考虑下面一种情况:您实现了一个购物车,您可以在其中使用图像显示所有选定的商店项目。 一旦用户点击“购买” 按钮,显示ProgressDialog。 一旦用户点击“购买” 按钮,将会部分隐藏项目列表。
这个时候我们不需要继续加载项目图像来进一步加重设备的网络连接,电池和内存的负担。
我们可以通过在显示ProgressDialog之后调用.cancelTag()来优化行为。
public void buyButtonClick(View v) {
// display ProgressDialog
// ...
// stop image requests
Picasso
.with(context)
.cancelTag("ShoppingCart");
// make 'buy'-request to server
// ...
}
图像旋转
Picasso内置支持旋转图像,然后显示它们。
有两个选择:简单和复杂旋转。
简单旋转
Picasso
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.rotate(90f)
.into(imageViewSimpleRotate);
这将会是图片旋转90度。
复杂旋转
默认情况下,旋转中心(“枢轴点”)为坐标(0,0)。有时,您可能需要围绕特定枢轴点(不是标准旋转中心)旋转图像。
你可以调用rotate(float degrees,float pivotX,float pivotY)。
Picasso
.with(context)
.load(R.drawable.floorplan)
.rotate(45f, 200f, 100f)
.into(imageViewComplexRotate);
Transformation方法
图像的变换还有一个方法: transform(android.graphics.Bitmap source)。 此方法接受位图,并返回已转换的位图。
自定义转换后,您可以在您的Picasso请求上使用transform(Transformation transformation)进行简单设置。 这将导致图像在显示之前进行变换。
自定义Transformation并实现Transformation接口:
public class BlurTransformation implements Transformation {
RenderScript rs;
public BlurTransformation(Context context) {
super();
rs = RenderScript.create(context);
}
@Override
public Bitmap transform(Bitmap bitmap) {
// Create another bitmap that will hold the results of the filter.
Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
// Allocate memory for Renderscript to work with
Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
Allocation output = Allocation.createTyped(rs, input.getType());
// Load up an instance of the specific script that we want to use.
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// Set the blur radius
script.setRadius(10);
// Start the ScriptIntrinisicBlur
script.forEach(output);
// Copy the output to the blurred bitmap
output.copyTo(blurredBitmap);
bitmap.recycle();
return blurredBitmap;
}
@Override
public String key() {
return "blur";
}
}
然后,将transformation添加到Picasso是非常简单的:
Picasso
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.transform(new BlurTransformation(context))
.into(imageViewTransformationBlur);
除此之外,Picasso还允许该参数为列表:**transform(List <?extends Transformation>
transformations)**。 这意味着你可以对图像应用进行一连串的变换。
public class GrayscaleTransformation implements Transformation {
private final Picasso picasso;
public GrayscaleTransformation(Picasso picasso) {
this.picasso = picasso;
}
@Override
public Bitmap transform(Bitmap source) {
Bitmap result = createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
Bitmap noise;
try {
noise = picasso.load(R.drawable.noise).get();
} catch (IOException e) {
throw new RuntimeException("Failed to apply transformation! Missing resource.");
}
BitmapShader shader = new BitmapShader(noise, REPEAT, REPEAT);
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint(ANTI_ALIAS_FLAG);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(result);
canvas.drawBitmap(source, 0, 0, paint);
paint.setColorFilter(null);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
source.recycle();
noise.recycle();
return result;
}
@Override
public String key() {
return "grayscaleTransformation()";
}
}
通过构建列表并将其作为参数传递,可以向Picasso请求添加多个转换:
List<Transformation> transformations = new ArrayList<>();
transformations.add(new GrayscaleTransformation(Picasso.with(context)));
transformations.add(new BlurTransformation(context));
Picasso
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.transform(transformations)
.into(imageViewTransformationsMultiple);
还有更多的用法可以看这里:Picasso的官方示例。