Reputation: 6958
I need to display a TextView
over a gradient background. The TextView
itself should have a plain white background, and the text should be transparent.
However, setting a transparent color (#00000000) to the text doesn't work: it only shows a white rectangle, the background doesn't show up where the text is (the text takes the same color as the TextView
background).
How can I display a transparent text with a background color on my TextView
?
Upvotes: 12
Views: 10744
Reputation: 537
Base on Gil Vegliach's answer, this's for kotlin that worked, hope can help s.o:
class SeeThroughTextView : AppCompatTextView {
private var mMaskBitmap: Bitmap? = null
private var mMaskCanvas: Canvas? = null
private var mPaint: Paint? = null
private var mBackground: Drawable? = null
private var mBackgroundBitmap: Bitmap? = null
private var mBackgroundCanvas: Canvas? = null
private var mSetBoundsOnSizeAvailable = false
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
init()
}
private fun init() {
mPaint = Paint()
mPaint!!.xfermode = PorterDuffXfermode(Mode.DST_OUT)
super.setTextColor(Color.BLACK)
super.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
@Deprecated("Deprecated in Java")
override fun setBackgroundDrawable(bg: Drawable) {
mBackground = bg
val w = bg.intrinsicWidth
val h = bg.intrinsicHeight
// Drawable has no dimensions, retrieve View's dimensions
if (w == -1 || h == -1) {
mSetBoundsOnSizeAvailable = true
return
}
bg.setBounds(0, 0, w, h)
invalidate()
}
override fun setBackgroundColor(color: Int) {
setBackgroundDrawable(ColorDrawable(color))
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
mBackgroundCanvas = Canvas(mBackgroundBitmap!!)
mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
mMaskCanvas = Canvas(mMaskBitmap!!)
if (mSetBoundsOnSizeAvailable) {
mBackground!!.setBounds(0, 0, w, h)
mSetBoundsOnSizeAvailable = false
}
}
override fun onDraw(canvas: Canvas) {
// Draw background
mBackground?.draw(mBackgroundCanvas!!)
// Draw mask
mMaskCanvas!!.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR)
super.onDraw(mMaskCanvas!!)
mBackgroundCanvas!!.drawBitmap(mMaskBitmap!!, 0f, 0f, mPaint!!)
canvas.drawBitmap(mBackgroundBitmap!!, 0f, 0f, null)
}
}
Upvotes: 0
Reputation: 3562
I made a small library and written a blog post out of this answer, so you don't need to copy and paste code and I do the maintenance for you. :)
Use the view in xml as:
<it.gilvegliach.android.transparenttexttextview.TransparentTextTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/view_bg"
android:text="Hello World" />
Gradle dependency:
compile 'it.gilvegliach.android:transparent-text-textview:1.0.3'
This is how you can achieve that effect:
Here is a simple subclass of TextView
that does that.
final public class SeeThroughTextView extends TextView
{
Bitmap mMaskBitmap;
Canvas mMaskCanvas;
Paint mPaint;
Drawable mBackground;
Bitmap mBackgroundBitmap;
Canvas mBackgroundCanvas;
boolean mSetBoundsOnSizeAvailable = false;
public SeeThroughTextView(Context context)
{
super(context);
mPaint = new Paint();
mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
super.setTextColor(Color.BLACK);
super.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
@Override
@Deprecated
public void setBackgroundDrawable(Drawable bg)
{
mBackground = bg;
int w = bg.getIntrinsicWidth();
int h = bg.getIntrinsicHeight();
// Drawable has no dimensions, retrieve View's dimensions
if (w == -1 || h == -1)
{
w = getWidth();
h = getHeight();
}
// Layout has not run
if (w == 0 || h == 0)
{
mSetBoundsOnSizeAvailable = true;
return;
}
mBackground.setBounds(0, 0, w, h);
invalidate();
}
@Override
public void setBackgroundColor(int color)
{
setBackgroundDrawable(new ColorDrawable(color));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBackgroundCanvas = new Canvas(mBackgroundBitmap);
mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mMaskCanvas = new Canvas(mMaskBitmap);
if (mSetBoundsOnSizeAvailable)
{
mBackground.setBounds(0, 0, w, h);
mSetBoundsOnSizeAvailable = false;
}
}
@Override
protected void onDraw(Canvas canvas)
{
// Draw background
mBackground.draw(mBackgroundCanvas);
// Draw mask
mMaskCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
super.onDraw(mMaskCanvas);
mBackgroundCanvas.drawBitmap(mMaskBitmap, 0.f, 0.f, mPaint);
canvas.drawBitmap(mBackgroundBitmap, 0.f, 0.f, null);
}
}
Example screenshot: indigo pattern for activity background, pink solid fill for TextView background.
This works both for solid color backgrounds and general drawables. Anyway, this is only a BASIC implementation, some feature such as tiling are not supported.
Upvotes: 18
Reputation: 1810
Add this code to your textview tag:
android:background="#07000000"
Upvotes: -2
Reputation: 1610
I have not tried this, but you might be able to do this by (against all documentation advice) getting the TextPaint through TextView.getTextPaint() and call setXferMode(new PorterDuffXferMode(PorterDuff.Mode.MULTIPLY)), in order to clear the alpha bits on the background while rendering.
Otherwise, implement your own text view where you are in full control of the rendering.
Upvotes: 2