Center the text in the circle

android, center, draw, geometry, line

Solution

I'm having a lot of fun with answering this question, here's my last effort:

The first image is just for testing and determinig the empyrical values of the extra padding; the second one is the final product after removing the extra code.

The illusion of circularity is nearly perfect (enough for human eye, I guess)

Here is the modified layout, activity_main.xml:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="#f000"
    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=".MainActivity"
    android:id="@+id/bg"
    >
    <TextView
        android:id="@+id/txt9"
        android:layout_width="160dp"
        android:layout_height="160dp"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="9"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_above="@id/txt9"
        android:layout_alignLeft="@id/txt9"
        android:paddingRight="12dp"
        android:paddingTop="12dp"
        android:gravity="center"
        android:text="1"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt8"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignTop="@id/txt1"
        android:layout_toRightOf="@id/txt1"
        android:paddingLeft="12dp"
        android:paddingTop="12dp"
        android:gravity="center"
        android:text="8"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignTop="@id/txt9"
        android:layout_toLeftOf="@id/txt9"
        android:paddingLeft="12dp"
        android:paddingBottom="12dp"
        android:gravity="center"
        android:text="2"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt3"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_below="@id/txt2"
        android:layout_toLeftOf="@id/txt9"
        android:paddingLeft="12dp"
        android:paddingTop="12dp"
        android:gravity="center"
        android:text="3"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt4"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_below="@id/txt9"
        android:layout_alignLeft="@id/txt9"
        android:paddingRight="12dp"
        android:paddingBottom="12dp"
        android:gravity="center"
        android:text="4"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt5"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignTop="@id/txt4"
        android:layout_toRightOf="@id/txt4"
        android:paddingLeft="12dp"
        android:paddingBottom="12dp"
        android:gravity="center"
        android:text="5"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt7"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignTop="@id/txt9"
        android:layout_toRightOf="@id/txt9"
        android:paddingRight="12dp"
        android:paddingBottom="12dp"
        android:gravity="center"
        android:text="7"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
    <TextView
        android:id="@+id/txt6"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_below="@id/txt7"
        android:layout_toRightOf="@id/txt9"
        android:paddingRight="12dp"
        android:paddingTop="12dp"
        android:gravity="center"
        android:text="6"
        android:textSize="40sp"
        android:textStyle="bold"
        android:textColor="#ffff"
    />
</RelativeLayout>

