Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Développement d'un widget Android
de tracé de courbes

Ce tuto vous montre comment définir un nouveau widget Android permettant l'affichage d'une courbe associée à une fonction mathématiques (ici un sinus et un cosinus).

Codage de la nouvelle classe de Widget

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
package com.infinisoftware.curvetracer;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

public class CurveTracer extends View {

    public static interface Function {
        public double computeValue(double x);
    }

    private Paint paint = new Paint( Paint.ANTI_ALIAS_FLAG );
    private int curveColor = 0xFFFF0000;
    private double xMin = -Math.PI;
    private double xMax =  Math.PI;
    private double stepX = 0.1;

    private double yMin = -1;
    private double yMax =  1;

    private Function function = new Function() {
        @Override public double computeValue(double x) {
            return Math.sin( x );
        }
    };

    public CurveTracer( Context context ) {
        super( context );
        curveColor = getResources().getColor( R.color.curveColor );
    }

    public CurveTracer( Context context, AttributeSet attrSet  ) {
        super( context,attrSet );
        curveColor = getResources().getColor( R.color.curveColor );
    }

    public Function getFunction() {
        return function;
    }

    public void setFunction(Function function) {
        if ( function == null ) throw new NullPointerException();
        this.function = function;
        this.invalidate();
    }

    private int abscisseToPixel( double value ) {
        return (int) (((value - xMin) / (xMax-xMin)) * this.getWidth());
    }

    private int ordonneeToPixel( double value ) {
        return (int) ((1 - ((value - yMin) / (yMax-yMin))) * this.getHeight());
    }

    @Override public void onDraw(Canvas canvas) {
        int oldXPixel = abscisseToPixel( xMin );
        int oldYPixel = ordonneeToPixel( this.function.computeValue(xMin) );

        // Tracé du repère
        paint.setColor(Color.GRAY);
        paint.setStrokeWidth(2);

        canvas.drawLine( abscisseToPixel(xMin), ordonneeToPixel(0),
                abscisseToPixel(xMax), ordonneeToPixel(0), paint );

        canvas.drawLine( abscisseToPixel(0), ordonneeToPixel(yMin),
                abscisseToPixel(0), ordonneeToPixel(yMax), paint );

        paint.setColor( 0xFF000000 );
        paint.setTextSize( getHeight()/30 );

        // Tracé d'un texte
        String label = "0,0";
        Rect bounds = new Rect();
        paint.getTextBounds( label, 0, label.length(), bounds );
        canvas.drawText( label, getWidth()/2 + 10, getHeight()/2 + bounds.height() + 5, paint );

        // Tracé de la courbe
        paint.setColor( this.curveColor );
        paint.setStrokeWidth(3);
        for( double x=xMin; x<=xMax; x+=stepX ) {
            int xPixel = abscisseToPixel( x );
            int yPixel = ordonneeToPixel( this.function.computeValue(x) );

            canvas.drawLine( oldXPixel, oldYPixel, xPixel, yPixel, paint );
            oldXPixel = xPixel;
            oldYPixel = yPixel;
        }
    }

}
Classe d'implémentation de notre Widget CurveTracer.

Intégration du widget dans une activité

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
package com.infinisoftware.curvetracer;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity { 
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        CurveTracer curveView = new CurveTracer( this );
        curveView.setFunction( new CurveTracer.Function() {
            @Override public double computeValue(double x) {
                return Math.cos( x );
            }
        } );
        setContentView( curveView );
    }
    
}
Intégration du widget dans une activité.

Enrichissement de l'interface via une ressource de layout.

Je vous propose maintenant d'enrichir l'interface graphique afin de permettre de choisir la courbe qui doit être dessinée parmis deux choix possibles (sinus ou cosinus). Voici le contenu du fichier res/layout/main_layout.xml.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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=".CurveTracerActivity" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >

        <Button
            android:id="@+id/btnSinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/sinus" />

        <Button
            android:id="@+id/btnCosinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/cosinus" />

    </LinearLayout>

    <com.infinisoftware.curvetracer.CurveTracer
        android:id="@+id/curveTracer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/linearLayout1" />
    
</RelativeLayout>
Fichier res/layout/main_layout.xml

Le code Java suivant permet de charger le layout dans l'activité et fournit les gestionnaires d'événements associées aux deux boutons.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
package com.infinisoftware.curvetracer;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;


public class MainActivity extends Activity { 
    
    private Button btnSinus;
    private Button btnCosinus;
    private CurveTracer curveTracer;
    
    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.main_layout );
        
        btnSinus = (Button) findViewById( R.id.btnSinus );
        btnSinus.setOnClickListener( sinusListener );
        
        btnCosinus = (Button) findViewById( R.id.btnCosinus );
        btnCosinus.setOnClickListener( cosinusListener );

        curveTracer = (CurveView) findViewById( R.id.curveTracer );
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.curve_tracer, menu);
        return true;
    }

    private View.OnClickListener sinusListener = new View.OnClickListener() {
        @Override public void onClick( View v ) {
            curveTracer.setFunction( new CurveTracer.Function() {
                @Override public double computeValue( double x ) {
                    return Math.sin( x );
                }
            });
        }
    };
    
    private View.OnClickListener cosinusListener = new View.OnClickListener() {
        @Override public void onClick( View v ) {
            curveTracer.setFunction( new CurveTracer.Function() {
                @Override public double computeValue( double x ) {
                    return Math.cos( x );
                }
            });
        }
    };

}
Les gestionnaires d'événements.

Affichage du résultat