Android编程实现画板功能的方法总结【附源码下载】

本文实例讲述了Android编程实现画板功能的方法。分享给大家供大家参考,具体如下:

Android实现画板主要有2种方式,一种是用自定义View实现,另一种是通过Canvas类实现。当然自定义View内部也是用的Canvas。第一种方式的思路是,创建一个自定义View(推荐SurfaceView),在自定义View里通过Path对象记录手指滑动的路径调用lineTo()绘制;第二种方式的思路是,先用Canvas绘制一张空的Bitmap,通过ImageView的setImageBitmap()方法加载这个Bitmap,然后该ImageView实现onTouch()监听事件,跟踪用户手指的移动调用drawLine()绘制线条。

我们先来看第一种的实现的方式吧。这里就用SurfaceView来实现,在这里介绍一下关于SurfaceView的知识。SurfaceView继承自View,两者都可以实现绘图功能,那么他们有什么不同呢。先说下Android绘制视图的原理,View通过刷新来绘制视图,Android系统则通过发出VSYNC信号进行屏幕绘制,玩游戏的朋友都应该知道"垂直同步",VSYNC就是垂直同步,谷歌是在4.1之后引入VSYNC的,VSYNC是为了不让画面掉帧。为了不掉帧,View的绘制需要在16ms之内完成。如果执行耗时太长或者需要频繁刷新,那么View就不合适了,影响用户体验和性能。用 SurfaceView就好办了,它内部是在子线程进行页面刷新,使用了双缓冲机制。现在我们来使用它吧。

通常用法是创建一个View继承自SurfaceView,并实现Callback和Runnable接口。

public class MySurfaceView extends SurfaceView implements
    SurfaceHolder.Callback, Runnable {
  // SurfaceHolder实例
  private SurfaceHolder mSurfaceHolder;
  // Canvas对象
  private Canvas mCanvas;
  // 控制子线程是否运行
  private boolean startDraw;
  // Path实例
  private Path mPath = new Path();
  // Paint实例
  private Paint mpaint = new Paint();
  public MySurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView(); // 初始化
  }
  private void initView() {
    mSurfaceHolder = getHolder();
    mSurfaceHolder.addCallback(this);
    // 设置可获得焦点
    setFocusable(true);
    setFocusableInTouchMode(true);
    // 设置常亮
    this.setKeepScreenOn(true);
  }
  @Override
  public void run() {
    // 如果不停止就一直绘制
    while (startDraw) {
      // 绘制
      draw();
    }
  }
  /*
   * 创建
   */
  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    startDraw = true;
    new Thread(this).start();
  }
  /*
   * 改变
   */
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width,
      int height) {
  }
  /*
   * 销毁
   */
  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    startDraw = false;
  }
  private void draw() {
    try {
      mCanvas = mSurfaceHolder.lockCanvas();
      mCanvas.drawColor(Color.WHITE);
      mpaint.setStyle(Paint.Style.STROKE);
      mpaint.setStrokeWidth(DensityUtil.px2dip(getContext(), 30));
      mpaint.setColor(Color.BLACK);
      mCanvas.drawPath(mPath, mpaint);
    } catch (Exception e) {
    } finally {
      // 对画布内容进行提交
      if (mCanvas != null) {
        mSurfaceHolder.unlockCanvasAndPost(mCanvas);
      }
    }
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    int x = (int) event.getX();  //获取手指移动的x坐标
    int y = (int) event.getY();  //获取手指移动的y坐标
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      mPath.moveTo(x, y);
      break;
    case MotionEvent.ACTION_MOVE:
      mPath.lineTo(x, y);
      break;
    case MotionEvent.ACTION_UP:
      break;
    }
    return true;
  }
  // 重置画布
  public void reset() {
    mPath.reset();
  }
}

我们在构造方法里进行初始化,获得SurfaceHolder实例,添加Callback接口实例,及获得焦点等操作。重写了SurfaceView的三个方法surfaceCreated,surfaceChanged,surfaceDestroyed。在surfaceCreated方法里开启子线程,执行draw方法。在surfaceDestroyed方法里关闭线程。在draw方法里,通过mSurfaceHolder.lockCanvas()获取Canvas对象,设置样式,颜色等,然后重写onTouchEvent方法,监听用户手指移动,调用mPath.lineTo(x, y)绘制线条,最后调用mSurfaceHolder.unlockCanvasAndPost(mCanvas)提交画布内容.这样就完成了画板的绘制。

我在代码里添加了reset()方法,可以重置画布,只需要在MainActivity获取SurfaceView对象,调用SurfaceView.reset()就可以了。

private Button reset_btn;
private MySurfaceView mview;
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  context = this;
  mview = (MySurfaceView) findViewById(R.id.MySurfaceView);
  reset_btn = (Button) findViewById(R.id.reset_btn);
  reset_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      //清除
      mview.reset();
    }
  });

现在我们看下第二种方式吧,其实原理和第一种差不太多,我就不赘述了。直接贴上代码吧。