This is the updated code (you'll get even more optimizations), MainActivity.java

package com.example.numbers;

import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;

public class MainActivity
extends Activity
{

    final Paint pnt = new Paint(Paint.ANTI_ALIAS_FLAG);
    final Random rnd = new Random();

    RelativeLayout rlBG;

    @Override
    protected final void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Make it fullscreen
        // Desactiver la barre de titre de notre application
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // Passer la fenêtre en full-creen == cacher la barre de notification
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);

        rlBG = (RelativeLayout) findViewById(R.id.bg);
        rlBG.setPadding(0, 0, 0, 0);
        final CustomView cv = new CustomView(this);
        rlBG.addView(cv);
        sendViewToBack(cv);
    }

    private static void sendViewToBack(final View v)
    {
        final ViewGroup parent = (ViewGroup)v.getParent();
        if (parent != null)
        {
            parent.removeView(v);
            parent.addView(v, 0);
        }
    }

    private class CustomView extends View
    {
        public CustomView(final Context ctx)
        {
            super(ctx);
        }

        @Override
        protected final void onDraw(final Canvas cnv)
        {
            //
            super.onDraw(cnv);

            // Clear the canvas
            cnv.drawRGB(0, 0, 0);

            // Instance de Paint pour définir l'attribut couleur de notre point,
            // ainsi que sa taille.

            // Nous allons dessiner nos points par rapport à la résolution de
            // l'écran
            final int width = cnv.getWidth(); // Largeur
            final int height = cnv.getHeight(); // Hauteur
            final float rayonDuCercle = (float) (cnv.getWidth() *.5) - 5;
            final float rayonDuCerclePetit = (float) (cnv.getWidth() * .167);

            //
            drawStars(cnv, width, height);

            //
            drawRays(cnv, rayonDuCercle, rayonDuCerclePetit);

            //
            drawCircles(cnv, width, height, rayonDuCercle, rayonDuCerclePetit);
        }

        private final void drawCircles
        (
            final Canvas cnv, final int width, final int height,
            final float rayonDuCercle, final float rayonDuCerclePetit
            )
        {
            //
            // aficchons notre fameux cercle

            pnt.setColor(Color.parseColor("#ffff0000"));
            pnt.setStyle(Style.STROKE);
            pnt.setStrokeWidth(10);
            cnv.drawCircle((float) (cnv.getWidth() * .5),
                (float) (cnv.getHeight() * .5), rayonDuCercle, pnt);
            cnv.drawCircle((float) (cnv.getWidth() * .5),
                (float) (cnv.getHeight() * .5), rayonDuCerclePetit, pnt);

            // ????????????????????????????????????????????????????????????????
            /*
            Random rand = new Random(); //Affichons 100 segments de toutes
            les couleurs for (int i=0; i < 100; i++) { // Affecter une
            couleur de manière aléatoire paint.setARGB(255,
            rand.nextInt(256), rand.nextInt(256), rand.nextInt(256)); //
            Définir l'épaisseur du segment paint.setStrokeWidth
            (rand.nextInt(10)); // Puis dessiner nos points dans le cavenas
            canvas.drawLine(rand.nextInt(iWidth), rand.nextInt(iHeight),
            rand.nextInt(iWidth), rand.nextInt(iHeight), paint); }
             */

            pnt.setARGB(255, rnd.nextInt(256), rnd.nextInt(256),
                rnd.nextInt(256));
            // Définir l'épaisseur du segment
            pnt.setStrokeWidth(2);

            // ????????????????????????????????????????????????????????????????

            // Puis dessiner nos points dans le cavenas
            // okcanvas.drawLine((float)((float)Math.cos(0)*rayonDuCerclePetit)+canvas.getWidth()/2,
            // canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle,
            // canvas.getHeight()/2, paint);
            // okcanvas.drawLine((float)((float)Math.cos(Math.PI/2)*rayonDuCerclePetit)+canvas.getWidth()/2,
            // ((float)Math.sin(Math.PI/2)*rayonDuCerclePetit)+canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle*(float)Math.cos(Math.PI/2),
            // rayonDuCercle*(float)Math.sin(Math.PI/2)+canvas.getHeight()/2,
            // paint);
            // okkk
            // canvas.drawLine((float)((float)Math.cos(Math.PI/4)*rayonDuCerclePetit)+canvas.getWidth()/2,
            // ((float)Math.sin(Math.PI/4)*rayonDuCerclePetit)+canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle*(float)Math.cos(Math.PI/4),
            // rayonDuCercle*(float)Math.sin(Math.PI/4)+canvas.getHeight()/2,
            // paint);

            // initPaint(paint,);
        }

        private final void drawRays
        (
            final Canvas cnv, final float rayonDuCercle,
            final float rayonDuCerclePetit
            )
        {
            // pourquoi j'utilise 2 boucles ? Parce que pour limiter l'espace
            // memoire j'utilise le même canva et la seul difference entre ces
            // deux element est la couleur.
            // cette boucle affiche des rayons
            for (int i = 8; i > -1; --i)
            {
                setRayon(cnv, (Math.PI * .25) * i, pnt, rayonDuCercle,
                    rayonDuCerclePetit);
            }
        }

        private final void drawStars
        (final Canvas cnv, final int width, final int height)
        {
            // j'ai l'impression detre dans les etoiles avec ces petits points
            // Affichons (1/100th of screen size) points de toutes les couleurs
            final int stars = (int) ((width * height) *.01);
            for (int i = stars; i > 0; --i)
            {
                // Affecter une couleur de manière aléatoire
                pnt.setARGB(255, rnd.nextInt(256), rnd.nextInt(256),
                    rnd.nextInt(256));
                // Puis dessiner nos points dans le canevas
                cnv.drawPoint(rnd.nextInt(width), rnd.nextInt(height), pnt);
            }
        }

        /*
         * info pour unen raison que j'ai pas chercher a comprendre l'angle
         * positif s'affiche comme si c'été un ange negatif . Donc je bidouille
         * en multipliant l'angle par -1
         */
        void setRayon
        (
            final Canvas cnv, double angleRad, final Paint pnt,
            final float rayonDuCercle, final float rayonDuCerclePetit
            )
        {
            angleRad = (Math.toRadians(90) + angleRad) * -1;
            cnv.drawLine
            (
                ((float) Math.cos(angleRad) * rayonDuCerclePetit) +
                (float) (cnv.getWidth() * .5),
                ((float) Math.sin(angleRad) * rayonDuCerclePetit) +
                (float) (cnv.getHeight() * .5),
                (float) (cnv.getWidth() * .5) + (rayonDuCercle *
                    (float) Math.cos(angleRad)),
                    (rayonDuCercle * (float) Math.sin(angleRad)) +
                    (float) (cnv.getHeight() * .5), pnt
                );
        }
    }
}

