Рисование на Андроид/Урок 1

Всем привет, это у нас очередной урок по созданию приложений для операционной системы андроид с помощью среды разработки Android Studio.

Начнем создавать необходимые классы для работы приложения и я вам по ходу дела буду объяснять что к чему!

FingerPath.java

FingerPath.java это простой класс который будет сохранять в себе элементы которые мы будем менять, такие как размер кисточки, цвет и.т.д

import android.graphics.Path;

public class FingerPath {

public int color;
public boolean emboss;
public boolean blur;
public int strokeWidth;
public Path path;

public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path) {
this.color = color;
this.emboss = emboss;
this.blur = blur;
this.strokeWidth = strokeWidth;
this.path = path;
}
}

PaintView.java

PaintView.java это наше “custom” View. Простыми словами это View которое мы сами создадим. Данный класс и будет являться холстом.Этот класс отвечает за рисование на экране размер холста и многое другое. В данном классе мы также обрабатываем прикосновение пальца к экрану и рисуем согласно координатам полученным от сенсорного экрана. 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;


public class PaintView extends View {

public static int BRUSH_SIZE = 20;
public static final int DEFAULT_COLOR = Color.RED;
public static final int DEFAULT_BG_COLOR = Color.WHITE;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);

public PaintView(Context context) {
this(context, null);
}

public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);

mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}

public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;

mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);

currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}

public void normal() {
emboss = false;
blur = false;
}
public void size_normal() {
strokeWidth = 10;
}
public void size_big() {
strokeWidth = 15;
}
public void size_small() {
strokeWidth = 5;
}
public void color_green() {
currentColor = Color.GREEN;
}
public void color_red() {
currentColor = Color.RED;
}
public void color_black() {
currentColor = Color.BLACK;
}

public void emboss() {
emboss = true;
blur = false;
}

public void blur() {
emboss = false;
blur = true;
}

public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);

for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);

if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);

mCanvas.drawPath(fp.path, mPaint);

}

canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}

private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);

mPath.reset();
mPath.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) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}

private void touchUp() {
mPath.lineTo(mX, mY);
}

@Override
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();
invalidate();
break;
}

return true;
}
}

MainActivity.java

MainActivity.java это наше activity которое и будет показывать наш экран на котором находится наше PainView. А также этот класс загружает основное меню и следит за нажатиями на элементы меню.

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

private PaintView paintView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
paintView = findViewById(R.id.paintView);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.normal:
paintView.normal();
return true;
case R.id.emboss:
paintView.emboss();
return true;
case R.id.blur:
paintView.blur();
return true;
case R.id.clear:
paintView.clear();
return true;
case R.id.size_small:
paintView.size_small();
return true;
case R.id.size_normal:
paintView.size_normal();
return true;
case R.id.size_big:
paintView.size_big();
return true;
case R.id.color_green:
paintView.color_green();
return true;
case R.id.color_red:
paintView.color_red();
return true;
case R.id.color_black:
paintView.color_black();
return true;
}

return super.onOptionsItemSelected(item);
}
}

activity_main.xml

activity_main.xml это наш экран, и он довольно простой на нем только один элемент, это наш PainView.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.neco_desarrollo.paintapptest.PaintView
android:id="@+id/paintView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

main_menu.xml

main_menu.xml это наше основное меню, не забудте для начала создать папку menu в папке res, я уже об этом не раз рассказывал.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item

android:title="Эффекты">
<menu>
<item
android:id="@+id/normal"
android:title="Нормальный" />
<item
android:id="@+id/emboss"
android:title="Тень" />
<item
android:id="@+id/blur"
android:title="Туманный" />
</menu>
</item>
<item

android:title="Размер кисточки">
<menu>
<item
android:id="@+id/size_normal"
android:title="Нормальный" />
<item
android:id="@+id/size_small"
android:title="Маленький" />
<item
android:id="@+id/size_big"
android:title="Большой"></item>
</menu>
</item>
<item

android:title="Цвет">

<menu>
<item
android:id="@+id/color_black"
android:title="Черный"></item>
<item
android:id="@+id/color_red"
android:title="Красный" />
<item
android:id="@+id/color_green"
android:title="Зеленый" />
</menu>
</item>
<item
android:id="@+id/clear"
android:title="Стереть" />
</menu>

Заключение:

Если будет интерес к данной теме то на следующем уроке мы все детально изучим и напишем данное приложение с самого начало, и я вам объясню все более подробно!

3 комментария для “Рисование на Андроид/Урок 1”

  1. Спасибо! Все работает, скопировал код. Хотелось бы поподробнее изучить создание данного приложения!

Добавить комментарий

Ваш адрес email не будет опубликован.