您的位置:首页 > 移动开发 > Android开发

View的基本绘制

2016-05-04 00:14 776 查看

View的基本绘制

翻译自:点击链接

综述

让我们来构建一个用户自定义的View,它允许用户用他们按下的手指在屏幕上进行绘图。这片文章将会阐述怎样去构建一个用户自定义的组件,怎样在View上去绘制几何图形和路径,以及怎样处理用户的触摸交互。

生成我们的View

创建一个叫SimpleDrawingView简单的class,并且让它继承自View:

public class SimpleDrawingView extends View {
public SimpleDrawingView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
}


把下面这个加入到activity的xml布局文件中,这样我们定义的View才会被植入:

<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" >

<com.codepath.example.simpledrawapp.SimpleDrawingView
android:id="@+id/simpleDrawingView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />

</RelativeLayout>


使用Canvas进行简单绘制

让我们试试在在屏幕上画几个圆这需要我们定义一个Paint对象,用来控制绘画的风格和颜色让我们开始使用它吧:

public class SimpleDrawingView extends View {
// setup initial color
private final int paintColor = Color.BLACK;
// defines paint and canvas
private Paint drawPaint;

public SimpleDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}

// Setup paint with color and stroke styles
private void setupPaint() {
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);//设置抗锯齿
drawPaint.setStrokeWidth(5);//设置空心线宽
drawPaint.setStyle(Paint.Style.STROKE);//设置成空心
drawPaint.setStrokeJoin(Paint.Join.ROUND);//设置结合处为圆弧
drawPaint.setStrokeCap(Paint.Cap.ROUND);//笔尖是圆形
}
}


现在我们设置一个黑色的空心风格的Paint,我们试试用不同颜色画一些圆圈。所有这些绘制的过程将写在onDraw方法里面,这个方法会在View渲染之后进行回调:

public class SimpleDrawingView extends View {
// ...variables and setting up paint...
// Let's draw three circles
@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(50, 50, 20, drawPaint);
drawPaint.setColor(Color.GREEN);
canvas.drawCircle(50, 150, 20, drawPaint);
drawPaint.setColor(Color.BLUE);
canvas.drawCircle(50, 250, 20, drawPaint);
}
}


注意onDraw方法传入了一个canvas对象,我们用这个进行绘制,并且还要借助我们之前定义的Paint,drawCircle方法需要x,y坐标和radius半径,以下是绘制效果:



处理触摸事件

假设我们想要任何时候,当我们的用户在屏幕上按下时,都能画一个圈。我们需要一系列的点给我们的圆圈,并且每次触摸都将追加新的点,这里的点使用Point这个对象,它提供了一个点应有的要素,和操作它的一些方法,它维护x,和y这两个值:

public class SimpleDrawingView extends View {

private final int paintColor = Color.BLACK;

private Paint drawPaint;

private List<Point> circlePoints;// 装Point

public SimpleDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupPaint();
circlePoints = new ArrayList<Point>();
}

// Draw each circle onto the view
@Override
protected void onDraw(Canvas canvas) {
//把所有的点绘制一遍,感觉有点。。。
for (Point p : circlePoints) {
canvas.drawCircle(p.x, p.y, 5, drawPaint);
}
}

// Append new circle each time user presses on screen
@Override
public boolean onTouchEvent(MotionEvent event) {

4000
float touchX = event.getX();
float touchY = event.getY();
circlePoints.add(new Point(Math.round(touchX), Math.round(touchY)));
postInvalidate();//重新绘制,重新调用onDraw方法
return true;
}

private void setupPaint() {
// 这里把风格改成填充,其它的跟前面一样
drawPaint.setStyle(Paint.Style.FILL); // change to fill
// ...
}
}


有了这个,我们就可以在任意按下的位置画黑圆了



使用Path来绘制

到目前为止我们已经会使用onDraw了,并且会用基于触摸事件处理的画圆方式了。下一步,让我们用路径绘制方式代替刚刚的逐一绘制。Path这个类允许用户在屏幕上绘制。一个Path可以包含很多条线,轮廓和其他几何图形。首先我们添加个Path变量去绘制一个轨迹:

public class SimpleDrawingView extends View {
// ...
private Path path = new Path();
// ...
}


下一步,当用户按下的时候,我们在屏幕上追加一些点。当用户按下,们开始增加一个路径,把这些点连接起来。为了做这些,我们需要修改onTouchEvent方法,并追加这些点进我们的Path对象:

public class SimpleDrawingView extends View {
private Path path = new Path();

// Get x and y and append them to the path
public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Starts a new line in the path
path.moveTo(pointX, pointY);
break;
case MotionEvent.ACTION_MOVE:
// Draws line between last point and this point
path.lineTo(pointX, pointY);
break;
default:
return false;
}

postInvalidate(); // Indicate view should be redrawn
return true; // Indicate we've consumed the touch
}

// ...
}


把之前的onDraw方法改一下,用绘制路径的方式代替:

public class SimpleDrawingView extends View {
// ... onTouchEvent ...

// Draws the path created during the touch events
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, drawPaint);
}

private void setupPaint() {
// same as before
drawPaint.setStyle(Paint.Style.STROKE); // change back to stroke
// ...
}
}


有了这些,我们就有了一个最基本的绘图的app了:



用Bitmap高效率绘制

当你在canvas上面绘画的时候,你经常会想到要依靠bitmap缓存图片,就像这个stackoverflow网站上的问题一样。stackoverflow的问题

Bitmap mField = null;

public void init()
{
mField = new Bitmap(...dimensions...);
Canvas c = new Canvas(mField);
c.drawRect(...);
...
}

public void onDraw(Canvas c)
{
c.drawBitmap(mField);
}


这是一个常用的提高性能的模型

关于SimpleDrawingView

SimpleDrawingView的所有代码如下所示:

public class SimpleDrawingView extends View {
// setup initial color
private final int paintColor = Color.BLACK;
// defines paint and canvas
private Paint drawPaint;
// stores next circle
private Path path = new Path();

public SimpleDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}

private void setupPaint() {
// Setup paint with color and stroke styles
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}

@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, drawPaint);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(pointX, pointY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(pointX, pointY);
break;
default:
return false;
}
// Force a view to draw again
postInvalidate();
return true;
}
}


使用单独的像素来绘制

当绘制或是正在进行动画,你往往想用整齐的独立的像素,在不同尺寸大小和密度的设备上稳健地绘制。你也许想更好的整齐的决定设备的高度或者宽度。拷贝这个DeviceDimensionsHelper.java工具类到你的工程中,只要你获得context,你就能获得设备的宽高,并且在dp和px之间任意转换:

// Get height or width of screen
int screenHeight = DeviceDimensionsHelper.getDisplayHeight(this);
int screenWidth = DeviceDimensionsHelper.getDisplayWidth(this);
// Convert dp to pixels
float px = DeviceDimensionsHelper.convertDpToPixel(25f, this);
// Convert pixels to dp
float dp = DeviceDimensionsHelper.convertPixelsToDp(25f, this);


你可以用这个更方便的绘制你定义的View了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android