package com.netfluke.sergey.plumbbob; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.ViewGroup; /** * This class draws the projection of a plumb bob on canvas. It assumes Portrait * orientation, hard set on the activity in the Manifest. The y-axis of the * sensor coordinate system is assumed to be parallel to the _long_ side * of the phone, x-axis to the shorter one. * * For allowing Landscape, the code would need to account for the fact that * the sensor coordinate system remains the same no matter how the phone * is flipped, but the screen coordinate system changes on flip. * * For the Canvas/Paint drawing, see * https://developer.android.com/training/custom-views/custom-drawing.html * for a much more elaborate example */ public class Bob extends ViewGroup { RectF bounds; Paint paint, paint1; float cx, cy; // centre of screen float dx, dy; // displacement of bob's center from center float r = 100f; protected void onLayout(boolean changed, int l, int t, int r, int b) { // Do nothing. Do not call the superclass method--that would start a layout pass // on this view's children. PieChart lays out its children in onSizeChanged(). } /* * Needs a constructor. * Class constructor taking only a context. */ public Bob(Context context) { super(context); init(); } /** * Class constructor taking a context and an attribute set. This constructor * is used by the layout engine to construct a {@link Bob} from a set of * XML attributes. Without this, you will get a runtime error about * not being able to create the Bob object from XML. * * @param context * @param attrs An attribute set which can contain attributes from * {@link .R.styleable.Bob} as well as attributes inherited * from {@link android.view.View}. */ public Bob(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { paint = new Paint(); paint.setColor(Color.RED); paint.setAntiAlias(true); paint.setStrokeCap(Paint.Cap.BUTT); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(r/2); paint1 = new Paint(); paint1.setColor(Color.BLUE); paint1.setAntiAlias(true); paint1.setStrokeCap(Paint.Cap.BUTT); paint1.setStyle(Paint.Style.STROKE); paint1.setStrokeWidth(2); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Draw the bob canvas.drawOval(bounds, paint); canvas.drawLine( cx, cy, cx + dx, cy + dy, paint1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.d("SIZE", "w: " + w + " h: " + h + " oldw: " + oldw + " oldh: " + oldh); cx = w/2.0f; cy = h/2.0f; // initial position: dead center bounds = new RectF(cx - r, cy - r, cx + r , cy + r ); Log.d("RECT", "RectF: " + bounds); invalidate(); } // x and y are on the scale from 0 to 10, and measure displacement from center public void repositionBob(float x, float y){ float cm = Math.min( cx, cy ); // must ensure we are drawing with the same factor on X and Y axes dx = - cm * x/10f; // must be negative: gravity vector points down, screen's X grows left-to-write dy = cm * y/10f; // screen's Y grows from the top down, just the direction we want. bounds = new RectF(cx + dx - r, cy + dy - r, cx + dx + r , cy + dy + r ); invalidate(); } }