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).
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; } } } |
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 ); } } |
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> |
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 ); } }); } }; } |
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 :