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了。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories