إخفاء الخريطة القابلة للسحب/النقطة على Android
سؤال
أنا أبحث حاليًا عن طريقة لاستخدام صورة نقطية بالأبيض والأسود لإخفاء قناة ألفا من صورة نقطية أخرى أو قابلة للرسمية على Android. أنا فضولي بشأن ما هي أفضل طريقة للقيام بذلك. لدي بالتأكيد بعض الأفكار حول كيفية القيام بذلك ، لكنها ليست مثالية.
أحتاج إلى أن أكون قادرًا على تطبيق قناع جديد على الصورة في كثير من الأحيان (سيتغير نقطات النقط بالأبيض والأسود كل بضع ثوان).
أي ردود فعل حول كيفية تحقيق ذلك ستكون موضع تقدير كبير.
المحلول
لقد عملت ، لذا فهو شيء من هذا القبيل
// we first same the layer, rectF is the area of interest we plan on drawing
// this will create an offscreen bitmap
canvas.saveLayer(rectF, null, Canvas.MATRIX_SAVE_FLAG
| Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// draw our unmasked stuff
super.draw(canvas);
// We same a layer again but this time we pass a paint object to mask
// the above layer
maskPaint = new Paint()
maskPaint.setColor(0xFFFFFFFF);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.saveLayer(rectF, maskPaint,
Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// we draw the mask which is black and white. In my case
// I have a path, and I use a blurPaint which blurs the mask slightly
// You can do anti aliasing or whatever you which. Just black & white
canvas.drawPath(path, blurPaint);
// We restore twice, this merges the results upward
// as each saveLayer() allocates a new drawing bitmap
canvas.restore();
canvas.restore();
نصائح أخرى
إن حلي قريب من حل @Over_optimistic ، ومكالمة أقل من Savelayer (). أستخدم قناعًا قابل للسحب بدلاً من المسار ، في حالتي كان قرصًا.
أعلنت هذه المتغيرات كحقول (من الممارسات الجيدة تخصيص الذاكرة خارج طريقة Ondraw):
private Paint maskingPaint = new Paint();
private Drawable mask = <insert your drawable here>
ثم ، في مكان ما خارج Ondraw () ، قم بإعداد الكائنات:
// Xfermode won't work if hardware accelerated
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
// Using destination shape as a mask
// For a good explanation of PorterDuff transfer modes : http://ssp.impulsetrain.com/porterduff.html
maskingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
maskingPaint.setAntiAlias(true);
// Position the mask
mask.setBounds(<insert your mask bounds here>);
ثم أخيرًا ، تطبق طريقة OnDraw () القناع:
@Override
protected synchronized void onDraw(Canvas canvas)
{
// Draw the mask first, making it the PorterDuff destination
mask.draw(canvas);
// Save the layer with the masking paint, that will be applied on restore()
// Using CLIP_TO_LAYER_SAVE_FLAG to avoid any overflow of the masked image outside the mask bounds.
Rect bounds = mask.getBounds();
canvas.saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, maskingPaint,
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// Draw the shape offscreen, making it the PorterDuff source
super.onDraw(canvas);
// Apply the source to the destination, using SRC_IN transfer mode
canvas.restore();
}
لفهم أفضل لأوضاع النقل ، أشرت إليها http://ssp.impulsetrain.com/porterduff.html. هذه الصفحة مثيرة للاهتمام للغاية للقراءة. بعد ذلك ، مع نفس النوع من التعليمات البرمجية ، ستتمكن من تحقيق أكثر من قناع بسيط!
لقد صنعت تخطيطًا قابل للإخفاء. إنه framelayout حيث يمكنك تحديد XporterDuffMode والقناع. يمكنك العثور عليها هنا: https://github.com/christophesmet/android_maskable_layout
أنا لست واضحًا تمامًا بشأن ما ستذهب إليه ، لكنني أعتقد أن مزيجًا من BitmapDrawable
و LayerDrawable
قد تعمل. سيتيح لك BitmapDrawable استخدام نقار الصورة النقطية الخاصة بك كقوالب ، وبعد ذلك يمكنك استخدام Layerdrawlable لطبقة القناع فوق آخر يمكن رسمه.
باستخدام مثال XferModes في عرض API ، تمكنت من استخدام PorterDuffXferMode المطبق على كائن الطلاء لمزج خريطة نصور على قماش. هذا يعمل بالضبط كيف أحتاج إليه.