public class SecondActivity extends Activity {
  private ImageView img;
  private Bitmap mBitmap;
  private Canvas canvas;
  private Paint paint;
  // 重置按钮
  private Button reset_btn;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    img = (ImageView) findViewById(R.id.img);
    reset_btn = (Button) findViewById(R.id.reset_btn);
    reset_btn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        img.setImageBitmap(null);
        showImage();
      }
    });
    // 绘图
    showImage();
  }
  private void showImage() {
    // 创建一张空白图片
    mBitmap = Bitmap.createBitmap(720, 1280, Bitmap.Config.ARGB_8888);
    // 创建一张画布
    canvas = new Canvas(mBitmap);
    // 画布背景为白色
    canvas.drawColor(Color.WHITE);
    // 创建画笔
    paint = new Paint();
    // 画笔颜色为蓝色
    paint.setColor(Color.BLUE);
    // 宽度5个像素
    paint.setStrokeWidth(5);
    // 先将白色背景画上
    canvas.drawBitmap(mBitmap, new Matrix(), paint);
    img.setImageBitmap(mBitmap);
    img.setOnTouchListener(new OnTouchListener() {
      int startX;
      int startY;
      @Override
      public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
          // 获取手按下时的坐标
          startX = (int) event.getX();
          startY = (int) event.getY();
          break;
        case MotionEvent.ACTION_MOVE:
          // 获取手移动后的坐标
          int endX = (int) event.getX();
          int endY = (int) event.getY();
          // 在开始和结束坐标间画一条线
          canvas.drawLine(startX, startY, endX, endY, paint);
          // 刷新开始坐标
          startX = (int) event.getX();
          startY = (int) event.getY();
          img.setImageBitmap(mBitmap);
          break;
        }
        return true;
      }
    });
  }
}

有人肯定要问,能不能把绘制的内容保存下来,这当然可以。

加上如下代码就行。

File file = new File(Environment.getExternalStorageDirectory(),
    System.currentTimeMillis() + ".jpg");
OutputStream stream;
try {
   stream = new FileOutputStream(file);
   mBitmap.compress(CompressFormat.JPEG, 200, stream);
   stream.close();
} catch (IOException e) {
  e.printStackTrace();
}

附:完整实例代码点击此处本站下载

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android开发动画技巧汇总》、《Android开发入门与进阶教程》、《Android视图View技巧总结》、《Android编程之activity操作技巧总结》、《Android文件操作技巧汇总》、《Android资源操作技巧汇总》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

您可能感兴趣的文章:

  • android实现简单的画画板实例代码
  • Android采用双缓冲技术实现画板
  • Android自定义SurfaceView实现画板功能
  • Android实现画板、写字板功能(附源码下载)
  • Android多媒体之画画板开发案例分享
  • 双缓冲技术实现Android 画板应用
  • Android画画板的制作方法
(0)

