Страница 1 из 1
Рисование на канве
Добавлено: 07 апр 2012, 19:17
andev
Появилась необходимость вставить в разрабатываемое приложение следующий функционал: есть некое изображение (задник), оно залито одноцветным полем. Когда водишь пальцем по этому полю, оно стирается и задник "проявляется". Аналог из реальной жизни - карточки пополнения мобильного счета.
Куда копать? может кто-то сталкивался с подобным функционалом в любом приложении - скачаю и декомпилирую, хотя бы layout гляну.
нужно очень срочно, за любую помощь отблагодарю
Re: Рисование на канве
Добавлено: 08 апр 2012, 21:25
KamiSempai
Код: Выделить всё
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Более подробно можно посмотреть в Гуголовской демке "API Demos".
Пакет: com.example.android.apis.graphics
Класс: FingerPaint
Re: Рисование на канве
Добавлено: 09 апр 2012, 02:09
andev
Спасибо, оттуда и начал. Естественно, наткнулся на проблему черного цвета при стирании. После дальнейшего поиска вроде бы нашел в точности то, что мне требуется, но пока не получается запустить.
http://groups.google.com/group/android- ... 173ba443a6
Re: Рисование на канве
Добавлено: 09 апр 2012, 03:17
andev
Вроде, сделал все как у него:
main.xml
Код: Выделить всё
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</RelativeLayout>
MainActivity.java
Код: Выделить всё
package ru.test.CanvasTest2;
import ru.test.CanvasTest2.R.drawable;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
private Paint mPaint;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
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);
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
ImageView iv = new ImageView(this);
iv.setImageResource(drawable.ic_launcher);
rl.addView(iv);
MyImageView miv = new MyImageView(this);
miv.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_red));
rl.addView(miv);
}
public class MyImageView extends ImageView {
private Paint paint;
private Canvas c2;
private Bitmap overlay;
private Path path;
public MyImageView(Context context) {
super(context);
paint = new Paint();
path = new Path();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(12);
paint.setAntiAlias(true);
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
Drawable bd = getDrawable();
if(bd == null) {
return;
}
Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
overlay = fullSizeBitmap.copy(Config.ARGB_8888, true);
c2 = new Canvas(overlay);
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Drawable bd = getDrawable();
if(bd == null) {
return;
}
Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
if(fullSizeBitmap != null && c2 != null) {
canvas.drawColor(Color.TRANSPARENT);
c2.drawBitmap(fullSizeBitmap, 0, 0, null);
c2.drawPath(path, paint);
canvas.drawBitmap(overlay, 0, 0, null);
}
}
}
}
Кто разбирается, гляньте по возможности, пожалуйста.
Re: Рисование на канве
Добавлено: 09 апр 2012, 07:36
KamiSempai
Я, конечно, пока графикой не занимался и сказать, что разбираюсь - громко сказано

Может не использовать Path, а сразу рисовать линию от старой точки к новой в onTouchEvent?
Кстати, где onTouchEvent? Или можно без него?
PS: Перешел по ссылке, у парня та же проблема с черным цветом.
Re: Рисование на канве
Добавлено: 09 апр 2012, 11:36
andev
Я что-то совсем запутался с этим Canvas'ом

