Использование Пикассо с RoundedBitmapDrawable
Я видел лекции Udacity о дизайне материалов и там упоминалось об использовании RoundedBitmapDrawable
добиться кругового обзора. Однако у меня есть некоторые проблемы, чтобы заставить его работать с Picasso
,
Я не уверен, как именно Picasso
работает, но у меня есть большое, не квадратное изображение в файловом хранилище. Для этого я использую Picasso
следующее:
Picasso.with(context).load(f).resize(densityDpi, densityDpi).centerInside().transform(new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
Log.d("jano", "transformation running");
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), source);
drawable.setCircular(true);
drawable.setCornerRadius(source.getWidth() / 2.0f);
return drawable.getBitmap();
}
@Override
public String key() {
return "circle";
}
}).into(imageView);
Изображения, однако, возводятся в квадрат без закругленных углов (должны быть круглыми). И это то, чего я хочу достичь.
Есть ли простой способ добиться этого с RoundedBitmapDrawable
или я должен полностью осуществить преобразование? (который я видел на Stackru)
Пожалуйста, не отправляйте ответ без описания, почему его нельзя использовать. Я только хочу знать о комбинации этих 2 предметов (Picasso
, RoundedBitmapDrawable
)
3 ответа
Я много пытался сделать то же самое, но тоже не работал... Я думаю, это проблема во время getBitmap, во всяком случае, я решил сделать это: (Обратите внимание, что основное отличие состоит в том, что я использую setImage как рисуемый и не преобразовываю в растровое как я уже сказал)
Picasso.with(getContext())
.load(mUser.user.profileImageUrl)
.into(mProfileImage, new Callback() {
@Override
public void onSuccess() {
Bitmap source = ((BitmapDrawable) mProfileImage.getDrawable()).getBitmap();
RoundedBitmapDrawable drawable =
RoundedBitmapDrawableFactory.create(getContext().getResources(), source);
drawable.setCircular(true);
drawable.setCornerRadius(Math.max(source.getWidth() / 2.0f, source.getHeight() / 2.0f));
mProfileImage.setImageDrawable(drawable);
}
@Override
public void onError() {
}
});
Я сделал решение для использования RoundedBitmapDrawable, реализовав такую цель (вместо прямого использования.into(ImageView))
Picasso.with(context)
.load("https://something.png")
.into( RoundCornersTargetProxy(my_avatar_imageview, 8f) )
с целевой реализацией следующим образом
class RoundCornersTargetProxy(val view: ImageView, val radius: Float): Target {
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
view.setImageDrawable(placeHolderDrawable)
}
override fun onBitmapFailed(errorDrawable: Drawable?) {
view.setImageDrawable(errorDrawable)
}
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom?) {
RoundedBitmapDrawableFactory.create(Resources.getSystem(), bitmap).let {
it.cornerRadius = radius
view.setImageDrawable(it)
}
}
}
Таким образом, вам не нужно устанавливать его в просмотре изображений, чтобы снова получить его.
Вы можете использовать BezelImageView приложения Google IO, который хорошо работает с библиотекой Picasso, просто добавьте этот класс в свой проект, и вы можете напрямую начать использовать его, как и любой другой просмотр изображений, но у bezelImageView есть 2 дополнительных параметра для указания цвета границы круга и маска вытяжка. Ссылка на исходный код здесь.
BezelImageView.java
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.iosched.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.google.samples.apps.iosched.R;
/**
* An {@link android.widget.ImageView} that draws its contents inside a mask and draws a border
* drawable on top. This is useful for applying a beveled look to image contents, but is also
* flexible enough for use with other desired aesthetics.
*/
public class BezelImageView extends ImageView {
private Paint mBlackPaint;
private Paint mMaskedPaint;
private Rect mBounds;
private RectF mBoundsF;
private Drawable mBorderDrawable;
private Drawable mMaskDrawable;
private ColorMatrixColorFilter mDesaturateColorFilter;
private boolean mDesaturateOnPress = false;
private boolean mCacheValid = false;
private Bitmap mCacheBitmap;
private int mCachedWidth;
private int mCachedHeight;
public BezelImageView(Context context) {
this(context, null);
}
public BezelImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BezelImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Attribute initialization.
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezelImageView,
defStyle, 0);
mMaskDrawable = a.getDrawable(R.styleable.BezelImageView_maskDrawable);
if (mMaskDrawable != null) {
mMaskDrawable.setCallback(this);
}
mBorderDrawable = a.getDrawable(R.styleable.BezelImageView_borderDrawable);
if (mBorderDrawable != null) {
mBorderDrawable.setCallback(this);
}
mDesaturateOnPress = a.getBoolean(R.styleable.BezelImageView_desaturateOnPress,
mDesaturateOnPress);
a.recycle();
// Other initialization.
mBlackPaint = new Paint();
mBlackPaint.setColor(0xff000000);
mMaskedPaint = new Paint();
mMaskedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// Always want a cache allocated.
mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
if (mDesaturateOnPress) {
// Create a desaturate color filter for pressed state.
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mDesaturateColorFilter = new ColorMatrixColorFilter(cm);
}
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
final boolean changed = super.setFrame(l, t, r, b);
mBounds = new Rect(0, 0, r - l, b - t);
mBoundsF = new RectF(mBounds);
if (mBorderDrawable != null) {
mBorderDrawable.setBounds(mBounds);
}
if (mMaskDrawable != null) {
mMaskDrawable.setBounds(mBounds);
}
if (changed) {
mCacheValid = false;
}
return changed;
}
@Override
protected void onDraw(Canvas canvas) {
if (mBounds == null) {
return;
}
int width = mBounds.width();
int height = mBounds.height();
if (width == 0 || height == 0) {
return;
}
if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) {
// Need to redraw the cache.
if (width == mCachedWidth && height == mCachedHeight) {
// Have a correct-sized bitmap cache already allocated. Just erase it.
mCacheBitmap.eraseColor(0);
} else {
// Allocate a new bitmap with the correct dimensions.
mCacheBitmap.recycle();
//noinspection AndroidLintDrawAllocation
mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCachedWidth = width;
mCachedHeight = height;
}
Canvas cacheCanvas = new Canvas(mCacheBitmap);
if (mMaskDrawable != null) {
int sc = cacheCanvas.save();
mMaskDrawable.draw(cacheCanvas);
mMaskedPaint.setColorFilter((mDesaturateOnPress && isPressed())
? mDesaturateColorFilter : null);
cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
super.onDraw(cacheCanvas);
cacheCanvas.restoreToCount(sc);
} else if (mDesaturateOnPress && isPressed()) {
int sc = cacheCanvas.save();
cacheCanvas.drawRect(0, 0, mCachedWidth, mCachedHeight, mBlackPaint);
mMaskedPaint.setColorFilter(mDesaturateColorFilter);
cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
super.onDraw(cacheCanvas);
cacheCanvas.restoreToCount(sc);
} else {
super.onDraw(cacheCanvas);
}
if (mBorderDrawable != null) {
mBorderDrawable.draw(cacheCanvas);
}
}
// Draw from cache.
canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null);
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mBorderDrawable != null && mBorderDrawable.isStateful()) {
mBorderDrawable.setState(getDrawableState());
}
if (mMaskDrawable != null && mMaskDrawable.isStateful()) {
mMaskDrawable.setState(getDrawableState());
}
if (isDuplicateParentStateEnabled()) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
public void invalidateDrawable(Drawable who) {
if (who == mBorderDrawable || who == mMaskDrawable) {
invalidate();
} else {
super.invalidateDrawable(who);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mBorderDrawable || who == mMaskDrawable || super.verifyDrawable(who);
}
}
Использование в макете.
<com.google.samples.apps.iosched.ui.widget.BezelImageView
android:id="@+id/session_photo"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/dp"
app:borderDrawable="@drawable/circle_stroke_only"
app:maskDrawable="@drawable/circle_blue" />
circle_blue.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
>
<solid android:color="#00bcd4" />
</shape>
circle_stroke_only.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke android:color="@color/theme_green" android:width="1dp"/>
</shape>
Я провел несколько часов с точно такой же проблемой. Причина, по которой он возвращает одно и то же изображение, не являющееся окружностью, заключается в том, что он сначала передал растровое изображение с не кружком
Из документации RoundedBitmapDrawable:
getBitmap ()
Возвращает растровое изображение, используемое для рисования.
Так что это значит вернуть исходное не преобразованное растровое изображение.
Решение: ничего! Я закончил тем, что использовал большую библиотеку Пикассо-преобразований с CropCircleTransformation()
Пример:
Picasso.with(mContext).load(url)
.transform(new CropCircleTransformation())
.into(holder_image);