1

I was searching for a while right now and I tested a lot of stuff, but nothing works. I have a TextView which should have a gradient fill-color and a stroke (not the background of the Textview but the text itself).

I started by writing a class GradientTextView. At the moment I have a text with gradient fill-color and a shadow (shadow was only a test perhaps I need one later. The stroke is important at the moment). But when I'm trying to add a stroke only the stroke or the gradient fill-color is shown. I tried a lot of stuff, for example the solution from here.

import com.qualcomm.QCARSamples.ImageTargets.R;
import com.qualcomm.QCARSamples.ImageTargets.R.color;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.widget.TextView;

public class GradientTextView extends TextView
{
    public GradientTextView( Context context )
    {
        super( context, null, -1 );
    }
    public GradientTextView( Context context, 
        AttributeSet attrs )
    {
        super( context, attrs, -1 );
    }
    public GradientTextView( Context context, 
        AttributeSet attrs, int defStyle )
    {
        super( context, attrs, defStyle );
    }

int start_gradient = getResources().getColor(R.color.textview_start_gradient);
int end_gradient = getResources().getColor(R.color.textview_end_gradient);
Paint gradientpaint, strokepaint;

@Override
protected void onDraw(Canvas canvas) {
    // draw the shadow
    getPaint().setShadowLayer(10, 1, 1, 0xbf000000); 
    getPaint().setShader(null);
    super.onDraw(canvas);

    // draw the gradient filled text
    getPaint().clearShadowLayer();
    getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), 
        start_gradient, end_gradient, TileMode.CLAMP ) );
        super.onDraw(canvas);
        // **Attempts here**
    }
}

(attempts inserted at "attempts here" comment)

First attempt:

super.onDraw(canvas);   
Paint one = new Paint();
one.setStyle(Style.STROKE);
one.setTextSize(20);
one.setStrokeWidth(5);
setTextColor(Color.BLACK); 
canvas.drawText(VIEW_LOG_TAG, 0, 0, one);

Paint two = new Paint();
two.setStyle(Style.FILL);
two.setTextSize(20);
two.setStrokeWidth(0);
setTextColor(Color.BLUE);
two.setShader(new LinearGradient(0, 0, 0, getHeight(), 
    start_gradient, end_gradient, TileMode.CLAMP ) );
canvas.drawText(VIEW_LOG_TAG, 0, 0, two);

Second attempt:

Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), 
    start_gradient, end_gradient, TileMode.CLAMP ) );
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(32);

super.onDraw(canvas);
Paint mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCenterPaint.setStyle(Paint.Style.STROKE);
mCenterPaint.setColor(Color.GREEN);
mCenterPaint.setStrokeWidth(5);
super.onDraw(canvas);

Third attempt:

gradientpaint = this.getPaint();
gradientpaint.setShader(new LinearGradient(0, 0, 0, getHeight(), 
    start_gradient, end_gradient, TileMode.CLAMP ) );
super.onDraw(canvas);
strokepaint = new Paint(gradientpaint);
strokepaint.setStyle(Paint.Style.STROKE);
strokepaint.setStrokeWidth(30);
strokepaint.setARGB(255, 0, 0, 0);

super.onDraw(canvas);

textview_start_gradient and textview_and_gradient are simply two colors for the gradient.

Each of these lacks either stroke or fill (totally transparent).

How can I do this?

No I tried this:

New Attempt:

// draw the shadow
getPaint().setShadowLayer(10, 6, 6, 0xbf000000); 
getPaint().setShader(null);
super.onDraw(canvas);

// draw the stroke
getPaint().clearShadowLayer();
getPaint().setColor(Color.BLACK);
getPaint().setStyle(Style.STROKE);
getPaint().setStrokeWidth(5);
super.onDraw(canvas);
// draw the gradient filled text
getPaint().setStyle(Style.FILL);
getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), start_gradient, end_gradient, TileMode.CLAMP ));
//getPaint().setStrokeWidth(32);
super.onDraw(canvas);

