ImageView со скругленными углами и внутренней тенью

Мне нужно сделать миниатюру с закругленными углами и внутренней тенью. Обычно я делаю рамки ImageView с 9patches, которые до сих пор служили мне хорошо, но на этот раз эффект, который мне нужен, требует рисования внутренней тени поверх изображения (а не только вокруг него). Это привело меня к расширению класса ImageView и переопределению метода onDraw().

public class ThumbnailImageView extends ImageView {

После многих учебников (спасибо StackOverflow!), я закончил с этим кодом для метода onDraw():

@Override
protected void onDraw(Canvas canvas) {
    if (mBitmap == null) {
        return;
    }

    int radius = 4;
    int padding = 2;
    int bleed = 2;
    RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);

    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(0xFF000000);
    canvas.drawRoundRect(frame, radius, radius, mPaint);

    Shader bitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(0xFF000000);
    mPaint.setMaskFilter(new BlurMaskFilter(bleed, Blur.INNER));
    mPaint.setShader(bitmapShader);
    canvas.drawRoundRect(frame, radius, radius, mPaint);
}

То, что я в основном делаю, это сначала рисую черный закругленный прямоугольник, а затем рисую растровое изображение с закругленными углами с затухающими краями (с BlurMaskFilter) поверх него. Результат такой, какой я хочу: onDraw() result Значение mBitmap инициализируется в конструкторе ImageView следующим образом:

mDrawable = getDrawable();
if (mDrawable != null) {
    mBitmap = ((BitmapDrawable) mDrawable).getBitmap();
}

Проблема в том, что я полностью переопределяю onDraw() (не вызывается super.onDraw()), поэтому мне приходится предварительно масштабировать все изображения до желаемого размера миниатюры (например, 96x96), иначе рисуется только верхний левый угол изображения. То, что я хочу иметь возможность сделать, это воспользоваться всеми преимуществами масштабирования, которое делает фреймворк, когда я присваиваю следующие значения xml ThumbnailImageView:

android:id="@+id/thumb"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"

Для этого я подумал, что должен каким-то образом вызвать super.onDraw(), одновременно получая необходимые мне эффекты. Мне удалось получить закругленный прямоугольник, добавив обтравочный контур к холсту, но я не могу найти способ добавить внутреннюю тень. Это новый код onDraw():

@Override
protected void onDraw(Canvas canvas) {
    int radius = 4;
    int padding = 4;        
    RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
    Path clipPath = new Path();
    clipPath.addRoundRect(frame, radius, radius, Path.Direction.CW);
    canvas.clipPath(clipPath);
    super.onDraw(canvas);
    // add inner shadow
}

Я вижу две альтернативы:

1) Чтобы правильно масштабировать растровое изображение ImageView. Но где лучшее место для этого? В своем конструкторе? В методе onDraw(), где фреймворк, кажется, делает это? Является ли фреймворк даже изменением размера любого растрового изображения или есть другой способ нарисовать масштабированное изображение на холсте, не снижая производительности?

2) Чтобы добавить внутренний теневой слой поверх того, что рисует super.onDraw() до сих пор, но у меня заканчиваются идеи о том, как это сделать.

Будем признательны за любую помощь.

Спасибо!

17
задан eeVoskos 27 February 2012 в 17:54
поделиться