Intereting Posts
Не удается запустить на производственных устройствах Протирать данные / Сбросить заводские данные через ADB Андроидное текстовое дополнение между строками Чтение данных из тега NFC (IsoDep) Создайте экземпляр абстрактного класса в Котлине Как получить текущий уровень масштабирования GoogleMap? Как передать различные объекты в качестве параметра в AsycTask? Одновременное распознавание речи и аудиозапись Android Как мне компоновать вложенные RecyclerViews, оставаясь при этом исполняемым? FastScroller только прокручивает назад к первому элементу, а не к виду заголовка Что такое файл keycharmap? Почему я получаю сообщение «can not open keycharmap file»? Мобильная разработка – родной VS Cross Platform VS JavaScript Есть ли тег XML, эквивалентный «ListView.addHeaderView»? Должен ли полный файл xml содержимого резервной копии быть пустым или вообще не добавлять, чтобы включить все? Как установить NAVIGATION_MODE_LIST на Панели инструментов new appcompat v7 21

Рисовать в холсте пальцем, Android

Мне нужно построить проект для рисования на холсте пальцами,

Чтобы получить событие касания и событие движения пальца, а оттуда.

Любой может посоветовать мне, как начать работу в проекте,

И что является лучшим компонентом для этого?

Solutions Collecting From Web of "Рисовать в холсте пальцем, Android"

Начало Просматривая демоверсию Fingerpaint в примере sdk.

Другой пример:

public class MainActivity extends Activity { DrawingView dv ; private Paint mPaint; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); dv = new DrawingView(this); setContentView(dv); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(Color.GREEN); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(12); } public class DrawingView extends View { public int width; public int height; private Bitmap mBitmap; private Canvas mCanvas; private Path mPath; private Paint mBitmapPaint; Context context; private Paint circlePaint; private Path circlePath; public DrawingView(Context c) { super(c); context=c; mPath = new Path(); mBitmapPaint = new Paint(Paint.DITHER_FLAG); circlePaint = new Paint(); circlePath = new Path(); circlePaint.setAntiAlias(true); circlePaint.setColor(Color.BLUE); circlePaint.setStyle(Paint.Style.STROKE); circlePaint.setStrokeJoin(Paint.Join.MITER); circlePaint.setStrokeWidth(4f); } @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) { super.onDraw(canvas); canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint); canvas.drawPath( mPath, mPaint); canvas.drawPath( circlePath, circlePaint); } 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; circlePath.reset(); circlePath.addCircle(mX, mY, 30, Path.Direction.CW); } } private void touch_up() { mPath.lineTo(mX, mY); circlePath.reset(); // 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; } } } 

Snap shot

Введите описание изображения здесь

Объяснение:

Вы создаете класс представления, а затем расширяете представление. Вы переопределяете onDraw (). Вы добавляете путь, по которому палец касается и перемещается. Вы переопределите onTouch () для этой цели. В вашем onDraw () вы рисуете пути, используя краску по вашему выбору. Вы должны вызвать invalidate (), чтобы обновить представление.

Для выбора параметров вы можете щелкнуть меню и выбрать параметры.

Нижеследующее может использоваться как ссылка. Вы можете изменить ниже в соответствии с вашими потребностями.

 public class FingerPaintActivity extends Activity implements ColorPickerDialog.OnColorChangedListener { MyView mv; AlertDialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mv= new MyView(this); mv.setDrawingCacheEnabled(true); mv.setBackgroundResource(R.drawable.afor);//set the back ground if you wish to setContentView(mv); 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(20); 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; Context context; public MyView(Context c) { super(c); context=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) { super.onDraw(canvas); 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) { //showDialog(); 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(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); //mPaint.setMaskFilter(null); } @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; private static final int Save = Menu.FIRST + 5; @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'); menu.add(0, Save, 0, "Save").setShortcut('5', 'z'); 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)); mPaint.setAlpha(0x80); return true; case SRCATOP_MENU_ID: mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.SRC_ATOP)); mPaint.setAlpha(0x80); return true; case Save: AlertDialog.Builder editalert = new AlertDialog.Builder(FingerPaintActivity.this); editalert.setTitle("Please Enter the name with which you want to Save"); final EditText input = new EditText(FingerPaintActivity.this); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT); input.setLayoutParams(lp); editalert.setView(input); editalert.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String name= input.getText().toString(); Bitmap bitmap = mv.getDrawingCache(); String path = Environment.getExternalStorageDirectory().getAbsolutePath(); File file = new File("/sdcard/"+name+".png"); try { if(!file.exists()) { file.createNewFile(); } FileOutputStream ostream = new FileOutputStream(file); bitmap.compress(CompressFormat.PNG, 10, ostream); ostream.close(); mv.invalidate(); } catch (Exception e) { e.printStackTrace(); }finally { mv.setDrawingCacheEnabled(false); } } }); editalert.show(); return true; } return super.onOptionsItemSelected(item); } } 

Выбор цвета

