L3n95
L3n95

Reputation: 1615

Android: Draw Custom TextView on Canvas

I have following TextView

public class Cube extends TextView {

Context mContext;

Drawable background;//Hintergrund des Blocks
char mLetter;//Buchstabe des Blocks
int x, y;//Koordinaten des Blocks

@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Cube(Context context, char letter, int _x, int _y) {
    super(context);
    mContext = context;
    mLetter = letter;
    background = ContextCompat.getDrawable(getContext(), R.drawable.cube);
    x = _x;
    y = _y;
    this.setText("" + letter);
    if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
        this.setBackgroundDrawable(background);
    else
        this.setBackground(background);
}

public void drawCube(Canvas canvas){//how to draw now!? This is called from a separate thread in SurfaceView
}

}

If I call following in drawCube():

    background.setBounds(x, y, x + 20, y + 20);
    background.draw(canvas);

it just draws the backgroundDrawable. But how can I draw it with the text/the letter inside? That it looks like this: (The background ist the canvas, the orange and white one is the Background and the "A" is the letter/text)

enter image description here

EDIT: Code at 21.09 This is my (shortened) thread:

public class CanvasThread extends Thread {

private SurfaceHolder mSh;

private ArrayList<Cube> mCubes;

private Canvas mCanvas;
private Context mContext;
private boolean mRun = false;
private boolean mDown = false;
private boolean newCube = false;
public CanvasThread(SurfaceHolder sh, Context context){
    mSh = sh;
    mCubes = new ArrayList<>();
    mContext = context;
}

public void run(){
    while(mRun){
        mCanvas = null;

        try{
            mCanvas = mSh.lockCanvas(null);
            synchronized (mSh){
                mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                newCube = true;
                for(int i = 0; i < mCubes.size(); i++){
                    if(mCubes.get(i).getSpeed() > 0)
                        newCube = false;
                    if(mDown) {
                        if (mCubes.get(i).moveDown(feld)) {
                            mDown = false;
                        }
                    }
                    //mCubes.get(i).invalidate();
                    //mCubes.get(i).requestLayout();
                    mCubes.get(i).draw(mCanvas);
                }
                if(newCube)
                    addCube();
            }
        } finally {
            if(mCanvas != null){
                mSh.unlockCanvasAndPost(mCanvas);
            }
        }
    }
}

public void addCube(){
    Random r = new Random();
    Cube cube = new Cube(mContext, mBuchstaben[r.nextInt(29)], r.nextInt(10), 0, mCanvas);
    mCubes.add(cube);
}

}

This is my (shortened) fragment which uses the canvas/surface view:

public class KlassischFragment extends Fragment implements SurfaceHolder.Callback {

SurfaceHolder sh;
SurfaceView sv;

private CanvasThread thread;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_klassisch, container, false);
    sv = (SurfaceView) view.findViewById(R.id.surfaceView);
    sh = sv.getHolder();
    sh.addCallback(this);
    sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    return view;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    thread = new CanvasThread(sh, getContext());
    thread.setRunnable(true);
    thread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = true;
    //thread.setRunnable(false);

    while(retry){
        try{
            thread.join();
            retry = false;
        } catch(InterruptedException ie){
            //Immer wieder versuchen
        }
        break;
    }
    thread = null;
}

}

Upvotes: 0

Views: 5018

Answers (1)

hoomi
hoomi

Reputation: 1912

Here is an example on how to draw a text on top of a square. Some of the values hardcoded but you should be able to make them dynamic.

public class Cube extends View {

    private final static String TEST_STRING = "ABC";
    private Paint mBackgroundPaint;
    private Paint mTextPaint;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public Cube(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    public Cube(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public Cube(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public Cube(Context context) {
        this(context, null, -1);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Just for demo purposes this should be calculated properly
        int desiredWidth = 100;
        int desiredHeight = 100;

        setMeasuredDimension(desiredWidth, desiredHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int savedCount = canvas.save();
        drawRectangle(canvas);
        drawText(canvas);
        canvas.restoreToCount(savedCount);
    }

    private void init() {
        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setColor(Color.BLUE);
        mBackgroundPaint.setStyle(Paint.Style.FILL);

        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        // This need to be adjusted based on the requirements that you have
        mTextPaint.setTextSize(20.0f);

    }

    private void drawRectangle(Canvas canvas) {
        canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint);
    }

    private void drawText(Canvas canvas) {
        Rect rect = new Rect();
        // For simplicity I am using a hardcoded string
        mTextPaint.getTextBounds(TEST_STRING, 0, 1, rect);
        int w = getWidth(), h = getHeight();
        float x = (w - rect.width()) / 2, y = ((h - rect.height()) / 2) + rect.height();
        canvas.drawText(TEST_STRING, 0, 1, x, y, mTextPaint);


    }
}

Upvotes: 1

Related Questions