23

I have a layout with some background image and have a button on it. The background color of the button is, say, white. Now I want to write a text on it in such a way that the text displays anything that is behind the button through it (like transparent text). Now, obviously, if I make the text color transparent, the text will disappear and I will be seeing a white button with no text. How to do this?

Screenshot:

button with transparent text

ozbek
  • 20,955
  • 5
  • 61
  • 84
berserk
  • 2,690
  • 3
  • 32
  • 63
  • You can use a TextView and give it a background image. TextViews are clickable as Buttons are. By default, their background is transparent. So, just prepare a png (OK, one for each resolution you're going to support) with the text carved out and you're done. – Phantômaxx May 30 '14 at 14:12
  • 1
    @DerGolem Obviously It will work if I have a png image with transparent text. I want to do it without using any image. Suppose I have 50-60 or even more buttons in my app. I can't have that much images. So, I need a better solution. – berserk May 30 '14 at 14:23
  • As an alternative, you can make a custom control that extends a view and in the onDraw method, it carves out the text from the background fill. – Phantômaxx May 30 '14 at 14:32
  • I don't know how robust the HTML display is in Android as I've never had occasion to use it but I know that you can define HTML/CSS content in Views. So maybe [a solution like this](http://stackoverflow.com/a/22593393/1590950) may work/help you try a different tact. – indivisible May 30 '14 at 14:53
  • @indivisible I guess that in possible only in phonegap. – berserk May 30 '14 at 14:55
  • I really don't know for sure. I do know that you can use basic HTML and some CSS in TextViews, I just don't know how far the support goes. You might be able to incorporate a WebView and use some basic PHP or something to display supplied text using html and css in your assets folder. Again, I'm throwing out ideas that I have no idea are possible. – indivisible May 30 '14 at 14:59
  • @berserk Another possible avenue of research could be that instead of trying to cut away the background or blend the text together with it in some fashion maybe you can use the main background in place of a foreground text colour. So you would have, from back to front, a nice vista background ImageView, a solid colour View, a custom EditText that uses a pattern/image instead of a foreground colour. You would need to calculate (not too exactly though I'd imagine) Which parts of the main background the text overlaps and supply that to your custom TextView. – indivisible May 30 '14 at 15:05
  • @indivisible I don't think it is possible what you mentioned, but even if it is possible, it is not efficient and it has flaws. It is not about just the background of the layout. If the button has some other views behind it, the text must display them too. – berserk May 30 '14 at 15:10
  • Ah, ok. I'll keep it milling around in the back of my head, probably back later with some more implausible suggestions – indivisible May 30 '14 at 15:25

1 Answers1

26

Two ways: (1) not precise solution as text alignment should be coded by hands but:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button view1 = new Button(this);

    RelativeLayout layout1 = (RelativeLayout) findViewById(R.id.layout1);
    layout1.setBackground(getResources().getDrawable(R.drawable.choose_background));

    layout1.addView(view1);

    Bitmap mainImage = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
    {
        //creating image is not necessary, more important is ability to grab the bitmap.
        Canvas canvas = new Canvas(mainImage);
        canvas.drawColor(Color.WHITE);
        view1.setBackground(new BitmapDrawable(getResources(), mainImage));
    }

    {
        Canvas canvas = new Canvas(mainImage);
        //most interesting part:
        Paint eraserPaint = new Paint();
        eraserPaint.setAlpha(0); //this
        eraserPaint.setTextSize(200);
        eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); //and this
        canvas.drawText("some", 10, 150, eraserPaint);
    }
}

the idea of eraserPaint is from here Erase bitmap parts using PorterDuff mode and here Android how to apply mask on ImageView?

in activity_main.xml everything is default:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.runup.myapplication2.app.MainActivity">

and the result is:

enter image description here

(2) Second way is to add this behavior to class in order to use it in xml. https://github.com/togramago/ClearTextViewProject - library project with a sample. You may add as a library or copy only ClearTextView class to your project (as it is an extended TextView without xml resources). works on configuration change and dynamical text and/or background changes.

The result of the sample in portrait: enter image description here

and in landscape: enter image description here

Community
  • 1
  • 1
Margarita Litkevych
  • 2,086
  • 20
  • 28
  • +1 Nice job! But i want a custom view which I can use even in xml. Can you make a custom view using it? – berserk May 31 '14 at 13:20
  • https://gist.github.com/togramago/7dd276789a39205ee407 add it as a class to your project and use in xml as ordinary textview. Although some problems can pop out when you'll try to change it dynamically - but it's a suggestion only. – Margarita Litkevych Jun 02 '14 at 15:39