Funny thing: the shadow, the fill-gradient and the stroke show up! *But the stroke is white (not black). I think the color setting is wrong and because of that it shows up white. Any ideas?

Community
  • 1
  • 1
LauLau
  • 69
  • 1
  • 6
  • What didn't work in your attempts? – bjb568 Jun 05 '14 at 22:28
  • Mostly the stroke simply didn't show up. One time there was a stroke with the given gradient, but no fill-color (transparent). – LauLau Jun 05 '14 at 22:32
  • I'd combine the second attempt's Paint objects into a single one. Avoid setting the text color in the second drawText, or it will cover the gradient. I'd also avoid the double call to super, and move it up, as in the first attempt. – Phantômaxx Jun 06 '14 at 07:30
  • Thanks to @DerGolem! So I tried something like this: `super.onDraw(canvas); Paint mPaint = getPaint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.GREEN); mPaint.setStrokeWidth(5); canvas.drawText(VIEW_LOG_TAG, 0, 0, mPaint); mPaint.setStyle(Paint.Style.FILL); getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), start_gradient, end_gradient, TileMode.CLAMP )); mPaint.setStrokeWidth(32); canvas.drawText(VIEW_LOG_TAG, 0, 0, mPaint);` – LauLau Jun 06 '14 at 08:25
  • ...So now I see my Text I wanted to fill in white (don't now why). This text is in my app at the right/top edge (landsacape-mode). Above this text I get another text with (I think so) the stroke and the fill but I can't see it because it's beyond the view. Probably I'm missing something stupid but I don't know what it could be! Can anyone help? – LauLau Jun 06 '14 at 08:26
  • Something in the z-order of your views in your layout is wrong. There's a View overlapping your custom control. – Phantômaxx Jun 06 '14 at 08:27
  • In my View I have a LinearLayout in which is a space and the TextView: `` – LauLau Jun 06 '14 at 08:30

1 Answers1

5

So after a lot of trying, I solved the problem. Now my TextView has a black stroke, a gradient-fill-color and a shadow.

I'm still having the same GradientTextView.java class, but my solution for the onDraw is:

if(isInEditMode()){

}else{
    start_gradient = getResources().getColor(R.color.textview_start_gradient);
    end_gradient = getResources().getColor(R.color.textview_end_gradient);
}

// draw the shadow
getPaint().setShadowLayer(10, 6, 6, 0xbf000000); 
getPaint().setShader(null);
super.onDraw(canvas);

// draw the stroke
getPaint().clearShadowLayer();
getPaint().setStyle(Style.STROKE);
getPaint().setStrokeWidth(5);
getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), Color.BLACK, Color.BLACK, TileMode.CLAMP ));
super.onDraw(canvas);

// draw the gradient filled text
getPaint().setStyle(Style.FILL);
getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(), start_gradient, end_gradient, TileMode.CLAMP ));
//getPaint().setStrokeWidth(32);
super.onDraw(canvas);

}

The getPaint().setColor(Color.BLACK); didn't worked, so I simply set a Shader with a Gradient in Black (don't know whether this is a nice solution but it works).

In my xml I simply added the class (with package) as xmlns to my top-layout

Something like this

xmlns:gradient="http://schemas.android.com/apk/lib/package-name"

and instead of TextView I wrote:

<package-name.GradientTextView
        android:id="@+id/textView_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|top"
        android:textSize="20sp"
        android:text="@string/main1" />

So thanks for all given help!

Hope this will help someone else!

LauLau
  • 69
  • 1
  • 6
  • Dude, you did great, i did not need the shadow but took the other parts, in other solutions through other posts on stackoverflow, they were calling a function to redraw inside on onDraw which may cause a lot of issues, but your solution of drawing only twice or three times is very good. Thanks man! – JKOU Aug 20 '20 at 08:38