Android Tutorial - 2D Graphics : example 1
Arcs
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint[] mPaints; private Paint mFramePaint; private boolean[] mUseCenters; private RectF[] mOvals; private RectF mBigOval; private float mStart; private float mSweep; private int mBigIndex; private static final float SWEEP_INC = 2; private static final float START_INC = 15; public SampleView(Context context) { super(context); mPaints = new Paint[4]; mUseCenters = new boolean[4]; mOvals = new RectF[4]; mPaints[0] = new Paint(); mPaints[0].setAntiAlias(true); mPaints[0].setStyle(Paint.Style.FILL); mPaints[0].setColor(0x88FF0000); mUseCenters[0] = false; mPaints[1] = new Paint(mPaints[0]); mPaints[1].setColor(0x8800FF00); mUseCenters[1] = true; mPaints[2] = new Paint(mPaints[0]); mPaints[2].setStyle(Paint.Style.STROKE); mPaints[2].setStrokeWidth(4); mPaints[2].setColor(0x880000FF); mUseCenters[2] = false; mPaints[3] = new Paint(mPaints[2]); mPaints[3].setColor(0x88888888); mUseCenters[3] = true; mBigOval = new RectF(40, 10, 280, 250); mOvals[0] = new RectF( 10, 270, 70, 330); mOvals[1] = new RectF( 90, 270, 150, 330); mOvals[2] = new RectF(170, 270, 230, 330); mOvals[3] = new RectF(250, 270, 310, 330); mFramePaint = new Paint(); mFramePaint.setAntiAlias(true); mFramePaint.setStyle(Paint.Style.STROKE); mFramePaint.setStrokeWidth(0); } private void drawArcs(Canvas canvas, RectF oval, boolean useCenter, Paint paint) { canvas.drawRect(oval, mFramePaint); canvas.drawArc(oval, mStart, mSweep, useCenter, paint); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); drawArcs(canvas, mBigOval, mUseCenters[mBigIndex], mPaints[mBigIndex]); for (int i = 0; i < 4; i++) { drawArcs(canvas, mOvals[i], mUseCenters[i], mPaints[i]); } mSweep += SWEEP_INC; if (mSweep > 360) { mSweep -= 360; mStart += START_INC; if (mStart >= 360) { mStart -= 360; } mBigIndex = (mBigIndex + 1) % mOvals.length; } invalidate(); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth()/2; int y = getHeight()/2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Clipping Demo
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint mPaint; private Path mPath; public SampleView(Context context) { super(context); setFocusable(true); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(6); mPaint.setTextSize(16); mPaint.setTextAlign(Paint.Align.RIGHT); mPath = new Path(); } private void drawScene(Canvas canvas) { canvas.clipRect(0, 0, 100, 100); canvas.drawColor(Color.WHITE); mPaint.setColor(Color.RED); canvas.drawLine(0, 0, 100, 100, mPaint); mPaint.setColor(Color.GREEN); canvas.drawCircle(30, 70, 30, mPaint); mPaint.setColor(Color.BLUE); canvas.drawText("Clipping", 100, 30, mPaint); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.GRAY); canvas.save(); canvas.translate(10, 10); drawScene(canvas); canvas.restore(); canvas.save(); canvas.translate(160, 10); canvas.clipRect(10, 10, 90, 90); canvas.clipRect(30, 30, 70, 70, Region.Op.DIFFERENCE); drawScene(canvas); canvas.restore(); canvas.save(); canvas.translate(10, 160); mPath.reset(); canvas.clipPath(mPath); // makes the clip empty mPath.addCircle(50, 50, 50, Path.Direction.CCW); canvas.clipPath(mPath, Region.Op.REPLACE); drawScene(canvas); canvas.restore(); canvas.save(); canvas.translate(160, 160); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.UNION); drawScene(canvas); canvas.restore(); canvas.save(); canvas.translate(10, 310); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.XOR); drawScene(canvas); canvas.restore(); canvas.save(); canvas.translate(160, 310); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.REVERSE_DIFFERENCE); drawScene(canvas); canvas.restore(); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Draw animated gif
package app.test; import java.io.ByteArrayOutputStream; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Movie; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Bitmap mBitmap; private Bitmap mBitmap2; private Bitmap mBitmap3; private Bitmap mBitmap4; private Drawable mDrawable; private Movie mMovie; private long mMovieStart; // Set to false to use decodeByteArray private static final boolean DECODE_STREAM = true; private static byte[] streamToBytes(InputStream is) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); byte[] buffer = new byte[1024]; int len; try { while ((len = is.read(buffer)) >= 0) { os.write(buffer, 0, len); } } catch (java.io.IOException e) { } return os.toByteArray(); } public SampleView(Context context) { super(context); setFocusable(true); java.io.InputStream is; is = context.getResources().openRawResource(R.drawable.icon); BitmapFactory.Options opts = new BitmapFactory.Options(); Bitmap bm; opts.inJustDecodeBounds = true; bm = BitmapFactory.decodeStream(is, null, opts); // now opts.outWidth and opts.outHeight are the dimension of the // bitmap, even though bm is null opts.inJustDecodeBounds = false; // this will request the bm opts.inSampleSize = 4; // scaled down by 4 bm = BitmapFactory.decodeStream(is, null, opts); mBitmap = bm; // decode an image with transparency is = context.getResources().openRawResource(R.drawable.icon); mBitmap2 = BitmapFactory.decodeStream(is); // create a deep copy of it using getPixels() into different configs int w = mBitmap2.getWidth(); int h = mBitmap2.getHeight(); int[] pixels = new int[w * h]; mBitmap2.getPixels(pixels, 0, w, 0, 0, w, h); mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888); mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444); mDrawable = context.getResources().getDrawable(R.drawable.icon); mDrawable.setBounds(150, 20, 300, 100); is = context.getResources().openRawResource(R.drawable.animated_gif); if (DECODE_STREAM) { mMovie = Movie.decodeStream(is); } else { byte[] array = streamToBytes(is); mMovie = Movie.decodeByteArray(array, 0, array.length); } } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFCCCCCC); Paint p = new Paint(); p.setAntiAlias(true); canvas.drawBitmap(mBitmap, 10, 10, null); canvas.drawBitmap(mBitmap2, 10, 170, null); canvas.drawBitmap(mBitmap3, 110, 170, null); canvas.drawBitmap(mBitmap4, 210, 170, null); mDrawable.draw(canvas); long now = android.os.SystemClock.uptimeMillis(); if (mMovieStart == 0) { // first time mMovieStart = now; } if (mMovie != null) { int dur = mMovie.duration(); if (dur == 0) { dur = 1000; } int relTime = (int) ((now - mMovieStart) % dur); mMovie.setTime(relTime); mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height()); invalidate(); } } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Paint
Paint.ANTI_ALIAS_FLAG
package app.Test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Path.Direction; import android.os.Bundle; import android.view.View; public class appTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GraphicsView(this)); } static public class GraphicsView extends View { private static final String QUOTE = "This is a test. This is a demo."; private Path circle; private Paint cPaint; private Paint tPaint; public GraphicsView(Context context) { super(context); int color = Color.BLUE; circle = new Path(); circle.addCircle(150, 150, 100, Direction.CW); cPaint = new Paint(Paint.ANTI_ALIAS_FLAG); cPaint.setStyle(Paint.Style.STROKE); cPaint.setColor(Color.LTGRAY); cPaint.setStrokeWidth(3); setBackgroundResource(R.drawable.icon); } @Override protected void onDraw(Canvas canvas) { canvas.drawPath(circle, cPaint); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/icon"> <org.example.graphics.Graphics.GraphicsView android:id="@+id/graphics" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> //strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Graphics</string> </resources> //colors.xml <?xml version="1.0" encoding="utf-8"?> <resources> <color name="mycolor">#7fff00ff</color> </resources>
Paint.Style.STROKE
package app.Test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Path.Direction; import android.os.Bundle; import android.view.View; public class appTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GraphicsView(this)); } static public class GraphicsView extends View { private static final String QUOTE = "This is a test. This is a demo."; private Path circle; private Paint cPaint; private Paint tPaint; public GraphicsView(Context context) { super(context); int color = Color.BLUE; circle = new Path(); circle.addCircle(150, 150, 100, Direction.CW); cPaint = new Paint(Paint.ANTI_ALIAS_FLAG); cPaint.setStyle(Paint.Style.STROKE); cPaint.setColor(Color.LTGRAY); cPaint.setStrokeWidth(3); setBackgroundResource(R.drawable.icon); } @Override protected void onDraw(Canvas canvas) { canvas.drawPath(circle, cPaint); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/icon"> <org.example.graphics.Graphics.GraphicsView android:id="@+id/graphics" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> //strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Graphics</string> </resources> //colors.xml <?xml version="1.0" encoding="utf-8"?> <resources> <color name="mycolor">#7fff00ff</color> </resources>
Finger Paint
package app.test; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.EmbossMaskFilter; import android.graphics.MaskFilter; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity implements ColorPickerDialog.OnColorChangedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(0xFFFF0000); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(12); mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL); } private Paint mPaint; private MaskFilter mEmboss; private MaskFilter mBlur; public void colorChanged(int color) { mPaint.setColor(color); } public class MyView extends View { private static final float MINP = 0.25f; private static final float MAXP = 0.75f; private Bitmap mBitmap; private Canvas mCanvas; private Path mPath; private Paint mBitmapPaint; public MyView(Context c) { super(c); mPath = new Path(); mBitmapPaint = new Paint(Paint.DITHER_FLAG); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFAAAAAA); canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); canvas.drawPath(mPath, mPaint); } private float mX, mY; private static final float TOUCH_TOLERANCE = 4; private void touch_start(float x, float y) { mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touch_move(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touch_up() { mPath.lineTo(mX, mY); // commit the path to our offscreen mCanvas.drawPath(mPath, mPaint); // kill this so we don't double draw mPath.reset(); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touch_start(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); invalidate(); break; } return true; } } private static final int COLOR_MENU_ID = Menu.FIRST; private static final int EMBOSS_MENU_ID = Menu.FIRST + 1; private static final int BLUR_MENU_ID = Menu.FIRST + 2; private static final int ERASE_MENU_ID = Menu.FIRST + 3; private static final int SRCATOP_MENU_ID = Menu.FIRST + 4; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c'); menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's'); menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z'); menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z'); menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z'); /**** * Is this the mechanism to extend with filter effects? Intent intent = * new Intent(null, getIntent().getData()); * intent.addCategory(Intent.CATEGORY_ALTERNATIVE); * menu.addIntentOptions( Menu.ALTERNATIVE, 0, new ComponentName(this, * NotesList.class), null, intent, 0, null); *****/ return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { mPaint.setXfermode(null); mPaint.setAlpha(0xFF); switch (item.getItemId()) { case COLOR_MENU_ID: new ColorPickerDialog(this, this, mPaint.getColor()).show(); return true; case EMBOSS_MENU_ID: if (mPaint.getMaskFilter() != mEmboss) { mPaint.setMaskFilter(mEmboss); } else { mPaint.setMaskFilter(null); } return true; case BLUR_MENU_ID: if (mPaint.getMaskFilter() != mBlur) { mPaint.setMaskFilter(mBlur); } else { mPaint.setMaskFilter(null); } return true; case ERASE_MENU_ID: mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); return true; case SRCATOP_MENU_ID: mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); mPaint.setAlpha(0x80); return true; } return super.onOptionsItemSelected(item); } } class ColorPickerDialog extends Dialog { public interface OnColorChangedListener { void colorChanged(int color); } private OnColorChangedListener mListener; private int mInitialColor; private static class ColorPickerView extends View { private Paint mPaint; private Paint mCenterPaint; private final int[] mColors; private OnColorChangedListener mListener; ColorPickerView(Context c, OnColorChangedListener l, int color) { super(c); mListener = l; mColors = new int[] { 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000 }; Shader s = new SweepGradient(0, 0, mColors, null); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setShader(s); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(32); mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCenterPaint.setColor(color); mCenterPaint.setStrokeWidth(5); } private boolean mTrackingCenter; private boolean mHighlightCenter; @Override protected void onDraw(Canvas canvas) { float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f; canvas.translate(CENTER_X, CENTER_X); canvas.drawOval(new RectF(-r, -r, r, r), mPaint); canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint); if (mTrackingCenter) { int c = mCenterPaint.getColor(); mCenterPaint.setStyle(Paint.Style.STROKE); if (mHighlightCenter) { mCenterPaint.setAlpha(0xFF); } else { mCenterPaint.setAlpha(0x80); } canvas.drawCircle(0, 0, CENTER_RADIUS + mCenterPaint.getStrokeWidth(), mCenterPaint); mCenterPaint.setStyle(Paint.Style.FILL); mCenterPaint.setColor(c); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(CENTER_X * 2, CENTER_Y * 2); } private static final int CENTER_X = 100; private static final int CENTER_Y = 100; private static final int CENTER_RADIUS = 32; private int floatToByte(float x) { int n = java.lang.Math.round(x); return n; } private int pinToByte(int n) { if (n < 0) { n = 0; } else if (n > 255) { n = 255; } return n; } private int ave(int s, int d, float p) { return s + java.lang.Math.round(p * (d - s)); } private int interpColor(int colors[], float unit) { if (unit <= 0) { return colors[0]; } if (unit >= 1) { return colors[colors.length - 1]; } float p = unit * (colors.length - 1); int i = (int) p; p -= i; // now p is just the fractional part [0...1) and i is the index int c0 = colors[i]; int c1 = colors[i + 1]; int a = ave(Color.alpha(c0), Color.alpha(c1), p); int r = ave(Color.red(c0), Color.red(c1), p); int g = ave(Color.green(c0), Color.green(c1), p); int b = ave(Color.blue(c0), Color.blue(c1), p); return Color.argb(a, r, g, b); } private int rotateColor(int color, float rad) { float deg = rad * 180 / 3.1415927f; int r = Color.red(color); int g = Color.green(color); int b = Color.blue(color); ColorMatrix cm = new ColorMatrix(); ColorMatrix tmp = new ColorMatrix(); cm.setRGB2YUV(); tmp.setRotate(0, deg); cm.postConcat(tmp); tmp.setYUV2RGB(); cm.postConcat(tmp); final float[] a = cm.getArray(); int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b); int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b); int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b); return Color.argb(Color.alpha(color), pinToByte(ir), pinToByte(ig), pinToByte(ib)); } private static final float PI = 3.1415926f; @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX() - CENTER_X; float y = event.getY() - CENTER_Y; boolean inCenter = java.lang.Math.sqrt(x * x + y * y) <= CENTER_RADIUS; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mTrackingCenter = inCenter; if (inCenter) { mHighlightCenter = true; invalidate(); break; } case MotionEvent.ACTION_MOVE: if (mTrackingCenter) { if (mHighlightCenter != inCenter) { mHighlightCenter = inCenter; invalidate(); } } else { float angle = (float) java.lang.Math.atan2(y, x); // need to turn angle [-PI ... PI] into unit [0....1] float unit = angle / (2 * PI); if (unit < 0) { unit += 1; } mCenterPaint.setColor(interpColor(mColors, unit)); invalidate(); } break; case MotionEvent.ACTION_UP: if (mTrackingCenter) { if (inCenter) { mListener.colorChanged(mCenterPaint.getColor()); } mTrackingCenter = false; // so we draw w/o halo invalidate(); } break; } return true; } } public ColorPickerDialog(Context context, OnColorChangedListener listener, int initialColor) { super(context); mListener = listener; mInitialColor = initialColor; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OnColorChangedListener l = new OnColorChangedListener() { public void colorChanged(int color) { mListener.colorChanged(color); dismiss(); } }; setContentView(new ColorPickerView(getContext(), l, mInitialColor)); setTitle("Pick a Color"); } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Finger Paint View
//package com.aflyroc.doodle.view; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.Paint.FontMetrics; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; import android.view.View; public class FingerPaintView extends View { Path path; Bitmap bitmapBuff; Paint paint; Paint pen; Canvas canvas; Bitmap originBitmap; Bitmap pureBitmp; private float scaleWidth; private float scaleHeight; private float mX,mY; private static float TOUCH_TOLERANCE = 4; private Canvas printCanvas; Bitmap printBitmapBuff; private List<Path> pathList; int i = 0; public FingerPaintView(Context context, AttributeSet attrs) { super(context, attrs); loadBitmap(context); Log.i("Context context, AttributeSet attrs", "11"); } public FingerPaintView(Context context) { super(context); loadBitmap(context); Log.i("Context context", "222"); } public void loadBitmap(Context context) { pathList = new ArrayList<Path>(); path = new Path(); paint = new Paint(); paint.setAntiAlias(true); paint.setDither(true); paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); paint.setStrokeCap(Paint.Cap.ROUND); paint.setStrokeWidth(1.6f); InputStream stream = null;//getResources().openRawResource(drawable.precheck); originBitmap = BitmapFactory.decodeStream(stream); int width = originBitmap.getWidth(); int height = originBitmap.getHeight(); DisplayMetrics metrics = context.getApplicationContext().getResources().getDisplayMetrics(); int newWidth = metrics.widthPixels; int newHeight = metrics.heightPixels; // scaleWidth = ((float) newWidth / width); scaleHeight = ((float) newHeight / height); Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); pureBitmp = Bitmap.createBitmap(originBitmap, 0, 0, width, height,matrix, true); bitmapBuff = Bitmap.createBitmap(pureBitmp.getWidth(),pureBitmp.getHeight(), Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmapBuff); canvas.drawBitmap(pureBitmp, 0, 0, paint); } public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchStart(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touchMove(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touchUp(x, y); invalidate(); break; } return true; } protected void onDraw(Canvas canvas) { super.onDraw(canvas); // canvas.drawBitmap(bitmapBuff, 0, 0, paint); // canvas.drawPath(path, paint); } private void touchStart(float x, float y) { path.reset(); path.moveTo(x, y); mX = x; mY=y; } private void touchMove(float x,float y) { float dx = Math.abs(x-mX); float dy = Math.abs(y-mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); mX = x; mY = y; } } private void touchUp(float x,float y) { pathList.add(new Path(path)); canvas.drawPath(path,paint); path.reset(); } public void createPrintCanvas() { Bitmap printBitmap = Bitmap.createBitmap(originBitmap); printBitmapBuff = Bitmap.createBitmap(printBitmap.getWidth(),printBitmap.getHeight(), Bitmap.Config.ARGB_8888); Matrix matrix = new Matrix(); matrix.postScale(1/scaleWidth, 1/scaleHeight); printCanvas = new Canvas(printBitmapBuff); printCanvas.drawBitmap(printBitmap, 0, 0, paint); for(int i=0;i<pathList.size();i++) { Path tempPath = new Path(pathList.get(i)); tempPath.transform(matrix); printCanvas.drawPath(tempPath, paint); Log.d("path", tempPath.toString()); } printCanvas.save(); } public float getScaleWidth() { return scaleWidth; } public float getScaleHeight() { return scaleHeight; } }
Point
Draw a point
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStrokeWidth(100); canvas.drawPoint(199, 201, paint); } }
Draw Points
package app.test; import java.io.ByteArrayOutputStream; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint mPaint = new Paint(); private float[] mPts; private static final float SIZE = 300; private static final int SEGS = 32; private static final int X = 0; private static final int Y = 1; private void buildPoints() { final int ptCount = (SEGS + 1) * 2; mPts = new float[ptCount * 2]; float value = 0; final float delta = SIZE / SEGS; for (int i = 0; i <= SEGS; i++) { mPts[i*4 + X] = SIZE - value; mPts[i*4 + Y] = 0; mPts[i*4 + X + 2] = 0; mPts[i*4 + Y + 2] = value; value += delta; } } public SampleView(Context context) { super(context); buildPoints(); } @Override protected void onDraw(Canvas canvas) { Paint paint = mPaint; canvas.translate(10, 10); canvas.drawColor(Color.WHITE); paint.setColor(Color.RED); paint.setStrokeWidth(0); canvas.drawLines(mPts, paint); paint.setColor(Color.BLUE); paint.setStrokeWidth(3); canvas.drawPoints(mPts, paint); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
PorterDuffXfermode
new PorterDuffXfermode(PorterDuff.Mode.SRC)
package app.test; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Bitmap mBitmap; private Bitmap mBitmap2; private Bitmap mBitmap3; private Shader mShader; private static void drawIntoBitmap(Bitmap bm) { float x = bm.getWidth(); float y = bm.getHeight(); Canvas c = new Canvas(bm); Paint p = new Paint(); p.setAntiAlias(true); p.setAlpha(0x80); c.drawCircle(x/2, y/2, x/2, p); p.setAlpha(0x30); p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); p.setTextSize(60); p.setTextAlign(Paint.Align.CENTER); Paint.FontMetrics fm = p.getFontMetrics(); c.drawText("Alpha", x/2, (y-fm.ascent)/2, p); } public SampleView(Context context) { super(context); setFocusable(true); InputStream is = context.getResources().openRawResource(R.drawable.icon); mBitmap = BitmapFactory.decodeStream(is); mBitmap2 = mBitmap.extractAlpha(); mBitmap3 = Bitmap.createBitmap(200, 200, Bitmap.Config.ALPHA_8); drawIntoBitmap(mBitmap3); mShader = new LinearGradient(0, 0, 100, 70, new int[] { Color.RED, Color.GREEN, Color.BLUE }, null, Shader.TileMode.MIRROR); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); Paint p = new Paint(); float y = 10; p.setColor(Color.RED); canvas.drawBitmap(mBitmap, 10, y, p); y += mBitmap.getHeight() + 10; canvas.drawBitmap(mBitmap2, 10, y, p); y += mBitmap2.getHeight() + 10; p.setShader(mShader); canvas.drawBitmap(mBitmap3, 10, y, p); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth()/2; int y = getHeight()/2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Using PorterDuffXfermode
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.Xfermode; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Xfermodes extends GraphicsActivity { // create a bitmap with a circle, used for the "dst" image static Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p); return bm; } // create a bitmap with a rect, used for the "src" image static Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p); return bm; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private static final int W = 64; private static final int H = 64; private static final int ROW_MAX = 4; // number of samples per row private Bitmap mSrcB; private Bitmap mDstB; private Shader mBG; // background checker-board pattern private static final Xfermode[] sModes = { new PorterDuffXfermode(PorterDuff.Mode.CLEAR), new PorterDuffXfermode(PorterDuff.Mode.SRC), new PorterDuffXfermode(PorterDuff.Mode.DST), new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER), new PorterDuffXfermode(PorterDuff.Mode.DST_OVER), new PorterDuffXfermode(PorterDuff.Mode.SRC_IN), new PorterDuffXfermode(PorterDuff.Mode.DST_IN), new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT), new PorterDuffXfermode(PorterDuff.Mode.DST_OUT), new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP), new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP), new PorterDuffXfermode(PorterDuff.Mode.XOR), new PorterDuffXfermode(PorterDuff.Mode.DARKEN), new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN), new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY), new PorterDuffXfermode(PorterDuff.Mode.SCREEN) }; private static final String[] sLabels = { "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn", "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Darken", "Lighten", "Multiply", "Screen" }; public SampleView(Context context) { super(context); mSrcB = makeSrc(W, H); mDstB = makeDst(W, H); // make a ckeckerboard pattern Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF }, 2, 2, Bitmap.Config.RGB_565); mBG = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); Matrix m = new Matrix(); m.setScale(6, 6); mBG.setLocalMatrix(m); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG); labelP.setTextAlign(Paint.Align.CENTER); Paint paint = new Paint(); paint.setFilterBitmap(false); canvas.translate(15, 35); int x = 0; int y = 0; for (int i = 0; i < sModes.length; i++) { // draw the border paint.setStyle(Paint.Style.STROKE); paint.setShader(null); canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint); // draw the checker-board pattern paint.setStyle(Paint.Style.FILL); paint.setShader(mBG); canvas.drawRect(x, y, x + W, y + H, paint); // draw the src/dst example into our offscreen bitmap int sc = canvas.saveLayer(x, y, x + W, y + H, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); canvas.translate(x, y); canvas.drawBitmap(mDstB, 0, 0, paint); paint.setXfermode(sModes[i]); canvas.drawBitmap(mSrcB, 0, 0, paint); paint.setXfermode(null); canvas.restoreToCount(sc); // draw the label canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP); x += W + 10; // wrap around when we've drawn enough for one row if ((i % ROW_MAX) == ROW_MAX - 1) { x = 0; y += H + 30; } } } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Region
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.Region; import android.graphics.RegionIterator; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private final Paint mPaint = new Paint(); private final Rect mRect1 = new Rect(); private final Rect mRect2 = new Rect(); public SampleView(Context context) { super(context); setFocusable(true); mPaint.setAntiAlias(true); mPaint.setTextSize(16); mPaint.setTextAlign(Paint.Align.CENTER); mRect1.set(10, 10, 100, 80); mRect2.set(50, 50, 130, 110); } private void drawOriginalRects(Canvas canvas, int alpha) { mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.RED); mPaint.setAlpha(alpha); drawCentered(canvas, mRect1, mPaint); mPaint.setColor(Color.BLUE); mPaint.setAlpha(alpha); drawCentered(canvas, mRect2, mPaint); // restore style mPaint.setStyle(Paint.Style.FILL); } private void drawRgn(Canvas canvas, int color, String str, Region.Op op) { if (str != null) { mPaint.setColor(Color.BLACK); canvas.drawText(str, 80, 24, mPaint); } Region rgn = new Region(); rgn.set(mRect1); rgn.op(mRect2, op); mPaint.setColor(color); RegionIterator iter = new RegionIterator(rgn); Rect r = new Rect(); canvas.translate(0, 30); mPaint.setColor(color); while (iter.next(r)) { canvas.drawRect(r, mPaint); } drawOriginalRects(canvas, 0x80); } private static void drawCentered(Canvas c, Rect r, Paint p) { float inset = p.getStrokeWidth() * 0.5f; if (inset == 0) { // catch hairlines inset = 0.5f; } c.drawRect(r.left + inset, r.top + inset, r.right - inset, r.bottom - inset, p); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.GRAY); canvas.save(); canvas.translate(80, 5); drawOriginalRects(canvas, 0xFF); canvas.restore(); mPaint.setStyle(Paint.Style.FILL); canvas.save(); canvas.translate(0, 140); drawRgn(canvas, Color.RED, "Union", Region.Op.UNION); canvas.restore(); canvas.save(); canvas.translate(0, 280); drawRgn(canvas, Color.BLUE, "Xor", Region.Op.XOR); canvas.restore(); canvas.save(); canvas.translate(160, 140); drawRgn(canvas, Color.GREEN, "Difference", Region.Op.DIFFERENCE); canvas.restore(); canvas.save(); canvas.translate(160, 280); drawRgn(canvas, Color.WHITE, "Intersect", Region.Op.INTERSECT); canvas.restore(); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Stroke
Set Stroke Width
package app.Test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Path.Direction; import android.os.Bundle; import android.view.View; public class appTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GraphicsView(this)); } static public class GraphicsView extends View { private static final String QUOTE = "This is a test. This is a demo."; private Path circle; private Paint cPaint; private Paint tPaint; public GraphicsView(Context context) { super(context); int color = Color.BLUE; circle = new Path(); circle.addCircle(150, 150, 100, Direction.CW); cPaint = new Paint(Paint.ANTI_ALIAS_FLAG); cPaint.setStyle(Paint.Style.STROKE); cPaint.setColor(Color.LTGRAY); cPaint.setStrokeWidth(3); setBackgroundResource(R.drawable.icon); } @Override protected void onDraw(Canvas canvas) { canvas.drawPath(circle, cPaint); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/icon"> <org.example.graphics.Graphics.GraphicsView android:id="@+id/graphics" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> //strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Graphics</string> </resources> //colors.xml <?xml version="1.0" encoding="utf-8"?> <resources> <color name="mycolor">#7fff00ff</color> </resources>
Set stroke size
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStrokeWidth(100); canvas.drawPoint(199, 201, paint); } }
Thumbnail
//package com.birbeck.wallpaperslideshow; import android.graphics.Bitmap; class ThumbnailUtilsWrapper { static { try { Class.forName("android.media.ThumbnailUtils"); } catch (Exception e) { throw new RuntimeException(e); } } public static void checkAvailable() { } public static Bitmap extractThumbnail(final Bitmap source, final int width, final int height) { return android.media.ThumbnailUtils.extractThumbnail(source, width, height, android.media.ThumbnailUtils.OPTIONS_RECYCLE_INPUT); } }
Circle
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // Circle Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.STROKE); float x = 50; float y = 50; float radius = 20; canvas.drawCircle(x, y, radius, paint); } }
Line
Draw a line
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // Line Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStrokeWidth(10); int startx = 50; int starty = 100; int endx = 150; int endy = 210; canvas.drawLine(startx, starty, endx, endy, paint); } }
Smooth Line
// Created by plusminus on 13:24:05 - 21.09.2008 //package org.andnav2.osm.util; import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; class Util { public static final String DEBUGTAG = "OPENSTREETMAP"; public static final String BASEPATH_ON_EXTERNAL_MEDIA = "andnav2/"; public static final String SDCARD_SAVEDROUTES_PATH = "routes/"; public static final String SDCARD_SAVEDTRACES_PATH = "traces/"; public static final String SDCARD_SKYHOOKCACHE_PATH = "skyhookcache/"; public static final String SDCARD_TILE_PATH = "tiles/"; public static final int NOT_SET = Integer.MIN_VALUE; public static final int Y = 0; public static final int X = 1; /** * * @param pOrderedPoints Ordered means that the points are placed as if they are a line. */ public static void smoothLine(final Set<ValuePair> pPointsInLineorder){ ValuePair prev = null; ValuePair cur; /* We want only uniqe new values. */ final Set<ValuePair> newPoints = new TreeSet<ValuePair>(new Comparator<ValuePair>(){ @Override public int compare(final ValuePair a, final ValuePair b) { return a.compareTo(b); } }); for(final Iterator<ValuePair> lineIterator = pPointsInLineorder.iterator(); lineIterator.hasNext(); ) { cur = lineIterator.next(); if(prev != null){ final int difA = cur.a - prev.a; final int difB = cur.b - prev.b; /* Check if we have a diagonal jump, like: (See X's) * * X---- * ----X * * */ if(Math.abs(difA) == 1 && Math.abs(difB) == 1){ /* Add two new points (See O's) * * 0X---- * ----X0 * */ newPoints.add(new ValuePair(cur.a, prev.b)); newPoints.add(new ValuePair(prev.a, cur.b)); } } prev = cur; } pPointsInLineorder.addAll(newPoints); }} class ValuePair implements Comparable<ValuePair>{ // // Constants // // // Fields // final int a,b; // // Constructors // public ValuePair(final int[] reuse) { this.a = reuse[0]; this.b = reuse[1]; } public ValuePair(final int pA, final int pB) { this.a = pA; this.b = pB; } // // Getter & Setter // public int[] toArray() { return new int[]{this.a,this.b}; } public int getValueA() { return this.a; } public int getValueB() { return this.b; } // // Methods from SuperClass/Interfaces // @Override public boolean equals(final Object o) { return o instanceof ValuePair && this.a == ((ValuePair)o).a && this.b == ((ValuePair)o).b; } @Override public int compareTo(final ValuePair another) { if(this.a != another.a) { return this.a - another.a; } else if(this.b != another.b) { return this.b - another.b; } else { return 0; } } // // Methods // }
Raster Line
// Created by plusminus on 13:24:05 - 21.09.2008 //package org.andnav2.osm.util; import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; class Util { public static final String DEBUGTAG = "OPENSTREETMAP"; public static final String BASEPATH_ON_EXTERNAL_MEDIA = "andnav2/"; public static final String SDCARD_SAVEDROUTES_PATH = "routes/"; public static final String SDCARD_SAVEDTRACES_PATH = "traces/"; public static final String SDCARD_SKYHOOKCACHE_PATH = "skyhookcache/"; public static final String SDCARD_TILE_PATH = "tiles/"; public static final int NOT_SET = Integer.MIN_VALUE; public static final int Y = 0; public static final int X = 1; /** * @see http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html */ public static void rasterLine(int x0, int y0, int x1, int y1, final PixelSetter raster) { int dy = y1 - y0; int dx = x1 - x0; int stepx, stepy; if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } raster.setPixel(x0, y0); raster.setPixel(x1, y1); if (dx > dy) { final int length = (dx - 1) >> 2; final int extras = (dx - 1) & 3; final int incr2 = (dy << 2) - (dx << 1); if (incr2 < 0) { final int c = dy << 1; final int incr1 = c << 1; int d = incr1 - dx; for (int i = 0; i < length; i++) { x0 += stepx; x1 -= stepx; if (d < 0) { // Pattern: raster.setPixel(x0, y0); // raster.setPixel(x0 += stepx, y0); // x o o raster.setPixel(x1, y1); // raster.setPixel(x1 -= stepx, y1); d += incr1; } else { if (d < c) { // Pattern: raster.setPixel(x0, y0); // o raster.setPixel(x0 += stepx, y0 += stepy); // x o raster.setPixel(x1, y1); // raster.setPixel(x1 -= stepx, y1 -= stepy); } else { raster.setPixel(x0, y0 += stepy); // Pattern: raster.setPixel(x0 += stepx, y0); // o o raster.setPixel(x1, y1 -= stepy); // x raster.setPixel(x1 -= stepx, y1); // } d += incr2; } } if (extras > 0) { if (d < 0) { raster.setPixel(x0 += stepx, y0); if (extras > 1) { raster.setPixel(x0 += stepx, y0); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1); } } else if (d < c) { raster.setPixel(x0 += stepx, y0); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1); } } else { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1 -= stepy); } } } } else { final int c = (dy - dx) << 1; final int incr1 = c << 1; int d = incr1 + dx; for (int i = 0; i < length; i++) { x0 += stepx; x1 -= stepx; if (d > 0) { raster.setPixel(x0, y0 += stepy); // Pattern: raster.setPixel(x0 += stepx, y0 += stepy); // o raster.setPixel(x1, y1 -= stepy); // o raster.setPixel(x1 -= stepx, y1 -= stepy); // x d += incr1; } else { if (d < c) { raster.setPixel(x0, y0); // Pattern: raster.setPixel(x0 += stepx, y0 += stepy); // o raster.setPixel(x1, y1); // x o raster.setPixel(x1 -= stepx, y1 -= stepy); // } else { raster.setPixel(x0, y0 += stepy); // Pattern: raster.setPixel(x0 += stepx, y0); // o o raster.setPixel(x1, y1 -= stepy); // x raster.setPixel(x1 -= stepx, y1); // } d += incr2; } } if (extras > 0) { if (d > 0) { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1 -= stepy); } } else if (d < c) { raster.setPixel(x0 += stepx, y0); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1); } } else { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0); } if (extras > 2) { if (d > c) { raster.setPixel(x1 -= stepx, y1 -= stepy); } else { raster.setPixel(x1 -= stepx, y1); } } } } } } else { final int length = (dy - 1) >> 2; final int extras = (dy - 1) & 3; final int incr2 = (dx << 2) - (dy << 1); if (incr2 < 0) { final int c = dx << 1; final int incr1 = c << 1; int d = incr1 - dy; for (int i = 0; i < length; i++) { y0 += stepy; y1 -= stepy; if (d < 0) { raster.setPixel(x0, y0); raster.setPixel(x0, y0 += stepy); raster.setPixel(x1, y1); raster.setPixel(x1, y1 -= stepy); d += incr1; } else { if (d < c) { raster.setPixel(x0, y0); raster.setPixel(x0 += stepx, y0 += stepy); raster.setPixel(x1, y1); raster.setPixel(x1 -= stepx, y1 -= stepy); } else { raster.setPixel(x0 += stepx, y0); raster.setPixel(x0, y0 += stepy); raster.setPixel(x1 -= stepx, y1); raster.setPixel(x1, y1 -= stepy); } d += incr2; } } if (extras > 0) { if (d < 0) { raster.setPixel(x0, y0 += stepy); if (extras > 1) { raster.setPixel(x0, y0 += stepy); } if (extras > 2) { raster.setPixel(x1, y1 -= stepy); } } else if (d < c) { raster.setPixel(stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1, y1 -= stepy); } } else { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0, y0 += stepy); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1 -= stepy); } } } } else { final int c = (dx - dy) << 1; final int incr1 = c << 1; int d = incr1 + dy; for (int i = 0; i < length; i++) { y0 += stepy; y1 -= stepy; if (d > 0) { raster.setPixel(x0 += stepx, y0); raster.setPixel(x0 += stepx, y0 += stepy); raster.setPixel(x1 -= stepy, y1); raster.setPixel(x1 -= stepx, y1 -= stepy); d += incr1; } else { if (d < c) { raster.setPixel(x0, y0); raster.setPixel(x0 += stepx, y0 += stepy); raster.setPixel(x1, y1); raster.setPixel(x1 -= stepx, y1 -= stepy); } else { raster.setPixel(x0 += stepx, y0); raster.setPixel(x0, y0 += stepy); raster.setPixel(x1 -= stepx, y1); raster.setPixel(x1, y1 -= stepy); } d += incr2; } } if (extras > 0) { if (d > 0) { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1 -= stepx, y1 -= stepy); } } else if (d < c) { raster.setPixel(x0, y0 += stepy); if (extras > 1) { raster.setPixel(x0 += stepx, y0 += stepy); } if (extras > 2) { raster.setPixel(x1, y1 -= stepy); } } else { raster.setPixel(x0 += stepx, y0 += stepy); if (extras > 1) { raster.setPixel(x0, y0 += stepy); } if (extras > 2) { if (d > c) { raster.setPixel(x1 -= stepx, y1 -= stepy); } else { raster.setPixel(x1, y1 -= stepy); } } } } } } } // // Inner and Anonymous Classes // public static interface PixelSetter { public void setPixel(final int x, final int y); } }
Draw Picture
package app.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.graphics.drawable.PictureDrawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Pictures extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Picture mPicture; private Drawable mDrawable; static void drawSomething(Canvas canvas) { Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0x88FF0000); canvas.drawCircle(50, 50, 40, p); p.setColor(Color.GREEN); p.setTextSize(30); canvas.drawText("Pictures", 60, 60, p); } public SampleView(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); mPicture = new Picture(); drawSomething(mPicture.beginRecording(200, 100)); mPicture.endRecording(); mDrawable = new PictureDrawable(mPicture); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); canvas.drawPicture(mPicture); canvas.drawPicture(mPicture, new RectF(0, 100, getWidth(), 200)); mDrawable.setBounds(0, 200, getWidth(), 300); mDrawable.draw(canvas); ByteArrayOutputStream os = new ByteArrayOutputStream(); mPicture.writeToStream(os); InputStream is = new ByteArrayInputStream(os.toByteArray()); canvas.translate(0, 300); canvas.drawPicture(Picture.createFromStream(is)); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Draw Polygon
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Matrix mMatrix = new Matrix(); private Paint.FontMetrics mFontMetrics; private void doDraw(Canvas canvas, float src[], float dst[]) { canvas.save(); mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); canvas.concat(mMatrix); mPaint.setColor(Color.GRAY); mPaint.setStyle(Paint.Style.STROKE); canvas.drawRect(0, 0, 64, 64, mPaint); canvas.drawLine(0, 0, 64, 64, mPaint); canvas.drawLine(0, 64, 64, 0, mPaint); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.FILL); // how to draw the text center on our square // centering in X is easy... use alignment (and X at midpoint) float x = 64/2; // centering in Y, we need to measure ascent/descent first float y = 64/2 - (mFontMetrics.ascent + mFontMetrics.descent)/2; canvas.drawText(src.length/2 + "", x, y, mPaint); canvas.restore(); } public SampleView(Context context) { super(context); // for when the style is STROKE mPaint.setStrokeWidth(4); // for when we draw text mPaint.setTextSize(40); mPaint.setTextAlign(Paint.Align.CENTER); mFontMetrics = mPaint.getFontMetrics(); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); canvas.save(); canvas.translate(10, 10); // translate (1 point) doDraw(canvas, new float[] { 0, 0 }, new float[] { 5, 5 }); canvas.restore(); canvas.save(); canvas.translate(160, 10); // rotate/uniform-scale (2 points) doDraw(canvas, new float[] { 32, 32, 64, 32 }, new float[] { 32, 32, 64, 48 }); canvas.restore(); canvas.save(); canvas.translate(10, 110); // rotate/skew (3 points) doDraw(canvas, new float[] { 0, 0, 64, 0, 0, 64 }, new float[] { 0, 0, 96, 0, 24, 64 }); canvas.restore(); canvas.save(); canvas.translate(160, 110); // perspective (4 points) doDraw(canvas, new float[] { 0, 0, 64, 0, 64, 64, 0, 64 }, new float[] { 0, 0, 96, 0, 64, 96, 0, 64 }); canvas.restore(); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
rectangle
Draw a rectangle
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // Rectangle Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeWidth(10); float leftx = 20; float topy = 20; float rightx = 50; float bottomy = 100; canvas.drawRect(leftx, topy, rightx, bottomy, paint); } }
Draw a rectangle with float values
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // RectF Rectangle Paint paint = new Paint(); float leftx = 20; float topy = 20; float rightx = 50; float bottomy = 100; RectF rectangle = new RectF(leftx, topy, rightx, bottomy); canvas.drawRect(rectangle, paint); } }
Round Rectangles
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Path mPath; private Paint mPaint; private Rect mRect; private GradientDrawable mDrawable; public SampleView(Context context) { super(context); setFocusable(true); mPath = new Path(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mRect = new Rect(0, 0, 120, 120); mDrawable = new GradientDrawable( GradientDrawable.Orientation.TL_BR, new int[] { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF }); mDrawable.setShape(GradientDrawable.RECTANGLE); mDrawable.setGradientRadius((float) (Math.sqrt(2) * 60)); } static void setCornerRadii(GradientDrawable drawable, float r0, float r1, float r2, float r3) { drawable.setCornerRadii(new float[] { r0, r0, r1, r1, r2, r2, r3, r3 }); } @Override protected void onDraw(Canvas canvas) { mDrawable.setBounds(mRect); float r = 16; canvas.save(); canvas.translate(10, 10); mDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT); setCornerRadii(mDrawable, r, r, 0, 0); mDrawable.draw(canvas); canvas.restore(); canvas.save(); canvas.translate(10 + mRect.width() + 10, 10); mDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT); setCornerRadii(mDrawable, 0, 0, r, r); mDrawable.draw(canvas); canvas.restore(); canvas.translate(0, mRect.height() + 10); canvas.save(); canvas.translate(10, 10); mDrawable.setGradientType(GradientDrawable.SWEEP_GRADIENT); setCornerRadii(mDrawable, 0, r, r, 0); mDrawable.draw(canvas); canvas.restore(); canvas.save(); canvas.translate(10 + mRect.width() + 10, 10); mDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT); setCornerRadii(mDrawable, r, 0, 0, r); mDrawable.draw(canvas); canvas.restore(); canvas.translate(0, mRect.height() + 10); canvas.save(); canvas.translate(10, 10); mDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT); setCornerRadii(mDrawable, r, 0, r, 0); mDrawable.draw(canvas); canvas.restore(); canvas.save(); canvas.translate(10 + mRect.width() + 10, 10); mDrawable.setGradientType(GradientDrawable.SWEEP_GRADIENT); setCornerRadii(mDrawable, 0, r, 0, r); mDrawable.draw(canvas); canvas.restore(); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
ShapeDrawable
Bouncing Ball
package com.example.android.apis.animation; // Need the following import to get access to the app resources, since this // class is in a sub-package. import android.graphics.drawable.ColorDrawable; import com.example.android.apis.R; import android.animation.*; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.Shader; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; import java.util.ArrayList; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.Shape; import android.view.View; /** * A data structure that holds a Shape and various properties that can be used to define * how the shape is drawn. */ class ShapeHolder { private float x = 0, y = 0; private ShapeDrawable shape; private int color; private RadialGradient gradient; private float alpha = 1f; private Paint paint; public void setPaint(Paint value) { paint = value; } public Paint getPaint() { return paint; } public void setX(float value) { x = value; } public float getX() { return x; } public void setY(float value) { y = value; } public float getY() { return y; } public void setShape(ShapeDrawable value) { shape = value; } public ShapeDrawable getShape() { return shape; } public int getColor() { return color; } public void setColor(int value) { shape.getPaint().setColor(value); color = value; } public void setGradient(RadialGradient value) { gradient = value; } public RadialGradient getGradient() { return gradient; } public void setAlpha(float alpha) { this.alpha = alpha; shape.setAlpha((int)((alpha * 255f) + .5f)); } public float getWidth() { return shape.getShape().getWidth(); } public void setWidth(float width) { Shape s = shape.getShape(); s.resize(width, s.getHeight()); } public float getHeight() { return shape.getShape().getHeight(); } public void setHeight(float height) { Shape s = shape.getShape(); s.resize(s.getWidth(), height); } public ShapeHolder(ShapeDrawable s) { shape = s; } } public class BouncingBalls extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); LinearLayout container = (LinearLayout) findViewById(R.id.container); container.addView(new MyAnimationView(this)); } public class MyAnimationView extends View { private static final int RED = 0xffFF8080; private static final int BLUE = 0xff8080FF; private static final int CYAN = 0xff80ffff; private static final int GREEN = 0xff80ff80; public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>(); AnimatorSet animation = null; public MyAnimationView(Context context) { super(context); // Animate background color // Note that setting the background color will automatically invalidate the // view, so that the animated color, and the bouncing balls, get redisplayed on // every frame of the animation. ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE); colorAnim.setDuration(3000); colorAnim.setEvaluator(new ArgbEvaluator()); colorAnim.setRepeatCount(ValueAnimator.INFINITE); colorAnim.setRepeatMode(ValueAnimator.REVERSE); colorAnim.start(); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { return false; } ShapeHolder newBall = addBall(event.getX(), event.getY()); // Bouncing animation with squash and stretch float startY = newBall.getY(); float endY = getHeight() - 50f; float h = (float)getHeight(); float eventY = event.getY(); int duration = (int)(500 * ((h - eventY)/h)); ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY); bounceAnim.setDuration(duration); bounceAnim.setInterpolator(new AccelerateInterpolator()); ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(), newBall.getX() - 25f); squashAnim1.setDuration(duration/4); squashAnim1.setRepeatCount(1); squashAnim1.setRepeatMode(ValueAnimator.REVERSE); squashAnim1.setInterpolator(new DecelerateInterpolator()); ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(), newBall.getWidth() + 50); squashAnim2.setDuration(duration/4); squashAnim2.setRepeatCount(1); squashAnim2.setRepeatMode(ValueAnimator.REVERSE); squashAnim2.setInterpolator(new DecelerateInterpolator()); ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY, endY + 25f); stretchAnim1.setDuration(duration/4); stretchAnim1.setRepeatCount(1); stretchAnim1.setInterpolator(new DecelerateInterpolator()); stretchAnim1.setRepeatMode(ValueAnimator.REVERSE); ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height", newBall.getHeight(), newBall.getHeight() - 25); stretchAnim2.setDuration(duration/4); stretchAnim2.setRepeatCount(1); stretchAnim2.setInterpolator(new DecelerateInterpolator()); stretchAnim2.setRepeatMode(ValueAnimator.REVERSE); ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY); bounceBackAnim.setDuration(duration); bounceBackAnim.setInterpolator(new DecelerateInterpolator()); // Sequence the down/squash&stretch/up animations AnimatorSet bouncer = new AnimatorSet(); bouncer.play(bounceAnim).before(squashAnim1); bouncer.play(squashAnim1).with(squashAnim2); bouncer.play(squashAnim1).with(stretchAnim1); bouncer.play(squashAnim1).with(stretchAnim2); bouncer.play(bounceBackAnim).after(stretchAnim2); // Fading animation - remove the ball when the animation is done ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); fadeAnim.setDuration(250); fadeAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { balls.remove(((ObjectAnimator)animation).getTarget()); } }); // Sequence the two animations to play one after the other AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(bouncer).before(fadeAnim); // Start the animation animatorSet.start(); return true; } private ShapeHolder addBall(float x, float y) { OvalShape circle = new OvalShape(); circle.resize(50f, 50f); ShapeDrawable drawable = new ShapeDrawable(circle); ShapeHolder shapeHolder = new ShapeHolder(drawable); shapeHolder.setX(x - 25f); shapeHolder.setY(y - 25f); int red = (int)(Math.random() * 255); int green = (int)(Math.random() * 255); int blue = (int)(Math.random() * 255); int color = 0xff000000 | red << 16 | green << 8 | blue; Paint paint = drawable.getPaint(); //new Paint(Paint.ANTI_ALIAS_FLAG); int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4; RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f, color, darkColor, Shader.TileMode.CLAMP); paint.setShader(gradient); shapeHolder.setPaint(paint); balls.add(shapeHolder); return shapeHolder; } @Override protected void onDraw(Canvas canvas) { for (int i = 0; i < balls.size(); ++i) { ShapeHolder shapeHolder = balls.get(i); canvas.save(); canvas.translate(shapeHolder.getX(), shapeHolder.getY()); shapeHolder.getShape().draw(canvas); canvas.restore(); } } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2010 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container" > </LinearLayout>