Android 在ViewPager中使用的可以画线,放大,保存,点击删除线条的自定义图片显示控件

之前那篇文章记录了我学习图片上批注的过程, http://blog.csdn.net/baidu_33546245/article/details/55684699

不过上述的那个项目只是作为学习原理的代码,离真实的项目需求还是有很大差距的,
本来是想等功能稳定后补全下代码…但是前段空闲时间在学习python爬虫,再加上日常工作比较忙,就没有继续更新.

直到前几天打开github,发现有人竟然star了我的那个项目,荣获人生中第一个star,欣喜若狂,周末决定开坑继续把该模块碰到的坑全部补全.

分解例一下还需要做哪些方面的改进:

  1. 之前的项目是继承了view的一个控件,而实际使用时我们显示图片的view有很大可能要放到viewpager这种滑动列表中去,并且真实项目中去调用这个功能所需的代码的不可能太多,
    否则很影响其它人的开发效率.

  2. 我们想要在图片上进行绘制,必须在滑动列表中,找到当前view的对象.

  3. 在真实业务逻辑中保存绘制,不同大小图片的点,就必须先知道图片的宽高,这对业务逻辑开展是非常不利的,意味着业务代码会增加很多.

  4. 增加一些其它的功能,如绘制正方形,椭圆,箭头(因为箭头的算法是一个大神同事写的,暂时不上传),还有点击某个线条删除.

双缓冲绘制

首先,先了解一下双缓存绘制的概念,如果我们每次刷新都去重新绘制的话,图形比较少的话,可能没有什么问题.而如多一旦绘制了上百条线,每次刷新对处理器来说都是很大的压力.,所以要使用双缓冲机制,

Android第一个缓冲区就是在我们的onDraw方法里,可以尝试在onDraw里先绘制一个圆形,过1s再绘制一个正方形,你会发现圆形和正方形是一起被画出来的,并没有像我们想象的那样,首先出现圆形,再出现正方形(这个结论并没有试过,是看的hongyang大神的博客里的结果).这是因为onDraw是把信息先画到缓冲区,然后再统一画到画布上,这就是第一个缓冲.

第二个缓冲区是由我们手动创建控制的的,就是用一个bitmap去记录历史绘制信息,

 mCanvasBitmap = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_4444);
 mCanvas = new Canvas(mCanvasBitmap);

画线的时候:在手指按下,移动的时候,直接在绘制当前一次操作按下移动的轨迹,等手指抬起就就把刚才一笔信息画在mCanvasBitmap上,这样就有效防止了过度绘制…

1, 使用Glide加载自定义控件

为了解决1,我们就需要使用一些安卓常用的图片加载控件来加载我们的图片,我选择了Glide,

因为控件初始化的时候需要知道图片实际的宽高,以便确定后摆在屏幕中间.考虑到在viewPager中的使用以及使用Glide这种控件进行加载,所以自定义控件还是继承ImageView好,

最开始采用了监听图片布局全局变化的方法,判断长宽大于bitmap的长宽就自动赋值的方法.后来在测试时发现,这种方法有可能控件的长宽有可能不大于bitmap的长宽,就造成了初始化图片失败.

后来简单看了一下Glide的源码,发现它加载图片最终会调用imageview的setImageDrawable()的方法..于是就把初始化的代码放在seetImageDrawable后执行.

2,在ViewPager中找到当前的位置的对象

解决第二个问题:

在viewpager滑动中,必须根据当前位置找到当前页的图片对象,我的做法是给加载的图片设置当前位置的TAG,然后记录当前位置,
在viewpager中根据位置寻找当前位置的画板对象,然后操作PaintImageView,我是用Glide加载图片的,因为Glide默认使用了setTag的方法,
所以我们需要给Glide指定一个其它标记,在初始化时,让Glide使用我们设置的标记,这样我们就可以设置标记了

//初始化Glide的代码(清单文件中)
<meta-data
            android:name="com.demo.drawpaintview.MyGlideMoudle"
            android:value="GlideModule" />
`//初始化时改变Glide的TAG``

public class MyGlideMoudle implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        ViewTarget.setTagId(R.id.glide_tag_id);
    }

    @Override
    public void registerComponents(Context context, Glide glide) {

    }
}

3, 建立逻辑坐标系,简化交互流程

解决第三个问题:
为了简化信息传输,初始化逻辑,我们将拿到的点转化为(100,100)坐标系的相对位置,这样的好处就是,无须知道图片的宽高,只要两台设备有相同的该张图片,就可以根据自己测量的图片宽高来初始化点线,一定程度上减少了业务的同步交互逻辑.

也就是说现在是这个流程:
我们拿到的触摸点 —> 按当前矩阵求逆,获取在图片上的原始坐标系的相对点 ——–>
x,y分别除以宽,高,再 * 100,获取逻辑(logic)坐标系内的点——–>
实时发送给其它设备或者实时记录到数据库,内存, —–>
将逻辑坐标系的点根据当前的图片宽高,还原到绘制坐标系, ——>
使用绘制坐标系的点绘制.

该模块处理坐标系的相关代码被统一抽出到TransPoint类中…

4,绘制长方形和椭圆,增加点击线条删除的逻辑

1,画长方形: 长方形只需要知道起始点和最终点就可以了,直接调用Android的 canvas.drawRect(dx, sy, sx, dy, paint);方法

2,画椭圆: 椭圆同样很简单, 直接ctrl + p 查看要传的参数,发现可以传一个长方形确定椭圆,canvas.drawOval(new RectF(moveX, moveY, downX, downY), mPaint);

3,点击线条删除: 点击某个线条删除就比较麻烦了,我是这样做的,:
把所有的线条生成相应的path —->
然后根据path生成一个图形 ——->
根据触摸点生成一个长方形 ———>
判断两个长方形是否相交———–>
如果相交,就返回当前一笔的id,根据id,删除掉图形中的那条直线————->
重新绘制图形…

最后仍然附上代码的github地址,大家可以去看一下代码:
https://github.com/textview10/DrawPaintView

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值