最近半年一直在忙公司的GIS SDK,底层是公司的C++大佬来实现,我负责实现framework层,这不,大佬觉得C++实现的放大镜控件扩展性太差,就让我用AndroID自定义一个放大镜控件,方便后期扩展,要求嘛,和C++实现的要一模一样,手指触摸地图,放大触摸点的图像。
1.需求分析需求:手指拖拽节点的时候,放大镜出现,放大触摸点的图像,放大镜可以随着手指移动,放大镜不允许出现移出屏幕外的 *** 作,放大镜需要有拟物效果。
实现方案:去网上找了一下,大致为:加载整个界面的Bitmap,然后手指移动,然后裁剪手指的这个范围的画布,然后再放大绘制出来,问题来了,我的需求是在地图上实现放大镜,地图是可以拖动的,不可能地图随便拖动一点,就更新一个新的Bitmap,那得卡死,最好是只获取手指触摸点的那块的小范围的Bitmap,去看了一下地图控件,是一个SurfaceVIEw,那是不是可以用OPENGL 来获取;
图:
2.开始着手分析绘制过程:1.获取手指触摸范围的Bitmap对象,看是否可行,不就就白搭:
代码如下:
/** * @param x 手指的位置 * @param y 手指的位置 * @param wIDth 放大镜的大小 * @param height 放大镜的大小 * @return */private androID.graphics.Bitmap readBufferPixelToBitmap(int x, int y, int wIDth, int height) { ByteBuffer buf = ByteBuffer.allocateDirect(wIDth * height * 4); buf.order(ByteOrder.liTTLE_ENDIAN); GLES20.glreadPixels(x, y, wIDth, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); buf.rewind(); androID.graphics.Bitmap bmp = androID.graphics.Bitmap.createBitmap(wIDth, height, androID.graphics.Bitmap.Config.ARGB_8888); bmp.copyPixelsFromBuffer(buf); Matrix m = new Matrix(); // 水平翻转 m.setScale(1, -1); int w = bmp.getWIDth(); int h = bmp.getHeight(); // 生成的翻转后的bitmap bmp = androID.graphics.Bitmap.createBitmap(bmp, 0, 0, w, h, m, true); return bmp; }
2.测试了一下,Bitmap拿到了,那就很香了,剩下的一步就是把放大镜绘制出来,先不考虑放大镜随手指移动的情况,先实现放大镜效果:
@OverrIDe protected voID onDraw(Canvas canvas) { if (bm != null) { //背景防止加载自带透明的图片时,放大图片后面能看到原来的图片 Paint paintBg = new Paint(); //抗锯齿 paintBg.setAntiAlias(true); paintBg.setcolor(color.parsecolor("#ffffff")); canvas.drawCircle(magnifIErLen / 2, magnifIErLen / 2, magnifIErLen / 2, paintBg); Paint paint = new Paint(); paint.setFlags(Paint.ANTI_AliAS_FLAG); //抗锯齿 paint.setAntiAlias(true); //bitmapShader画圆形图片,也就是获取到的bitmap paint.setShader(bitmapShader); //创建矩阵,缩放平移图片 Matrix matrix = new Matrix(); matrix.setScale(scaleX, scaleY); //将获取到的图片平移到图片的正中心 matrix.postTranslate(-magnifIErLen/2, -magnifIErLen/2); //利用bitmapShader画圆形图片 bitmapShader.setLocalMatrix(matrix); canvas.drawCircle(magnifIErLen / 2, magnifIErLen / 2, magnifIErLen / 2, paint); //设置一个蒙层效果,让效果看起来更好 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.magnifIErdest); // 获得图片的宽高 int wIDth = bitmap.getWIDth(); int height = bitmap.getHeight(); // 设置想要的大小 int newWIDth = (int) magnifIErLen; int newHeight = (int) magnifIErLen; // 计算缩放比例 float scaleWIDth = ((float) newWIDth) / wIDth; float scaleHeight = ((float) newHeight) / height; // 取得想要缩放的matrix参数 Matrix matrix1 = new Matrix(); matrix1.postscale(scaleWIDth, scaleHeight); // 得到新的图片 Bitmap newbm = Bitmap.createBitmap(bitmap, 0, 0, wIDth, height, matrix1, true); //创建一个画笔 Paint paintShade = new Paint(Paint.ANTI_AliAS_FLAG); paintShade.setAlpha(magnifIErAlpha); //重置画笔 paintShade.reset(); //调用截图图层的方法 paintShade.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); //画图片 canvas.drawBitmap(newbm, 0, 0, paintShade); } }
3.因为不是需要放大镜跟随手指,是需要放大镜跟随我的控件的拖拽节点,所以我去拖拽的监听方法里面去实时获取x,y,并拿到Bitmap(可以根据需求的不同,去对应的地方获取,比如Ontouch)
Bitmap bm = readBufferPixelToBitmap(x, y, vIEwW, vIEwH); //利用BitmapShader画圆,模式可以查询用法 BitmapShader bitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); activityWeakReference.get().runOnUiThread(new Runnable() { @OverrIDe public voID run() { //去从新绘制放大镜 invalIDate(); } });
4.功能基本就实现了,也没什么,最后处理一下,手指在上下左右四个边界和几个角度的特殊情况,避免出现手指挡出放大镜之类的影响用户看的情况:
x = (int) (dragInfo.getScreenPos().getX() - magnifIErLen / 2);//dragInfo为拖拽点信息 y = (int) (height - dragInfo.getScreenPos().getY() - magnifIErLen / 2); float x = dragInfo.getScreenPos().getX() - vIEwW; float y = dragInfo.getScreenPos().getY() - vIEwH; if (x>0&&y>0){ //正常情况放在手指头的左上角 setX(x); setY(y); }else if (x>0&&y<0){ //放在最顶上 setX(x); setY(0); }else if (x<0&&y>0){ //放在最左边 setX(0); setY(y); }else if (x<0&&y<0){ //在最顶上,向右平移一个单位 setY(0); setX(vIEwW); }
总结:因为这个放大镜不是固定位置,也不是写在xml中,我也就不考虑onMeasure了,直接只使用了onDraw绘制,如果遇到了需要去放大地图的情况,可以参考,就这样,,,
总结以上是内存溢出为你收集整理的Android自定义控件-地图之放大镜的实现全部内容,希望文章能够帮你解决Android自定义控件-地图之放大镜的实现所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)