Re: Рисование на канве
Добавлено: 09 апр 2012, 17:02
andev
Изначально хотел подложку закрывать защитным слоем и, стирая защитный слой, "проявлять" лежащую под ним подложку. Но там были проблемы со стиранием с черными полосами которые, насколько показал поиск, никто не решил, даже на стековерфлове.
Сделал немного по-другому. Сначала кладу на канву защитный слой, подложку (которая теперь на самом деле и не подложка) просто держу в памяти. На событии ontouchEvent при action == Move делаю следующее
1) вычисляю координаты прикосновения,
2) беру с подложки ту часть изображения, которая соответствует этим координатам, размером 30 на 30 к примеру.
3) paintBitmap() этим кусочком изображения на защитный слой.
Хотя фактически внизу защита, а сверху кусок скрываемого изображения (по логике должно быть наоборот), в результате выглядит и отрабатывает адекватно.
Теперь о проблемах - не могу сообразить как мне это все культурно оформить что бы можно было вставить в готовую программу. Хотелось бы, что бы это была отдельная активити, на которой это изображение крупно по центру, снизу 1 кнопка.
Встает ряд проблем:
1) координаты прикосновения абсолютные на экране, а разместить надо в центре (либо учитывать смещение, либо пытаться получить относительные координаты)
2) во что это все красиво упаковать что бы было удобно пользоваться?
Проект:
http://zalil.ru/33043472
Re: Рисование на канве
Добавлено: 09 апр 2012, 22:16
KamiSempai
getLocationOnScreen (int[] location) - записывает в location координаты View.
Где location - массив из 2 элементов.
getMeasuredWidth() и getMeasuredHeight() вычисляют размеры.
Re: Рисование на канве
Добавлено: 09 апр 2012, 22:21
andev
спасибо, буду использовать
и еще один вопрос вдогонку: drawBitmap() естественно рисует rectangle (x, y, width, height), как бы сделать, что бы рисовало circle'ом, например?
Re: Рисование на канве
Добавлено: 10 апр 2012, 11:58
KamiSempai
Только-что, за пол часа переделал FingerPaint и получил то, что нужно. Все ка я и предполагал. Будет время, оформлю как класс и выложу здесь.
Re: Рисование на канве
Добавлено: 10 апр 2012, 14:01
andev
KamiSempai писал(а):получил то, что нужно
а что было нужно? стирание слоя без заливки цветом бэкграунда?
В любом случае очень жду
Re: Рисование на канве
Добавлено: 10 апр 2012, 17:29
KamiSempai
Собственно, вот сам класс:
Код: Выделить всё
package ru.KamiSempai.LotteryLayer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class LotteryLayer extends View {
private final static int COATING_COLOR = Color.DKGRAY;
private final static int PAINT_WIDTH = 24;
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint;
public LotteryLayer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialise();
}
public LotteryLayer(Context context, AttributeSet attrs) {
super(context, attrs);
initialise();
}
public LotteryLayer(Context context) {
super(context);
initialise();
}
private void initialise() {
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(PAINT_WIDTH);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
private Bitmap getBitmap() {
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(getMeasuredWidth(),
getMeasuredHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(COATING_COLOR);
}
return mBitmap;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(getBitmap(), 0, 0, mBitmapPaint);
}
private float mX, mY;
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_MOVE) {
mCanvas.drawLine(mX, mY, x, y, mPaint);
invalidate();
}
mX = x;
mY = y;
return true;
}
}
С размером кисти и цветом заливки заморачиваться не стал и сделал их константами. Если делать все по совести их стоило бы вывести в атрибуты.
Файл разметки main.xml может выглядеть, например, так:
Код: Выделить всё
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ic_launcher" >
<ru.KamiSempai.LotteryLayer.LotteryLayer
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
В самом активити ни чего делать не надо.
Готов ответить на любые вопросы, если таковые появились.
PS: Админ, не мешало бы на форуме спойлеры добавить

Re: Рисование на канве
Добавлено: 11 апр 2012, 01:28
andev
Ух, здорово! Сейчас если не усну, попытаюсь оформить при помощи SurfaceHolder и попутно разобраться в чем у меня была проблема. Спасибо за то, что нашли время посмотреть и запостить

Re: Рисование на канве
Добавлено: 11 апр 2012, 07:20
KamiSempai
andev писал(а):... попытаюсь оформить при помощи SurfaceHolder ...
Думаю так будет на много лучше. Можно будет избавиться от getBitmap().
Re: Рисование на канве
Добавлено: 11 апр 2012, 11:34
andev
А каким образом можно стирать canvas у уже существующего View?
Например, есть FrameLayout, на нем лежат друг на друге два ImageView, каждый с изображением. Я хочу "стирать" изображение с верхнего ImageView. Насколько я понимаю, мне нужно унаследовать класс ImageView - MyImageView, переопределить в нем onDraw, onTouchEvent, а также один из методов установки изображения, к примеру setImageBitmap или setImageResouce
Так должно получиться?
Re: Рисование на канве
Добавлено: 11 апр 2012, 12:38
KamiSempai
Не знаю тонкостей работы ImageView. Наверно можно.
Только при рисовании изображения на mCanvas скорее всего придется растягивать его по размерам ImageView.
А еще, можно взять родителем SurfaceView, тогда mCanvas совсем не нужен будет, и переопределять onDraw тоже, кажется.