如何在安卓系统中创建绘画应用?
我们小时候都用过 MS-Paint,当这个系统从桌子转移到我们的手掌上时,我们开始在 Instagram Stories、Hike、WhatsApp 和更多类似的应用上涂鸦。但是你有没有想过这些功能是如何实现的?因此,在本文中,我们将讨论此类应用程序使用的基本方法,并将创建此类应用程序的基本副本。下面给出了一个示例视频,让我们了解一下在本文中要做什么。请注意,我们将使用 Java 语言来实现这个项目。
[https://media.geeksforgeeks.org/wp-content/uploads/20210203001411/InShot_20210203_000836577.mp4](https://media.geeksforgeeks.org/wp-content/uploads/20210203001411/InShot_20210203_000836577.mp4)接近
- 在日常生活中,如果我们想创作一幅画,我们首先需要一幅画布。因此,在我们的应用程序中,我们将首先创建一个画布,用户可以在其中绘制他的绘图。为此,我们需要创建一个自定义视图,用户可以简单地拖动手指来绘制笔画。为了实现这一点,我们创建了一个 DrawView 类,它从标准的 Android SDK 扩展了 View 类。
- 然后我们将需要一个画笔,作为一个工具来帮助我们在画布上绘画。现在,由于我们需要不同颜色和不同笔画宽度的不同画笔,我们将创建一个蓝图,即一个名为 stroke 的类,它具有笔画颜色、笔画宽度、笔画可见性等属性。这个类的每个对象将代表一个独特的画笔,在画布上绘制一个独特的笔画。
- 为了记录用户在画布上绘制的每一个笔画,我们将创建一个笔画类型的数组列表。这个数组列表将帮助我们撤销用户在画布上错误绘制的笔画。
- 现在,当用户完成绘图后,他可能想要保存该绘画以供进一步使用。因此,我们提供了保存选项,它将允许用户以 PNG 或 JPEG 的形式保存当前画布。
方法列表
在跳到代码之前,我们将在构建应用程序时使用以下几种方法:
| 类型 | 方法 | 描述 | | --- | --- | --- | | gap | Setting jitter (Boolean jitter) | 抖动会影响属于 | Down-sampling of the color of | | hollow | 七龙珠登场人物及译名列表 | antiasias 平滑了所绘制内容的边缘,但对形状的内部影响不大。 | | hollow | setStyle(绘制)。679 维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪·维琪) | This method controls | | become invalid | 设置 strokekcap(油漆.帽帽) | 此方法根据参数改变线端点的几何形状,例如 ROUND、SQUARE、BUTT。 | | 空的 | void setStrokeJoin(Paint .加入加入) | This method sets the paint to be connected to any one of ROUND, slope and MITTER. | | 空的 | setAlpha(内部 a) | 它是一种辅助方法,只分配颜色的 alpha 值,而保持其 r、g、b 值不变。如果α值在范围[0]之外,则结果未定义..255] | | 空的 | 无效() | 此方法调用被覆盖的 onDraw()方法。每当我们想要更新屏幕时,在我们的例子中是 Canvas,我们调用 invalidate()方法,该方法进一步在内部调用 onDraw()方法。 | | (同 Internationalorganizations)国际组织 | 帆布。保存() | 此方法保存 Canvas 的当前状态以便我们以后可以回到它上面 | | 空的 | 帆布。还原() | 此方法将 Canvas 的调整还原回 | | | 空的 | 路径。四路至(浮点 x1、浮点 y1、浮点 x2、浮点 y2) | 此方法使用二次线平滑曲线。 (x1,y1)是二次曲线上的控制点,(x2,y2)是二次曲线上的端点。 |现在,让我们开始构建应用程序。此应用程序不需要任何特殊权限。所以保留 AndroidManifest.xml 为默认值。
分步实施
第一步:创建新项目
要在安卓工作室创建新项目,请参考如何在安卓工作室创建/启动新项目。注意选择 Java 作为编程语言。
第二步:在 gradle.build 中添加依赖项
这个库用来给我们的应用程序添加调色板,这样用户就可以选择他选择的任何颜色
实现' petrov . Kristi Yan:color picker-library:1 . 1 . 10 '
步骤 3:使用 activity_main.xml 文件
导航到应用程序> res >布局> activity_main.xml 并将下面的代码添加到该文件中。下面是 activity_main.xml 文件的代码。
可扩展标记语言
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/btn_undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_undo"
android:text="Undo" />
<ImageButton
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_floppy_disk"
android:text="Save" />
<ImageButton
android:id="@+id/btn_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_colorpicker"
android:text="Color" />
<ImageButton
android:id="@+id/btn_stroke"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_paint_brush"
android:text="Stroke" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.slider.RangeSlider
android:id="@+id/rangebar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
<com.raghav.paint.DrawView
android:id="@+id/draw_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/linear"
android:layout_centerInParent="true" />
</RelativeLayout>
第四步:创建笔画类
参考如何在安卓工作室中创建类。并将班级命名为笔画。以下是Stroke.java文件的代码。
Java 语言(一种计算机语言,尤用于创建网站)
import android.graphics.Path;
public class Stroke {
// color of the stroke
public int color;
// width of the stroke
public int strokeWidth;
// a Path object to
// represent the path drawn
public Path path;
// constructor to initialise the attributes
public Stroke(int color, int strokeWidth, Path path) {
this.color = color;
this.strokeWidth = strokeWidth;
this.path = path;
}
}
第五步: 创建绘图视图类
同样,创建一个新的 java 类,并将该类命名为 DrawView 。以下是DrawView.java文件的代码。
Java 语言(一种计算机语言,尤用于创建网站)
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class DrawView extends View {
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
// the Paint class encapsulates the color
// and style information about
// how to draw the geometries,text and bitmaps
private Paint mPaint;
// ArrayList to store all the strokes
// drawn by the user on the Canvas
private ArrayList<Stroke> paths = new ArrayList<>();
private int currentColor;
private int strokeWidth;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
// Constructors to initialise all the attributes
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
// the below methods smoothens
// the drawings of the user
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);
// 0xff=255 in decimal
mPaint.setAlpha(0xff);
}
// this method instantiate the bitmap and object
public void init(int height, int width) {
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
// set an initial color of the brush
currentColor = Color.GREEN;
// set an initial brush size
strokeWidth = 20;
}
// sets the current color of stroke
public void setColor(int color) {
currentColor = color;
}
// sets the stroke width
public void setStrokeWidth(int width) {
strokeWidth = width;
}
public void undo() {
// check whether the List is empty or not
// if empty, the remove method will return an error
if (paths.size() != 0) {
paths.remove(paths.size() - 1);
invalidate();
}
}
// this methods returns the current bitmap
public Bitmap save() {
return mBitmap;
}
// this is the main method where
// the actual drawing takes place
@Override
protected void onDraw(Canvas canvas) {
// save the current state of the canvas before,
// to draw the background of the canvas
canvas.save();
// DEFAULT color of the canvas
int backgroundColor = Color.WHITE;
mCanvas.drawColor(backgroundColor);
// now, we iterate over the list of paths
// and draw each path on the canvas
for (Stroke fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
// the below methods manages the touch
// response of the user on the screen
// firstly, we create a new Stroke
// and add it to the paths list
private void touchStart(float x, float y) {
mPath = new Path();
Stroke fp = new Stroke(currentColor, strokeWidth, mPath);
paths.add(fp);
// finally remove any curve
// or line from the path
mPath.reset();
// this methods sets the starting
// point of the line being drawn
mPath.moveTo(x, y);
// we save the current
// coordinates of the finger
mX = x;
mY = y;
}
// in this method we check
// if the move of finger on the
// screen is greater than the
// Tolerance we have previously defined,
// then we call the quadTo() method which
// actually smooths the turns we create,
// by calculating the mean position between
// the previous position and current position
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;
}
}
// at the end, we call the lineTo method
// which simply draws the line until
// the end position
private void touchUp() {
mPath.lineTo(mX, mY);
}
// the onTouchEvent() method provides us with
// the information about the type of motion
// which has been taken place, and according
// to that we call our desired methods
@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;
}
}
第 6 步:使用MainActivity.java 文件
转到MainActivity.java文件,参考以下代码。以下是MainActivity.java文件的代码。代码中添加了注释,以更详细地理解代码。
Java 语言(一种计算机语言,尤用于创建网站)
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.slider.RangeSlider;
import java.io.OutputStream;
import petrov.kristiyan.colorpicker.ColorPicker;
public class MainActivity extends AppCompatActivity {
// creating the object of type DrawView
// in order to get the reference of the View
private DrawView paint;
// creating objects of type button
private ImageButton save, color, stroke, undo;
// creating a RangeSlider object, which will
// help in selecting the width of the Stroke
private RangeSlider rangeSlider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// getting the reference of the views from their ids
paint = (DrawView) findViewById(R.id.draw_view);
rangeSlider = (RangeSlider) findViewById(R.id.rangebar);
undo = (ImageButton) findViewById(R.id.btn_undo);
save = (ImageButton) findViewById(R.id.btn_save);
color = (ImageButton) findViewById(R.id.btn_color);
stroke = (ImageButton) findViewById(R.id.btn_stroke);
// creating a OnClickListener for each button,
// to perform certain actions
// the undo button will remove the most
// recent stroke from the canvas
undo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
paint.undo();
}
});
// the save button will save the current
// canvas which is actually a bitmap
// in form of PNG, in the storage
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// getting the bitmap from DrawView class
Bitmap bmp = paint.save();
// opening a OutputStream to write into the file
OutputStream imageOutStream = null;
ContentValues cv = new ContentValues();
// name of the file
cv.put(MediaStore.Images.Media.DISPLAY_NAME, "drawing.png");
// type of the file
cv.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
// location of the file to be saved
cv.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
// get the Uri of the file which is to be created in the storage
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cv);
try {
// open the output stream with the above uri
imageOutStream = getContentResolver().openOutputStream(uri);
// this method writes the files in storage
bmp.compress(Bitmap.CompressFormat.PNG, 100, imageOutStream);
// close the output stream after use
imageOutStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
// the color button will allow the user
// to select the color of his brush
color.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final ColorPicker colorPicker = new ColorPicker(MainActivity.this);
colorPicker.setOnFastChooseColorListener(new ColorPicker.OnFastChooseColorListener() {
@Override
public void setOnFastChooseColorListener(int position, int color) {
// get the integer value of color
// selected from the dialog box and
// set it as the stroke color
paint.setColor(color);
}
@Override
public void onCancel() {
colorPicker.dismissDialog();
}
})
// set the number of color columns
// you want to show in dialog.
.setColumns(5)
// set a default color selected
// in the dialog
.setDefaultColorButton(Color.parseColor("#000000"))
.show();
}
});
// the button will toggle the visibility of the RangeBar/RangeSlider
stroke.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (rangeSlider.getVisibility() == View.VISIBLE)
rangeSlider.setVisibility(View.GONE);
else
rangeSlider.setVisibility(View.VISIBLE);
}
});
// set the range of the RangeSlider
rangeSlider.setValueFrom(0.0f);
rangeSlider.setValueTo(100.0f);
// adding a OnChangeListener which will
// change the stroke width
// as soon as the user slides the slider
rangeSlider.addOnChangeListener(new RangeSlider.OnChangeListener() {
@Override
public void onValueChange(@NonNull RangeSlider slider, float value, boolean fromUser) {
paint.setStrokeWidth((int) value);
}
});
// pass the height and width of the custom view
// to the init method of the DrawView object
ViewTreeObserver vto = paint.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
paint.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width = paint.getMeasuredWidth();
int height = paint.getMeasuredHeight();
paint.init(height, width);
}
});
}
}
版权属于:月萌API www.moonapi.com,转载请注明出处