Android как применить маску на ImageView?

поэтому я попробовал код отсюда:создание ImageView с маской. Я использую следующие изображения в качестве оригинала и маски:

enter image description hereenter image description here

однако результат, который я получаю, таков:

enter image description here

обратите внимание, что фон окна не черный, а голографический свет (который на Galaxy nexus выглядит очень бледно-серым, а не полностью белым). Второе изображение-это результат, который я получаю, когда элемент выбран в списке вид.

если вместо этого я создаю новое растровое изображение, используя тот же алгоритм, а затем передаю его в представление изображения вместо переопределения onDraw (), он рисует правильно:

Canvas canvas = new Canvas();
Bitmap mainImage = //get original image
Bitmap maskImage = //get mask image
Bitmap result = Bitmap.createBitmap(mainImage.getWidth(), mainImage.getHeight(), Bitmap.Config.ARGB_8888);

canvas.setBitmap(result);
Paint paint = new Paint();
paint.setFilterBitmap(false);

canvas.drawBitmap(mainImage, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(maskImage, 0, 0, paint);
paint.setXfermode(null);

imageView.setImageBitmap(result);

Я получаю ожидаемый результат:

enter image description here

обратите внимание, что fade применяется правильно. Это более очевидно, когда делается выбор.

Итак, что происходит с методом onDraw ImageView для создания этого черного фона вместо того, чтобы показывать фон окна? Интересно, что если исходное изображение само по себе имеет некоторую прозрачность, эта прозрачность соблюдается, например:

enter image description here

Я не могу понять это сам. Я бы предпочел сделать это на onDraw вместо предварительного создания растрового изображения, потому что он работает только для растровых изображений как источник и маска. Я хочу иметь возможность делать это с другими чертежами, такими как градиенты и сплошные цвета, но в этих случаях ширина и высота не установлены.

3 ответов


Я нашел идеальную комбинацию для создания маскировки без черной границы после исследования всех сообщений stackoverflow. Это вполне соответствует моей цели.

В настоящее время я создаю перетаскиваемый вид, используя одно обычное изображение и маскирующее изображение (png с прозрачностью), поэтому мне нужно переопределить функцию onDraw.

private Bitmap mImage = ...;
private Bitmap mMask = ...;  // png mask with transparency
private int mPosX = 0;
private int mPosY = 0;

private final Paint maskPaint;
private final Paint imagePaint;

public CustomView (final Context context) {
    maskPaint = new Paint();
    maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

    imagePaint = new Paint();
    imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
}

/* TODO
 if you have more constructors, make sure you initialize maskPaint and imagePaint
 Declaring these as final means that all your constructors have to initialize them.
 Failure to do so = your code won't compile.
*/

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();      
    canvas.drawBitmap(mMask, 0, 0, maskPaint);
    canvas.drawBitmap(mImage, mPosX, mPosY, imagePaint);
    canvas.restore();
}

отвечая на мой собственный вопрос. Xfermode работал по назначению. Краска делала полученный холст прозрачным (который был холстом, используемым активностью окна). Поскольку полотно было прозрачным, окно показывало то, что находилось за ним: черный фон.

чтобы сделать это правильно, действительно, новое растровое изображение должно быть создано для хранения результата Альфа-маски. Я обновил код, чтобы учесть все типы drawables.


в этом коде применяется:

 mask_over = BitmapFactory.decodeResource(
            getResources(), mask_over1[0]);
    icon = Bitmap.createScaledBitmap(icon, screenwidth, screenwidth, false);
    mask_over = Bitmap.createScaledBitmap(mask_over, screenwidth, screenwidth, false);
             back_img=createBitmap_ScriptIntrinsicBlur(Bitmap.createScaledBitmap(cropview.croppedImage, screenwidth, screenwidth, false),25.0f);
    LinearLayout.LayoutParams layoutParams111 = new LinearLayout.LayoutParams(screenwidth, screenwidth);