 public 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"); } } 

Что касается красивого кода Рагхунандана выше.

Многие спрашивали, как «очистить» чертеж. Вот как это сделать:

 public void clearDrawing() { Utils.Log("RaghunandanDraw, how to clear...."); setDrawingCacheEnabled(false); // don't forget that one and the match below, // or you just keep getting a duplicate when you save. onSizeChanged(width, height, width, height); invalidate(); setDrawingCacheEnabled(true); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; // don't forget these height = h; mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); } 

Многие спрашивали, как «сохранить» рисунок. Вот как это сделать:

 public DrawingView(Context c) { circlePaint.setStrokeJoin(Paint.Join.MITER); circlePaint.setStrokeWidth(4f); etc... // in the class where you set up the view, add this: setDrawingCacheEnabled( true ); } public void saveDrawing() { Bitmap whatTheUserDrewBitmap = getDrawingCache(); // don't forget to clear it (see above) or you just get duplicates // almost always you will want to reduce res from the very high screen res whatTheUserDrewBitmap = ThumbnailUtils.extractThumbnail(whatTheUserDrewBitmap, 256, 256); // NOTE that's an incredibly useful trick for cropping/resizing squares // while handling all memory problems etc // http://stackoverflow.com/a/17733530/294884 // you can now save the bitmap to a file, or display it in an ImageView: ImageView testArea = ... testArea.setImageBitmap( whatTheUserDrewBitmap ); // these days you often need a "byte array". for example, // to save to parse.com or other cloud services ByteArrayOutputStream baos = new ByteArrayOutputStream(); whatTheUserDrewBitmap.compress(Bitmap.CompressFormat.PNG, 0, baos); byte[] yourByteArray; yourByteArray = baos.toByteArray(); } 

Надеюсь, это помогает кому-то, поскольку это мне помогло.

Учебник по рисованию линии использует растровые, холсты и классы Paint. Рисовать -на-пальце-касание и androiddraw

Здесь один простой класс для рисования линии с использованием холста, как показано ниже.

  public class TestLineView extends View { private Paint paint; private PointF startPoint, endPoint; private boolean isDrawing; public TestLineView(Context context) { super(context); init(); } private void init() { paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Style.STROKE); paint.setStrokeWidth(2); paint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { if(isDrawing) { canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startPoint = new PointF(event.getX(), event.getY()); endPoint = new PointF(); isDrawing = true; break; case MotionEvent.ACTION_MOVE: if(isDrawing) { endPoint.x = event.getX(); endPoint.y = event.getY(); invalidate(); } break; case MotionEvent.ACTION_UP: if(isDrawing) { endPoint.x = event.getX(); endPoint.y = event.getY(); isDrawing = false; invalidate(); } break; default: break; } return true; } } 

Вы можете использовать этот класс просто:

 public class DoodleCanvas extends View{ private Paint mPaint; private Path mPath; public DoodleCanvas(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(10); mPath = new Path(); } @Override protected void onDraw(Canvas canvas) { canvas.drawPath(mPath, mPaint); super.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mPath.moveTo(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: mPath.lineTo(event.getX(), event.getY()); invalidate(); break; case MotionEvent.ACTION_UP: break; } return true; } } 

Я думаю, что важно добавить вещь, если вы используете инфляцию макета, что конструктор в drawview неверен, добавьте эти конструкторы в класс:

 public DrawingView(Context c, AttributeSet attrs) { super(c, attrs); ... } public DrawingView(Context c, AttributeSet attrs, int defStyle) { super(c, attrs, defStyle); ... } 

Или система андроидов не может раздуть файл макета. Надеюсь, это поможет.