Problem

I have to draw a circle with a number in each piece of my circle. My problem is i can't center the text where i want. Why the center to draw the text is not the same than the center to draw the line ??? sfdzqgs fsdgf dsbfd ds ds fdg sfgnfhggdf wdvfbdfsf dsgfhdr sdgfdshstqrssgqg sqfgshdf dgerfztiaruhis rguhtrqiorgeuqzengoh bçzioqrgethriZQGEHOQRAGIRGOGfjfn fgkjkjvfrejn eofnbfoig vjlj vvjfndbjfdnj figsn ``` /*enter code here * Author : * date : 06/12/2013 * * * enter code here */ package com.example.ando_dessin_test; //merci a http://supertos.free.fr/supertos.php?page=1066 import java.util.Random; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.Style; import android.os.Bundle; import android.view.View; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Desactiver la barre de titre de notre application requestWindowFeature(Window.FEATURE_NO_TITLE); // Passer la fenêtre en full-creen == cacher la barre de notification getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(new RenderView(this)); } // Création d'une classe interne RenderView pour gérer un affichage simple // permettant // de montrer que nous occupons bien tout l'écran class RenderView extends View { public RenderView(Context context) { super(context); } // Dessinons sur la totalité de l'écran protected void onDraw(Canvas canvas) { canvas.drawRGB(0, 0, 0); // Instance de Paint pour définir l'attribut couleur de notre point, // ainsi que // sa taille. Paint paint = new Paint(); // Nous allons dessiner nos points par rapport à la résolution de // l'écran int iWidth = canvas.getWidth(); // Largeur int iHeight = canvas.getHeight(); // Hauteur // float radius = 0;//Radius caused an error so I initialized this // variable Random rand = new Random(); // j'ai l'impression detre dans les etoiles avec ces petits points // Affichons 10000 points de toutes les couleurs for (int i = 0; i < 10000; i++) { // Affecter une couleur de manière aléatoire paint.setARGB(255, rand.nextInt(256), rand.nextInt(256), rand.nextInt(256)); // Puis dessiner nos points dans le canevas canvas.drawPoint(rand.nextInt(iWidth), rand.nextInt(iHeight), paint); } // aficchons notre fameux cercle // Canvas canvas = new Canvas(); Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); circlePaint.setColor(Color.RED); circlePaint.setStyle(Style.STROKE); circlePaint.setStrokeWidth(10); float rayonDuCercle = canvas.getWidth() / 2; canvas.drawCircle((float) canvas.getWidth() / 2, (float) canvas.getHeight() / 2, rayonDuCercle, circlePaint); float rayonDuCerclePetit = canvas.getWidth() / 6; canvas.drawCircle((float) canvas.getWidth() / 2, (float) canvas.getHeight() / 2, rayonDuCerclePetit, circlePaint); /* * // Random rand = new Random(); //Affichons 100 segments de toutes * les couleurs for (int i=0; i < 100; i++) { // Affecter une * couleur de manière aléatoire paint.setARGB(255, * rand.nextInt(256), rand.nextInt(256), rand.nextInt(256)); // * Définir l'épaisseur du segment paint.setStrokeWidth * (rand.nextInt(10)); // Puis dessiner nos points dans le cavenas * canvas.drawLine(rand.nextInt(iWidth), rand.nextInt(iHeight), * rand.nextInt(iWidth), rand.nextInt(iHeight), paint); } */ paint.setARGB(255, rand.nextInt(256), rand.nextInt(256), rand.nextInt(256)); // Définir l'épaisseur du segment paint.setStrokeWidth(2); // Puis dessiner nos points dans le cavenas // okcanvas.drawLine((float)((float)Math.cos(0)*rayonDuCerclePetit)+canvas.getWidth()/2, // canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle, // canvas.getHeight()/2, paint); // okcanvas.drawLine((float)((float)Math.cos(Math.PI/2)*rayonDuCerclePetit)+canvas.getWidth()/2, // ((float)Math.sin(Math.PI/2)*rayonDuCerclePetit)+canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle*(float)Math.cos(Math.PI/2), // rayonDuCercle*(float)Math.sin(Math.PI/2)+canvas.getHeight()/2, // paint); // okkk // canvas.drawLine((float)((float)Math.cos(Math.PI/4)*rayonDuCerclePetit)+canvas.getWidth()/2, // ((float)Math.sin(Math.PI/4)*rayonDuCerclePetit)+canvas.getHeight()/2,canvas.getWidth()/2+rayonDuCercle*(float)Math.cos(Math.PI/4), // rayonDuCercle*(float)Math.sin(Math.PI/4)+canvas.getHeight()/2, // paint); // initPaint(paint,); // pourquoi j'utilise 2 boucles ? Parce que pour limiter l'espace // memoire j'utilise le même canva et la seul difference entre ces // deux element est la couleur. // cette boucle affiche des rayons for (int i = 0; i < 8; i++) { setRayon(canvas, (Math.PI / 4) * i, paint, rayonDuCercle, rayonDuCerclePetit); } paint.setTextAlign(Align.RIGHT); // cette boucle affichage du texte for (int i = 1; i < 9; i++) { setText(canvas, paint, String.valueOf(i), (Math.PI / 4) * i, rayonDuCercle * 0.7, 80); // si je suis le dernier element j'affiche le 9 du centre if (i == 8) { paint.setTextAlign(Align.CENTER); setText(canvas, paint, String.valueOf(i + 1), (Math.PI / 4) * i, rayonDuCercle * 0, 80); } } } /* * info pour unen raison que j'ai pas chercher a comprendre l'angle * positif s'affiche comme si c'été un ange negatif . Donc je bidouille * en multipliant l'angle par -1 */ void setRayon(Canvas canvas, double angleRad, Paint paint, float rayonDuCercle, float rayonDuCerclePetit) { // angleRad=angleRad*-1; angleRad = (Math.toRadians((double) 70) + angleRad) * -1; canvas.drawLine( (float) ((float) Math.cos(angleRad) * rayonDuCerclePetit) + canvas.getWidth() / 2, ((float) Math.sin(angleRad) * rayonDuCerclePetit) + canvas.getHeight() / 2, canvas.getWidth() / 2 + rayonDuCercle * (float) Math.cos(angleRad), rayonDuCercle * (float) Math.sin(angleRad) + canvas.getHeight() / 2, paint); } /* * info pour unen raison que j'ai pas chercher a comprendre l'angle * positif s'affiche comme si c'été un ange negatif . Donc je bidouille * en multipliant l'angle par -1 */ void setText(Canvas canvas, Paint paint, String Txt, double angleRad, double rayonTxt, int sizeText) { paint.setColor(Color.WHITE); paint.setTextSize(sizeText); angleRad = (Math.toRadians((double) 50) + angleRad) * -1; // axe des ordonees enhaut a gauche -> canvas.drawText(Txt, (float) // Math.cos(angleRad)*(float) rayonTxt, // (float)Math.sin(angleRad)*(float) rayonTxt, paint); // ligne suivante j'ai centree l'axe canvas.drawText(Txt, (float) Math.cos(angleRad) * (float) rayonTxt + canvas.getWidth() / 2, (float) Math.sin(angleRad) * (float) rayonTxt + canvas.getHeight() / 2, paint); } /* * private void initPaint(Paint paint, Drawable drawable, float * textHeight, float baselineOffset) { paint = new Paint(); * paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.BLUE); paint * = new Paint(); paint.setStyle(Paint.Style.FILL_AND_STROKE); * paint.setAntiAlias(true); paint.setColor(Color.WHITE); * paint.setTextSize(30); paint.setTextAlign(Align.CENTER); FontMetrics * fontMetrics = paint.getFontMetrics(); baselineOffset = * fontMetrics.bottom; // bottom is the maximum amount that the text * descends // I'm not sure why this is different from descent... * textHeight = fontMetrics.bottom - fontMetrics.top; // drawable = * getResources().getDrawable(R.drawable.ic_launcher); } */ } } ```

Original source