相关推荐

  • Android自定义SurfaceView实现画板功能

    接触了这么久的View,总不能一直停留在View里,现在开始呢,就要学习一个新的知识点:SurfaceView,实际上SurfaceView与View的原理都差不多,只是效率和渲染方式上,SurfaceView要优于View,这也是我们写这个的原因.今天就看看这个SurfaceView,好了,下面就是今天要说的效果. 界面很简单,就是一个按钮以及一个画板,先看看界面的代码吧 <LinearLayout xmlns:android="http://schemas.android.com/ap

  • 双缓冲技术实现Android 画板应用

    什么是双缓冲技术?双缓冲技术就是当用户操作界面完成后,会有一个缓冲区保存用户操作的结果. 为什么要使用双缓冲技术?拿Android 游戏开发来说,界面贞每次都是全部重画的,也就说画了新的,旧的就没了,所以需要使用双缓冲技术保存之前的内容. 如何实现双缓冲?使用一个Bitmap对象保留之前的画布即可. package com.example.phonegaptest; import android.content.Context; import android.graphics.Bitmap; i

  • android实现简单的画画板实例代码

    直接看代码,注释都写清楚了 复制代码 代码如下: public class MainActivity extends Activity { private ImageView iv; private Bitmap baseBitmap; private Canvas canvas; private Paint paint; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedIns

  • Android采用双缓冲技术实现画板

    本文实例为大家分享了Android实现画板的具体代码,采用的技术是双缓冲技术,供大家参考,具体内容如下 1.双缓冲技术的概念 所谓的双缓冲技术其实很简单,当程序需要在指定的View上进行绘制时,程序并不需要直接绘制到该View组件,而是先绘制到一个内存中的Bitmap图片上(就是缓冲),等内存中的Bitmap绘制好之后,再一次性将Bitmap绘制到View组件上. 2.Android采用双缓冲实现画板  实现的思路: 1).定义一个内存中图片,将他作为缓冲区Bitmap cacheBitmap

  • Android实现画板、写字板功能(附源码下载)

    前言 本文给大家分享一个使用Android开发写字板功能Dem.简单操作内存中的图像.对图像进行简单的处理.绘制直线.以达到写字板的效果 效果图如下 XML布局代码 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="

  • Android多媒体之画画板开发案例分享

    先看看效果: 其实画画板的原理很简单,就是首先记录下按下屏幕的点,然后每移动一下就让这两次移动的点连线,周而复始,图像就由很多条直线构成了. 核心代码 : public class MainActivity extends Activity implements OnClickListener,OnSeekBarChangeListener { private View red_view,green_view,blue_view; //控制画笔颜色的三块区域 private SeekBar se

  • Android画画板的制作方法

    本文实例为大家分享了Android画画板展示的具体代码,供大家参考,具体内容如下 main.xml布局 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_w

  • Android编程实现画板功能的方法总结【附源码下载】

    本文实例讲述了Android编程实现画板功能的方法.分享给大家供大家参考,具体如下: Android实现画板主要有2种方式,一种是用自定义View实现,另一种是通过Canvas类实现.当然自定义View内部也是用的Canvas.第一种方式的思路是,创建一个自定义View(推荐SurfaceView),在自定义View里通过Path对象记录手指滑动的路径调用lineTo()绘制:第二种方式的思路是,先用Canvas绘制一张空的Bitmap,通过ImageView的setImageBitmap()方

  • Android仿腾讯QQ实现滑动删除 附源码下载

    看了很多大神们的文章,感觉受益良多,也非常欣赏大家的分享态度,所以决定开始写Blog,给大家分享自己的心得. 先看看效果图: 本来准备在ListView的每个Item的布局上设置一个隐藏的Button,当滑动的时候显示.但是因为每次只要存在一个Button,发现每个Item上的Button相互间不好控制.所以决定继承ListView然后结合PopupWindow. 首先是布局文件: delete_btn.xml:这里只需要一个Button <?xml version="1.0"

  • Android开发实现实时检测蓝牙连接状态的方法【附源码下载】

    本文实例讲述了Android开发实现实时检测蓝牙连接状态的方法.分享给大家供大家参考,具体如下: 本程序能实时监听并检测Android蓝牙的连接状态,无论是通过界面上的switch按钮打开/关闭手机蓝牙,还是手动打开/关闭手机蓝牙,程序都能监听当前的状态. 一.软件界面 二.程序实现 ① switch开关--打开/关闭蓝牙 Switch switchTest = (Switch) findViewById(R.id.switch1); switchTest.setOnCheckedChangeL

  • Android开发实现横向列表GridView横向滚动的方法【附源码下载】

    本文实例讲述了Android开发实现横向列表GridView横向滚动的方法.分享给大家供大家参考,具体如下: Android 横向列表实现,可左右滑动,如下图 1. 主界面布局代码:activity_main.xml a.包裹HorizontalScrollView控件是GirdView横向滚动的基本条件 b.GirdView外包裹LinearLayout是java代码中参数设置的必要条件 <?xml version="1.0" encoding="utf-8"

  • Python实现的ftp服务器功能详解【附源码下载】

    本文实例讲述了Python实现的ftp服务器功能.分享给大家供大家参考,具体如下: python 具备强大的网络编程功能,而且代码简介,用简单的代码,就能实现一个功能强大的FTP 服务器.我亲自测试了这个 python ftp server. 代码下载,在文章的末尾处,整个部署介绍如下: 1. 环境, python 2.7.3 ,centos 6.2 . 2. 定义服务器ip ,端口等信息,可以在下载的源码中查看 listen_ip = "192.168.4.128" # ftp se

  • 微信小程序实现动态设置页面标题的方法【附源码下载】

    本文实例讲述了微信小程序实现动态设置页面标题的方法.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 ① WXML文件 <button bindtap="setBiaoTi1">标题1</button> <button bindtap="setBiaoTi2">标题2</button> <button bindtap="setBiaoTi3">标题3</button&g

  • 微信小程序获取手机系统信息的方法【附源码下载】

    本文实例讲述了微信小程序获取手机系统信息的方法.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 index.wxml布局文件代码 <view>手机型号:{{mobileModel}}</view> <view>手机像素比:{{mobileePixelRatio}}</view> <view>窗口宽度:{{windowWidth}}</view> <view>窗口高度:{{windowHeight}}</

  • 微信小程序使用image组件显示图片的方法【附源码下载】

    本文实例讲述了微信小程序使用image组件显示图片的方法.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 ① index.wxml 复制代码 代码如下: <image style="width: 300px; height: 300px; margin:10px;" mode="scaleToFill" src="{{imageSrc}}"></image> ② index.js Page({ data:{

  • 微信小程序获取手机网络状态的方法【附源码下载】

    本文实例讲述了微信小程序获取手机网络状态的方法.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 index.wxml布局文件代码 <view>手机网络状态:{{netWorkType}}</view> index.js逻辑文件代码 Page({ data: { netWorkType:'' }, onLoad: function () { var that=this wx.getNetworkType({ success: function(res) { that.s

  • Vue.js实现表格动态增加删除的方法(附源码下载)

    Vue.js Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们能够快速地上手并使用Vue.js. 先来看看实现的效果: 下面的例子会用到bootstrap.min.css以及vue.js,都可以从网上下载(文末有完整源码下载提供). 实例 源码 <!DOCTYPE html> <html lang="en"> <head&g

随机推荐