安卓canvas实现拖动显示大背景图片
来源:互联网 发布:西西网络图绘制软件 编辑:程序博客网 时间:2024/06/06 02:07
我是个自学安卓开发的菜鸟,糊里糊涂地参加了一个安卓应用开发的项目。项目中有这样的需求:
一张很大的背景图,用户通过拖动来查看背景图的不同区域;背景图上还有小图片,也需要在背景图滑动的同时跟着一起动。
我一开始想,这还不好做嘛,直接把用ImageView控件显示图片,加一个触摸监听事件,根据触摸距离调整控件位置不就得了?然而第一个问题出现了:无法按照原大小显示图片。
↑我期望的效果
↑实际的效果
按照网上的说法,想要以原大小显示图片,只要在该ImageView控件里加这么一行:android:scaleType="matrix"
我加上之后,的确能够按照原大小显示图片了,然而我为ImageView添加了OnTouchListener之后,改变ImageView控件的位置,发现一开始未显示的图片,在滑动时也不能显示。
↑左图为未拖动的显示,右图为拖动之后的显示,可以看出,超出屏幕的图片在拖动控件之后并没有如期出现
当时我还百思不得其解,回想起来,这其实是因为ImageView是屏幕内的控件,即使把它设为
android:layout_width="wrap_content"android:layout_height="wrap_content"
ImageView的大小也不会超出屏幕的。所以在其内容超出屏幕大小时,ImageView的大小也依然是屏幕大小,滑动时是把ImageView移来移去,自然也不能指望着ImageView控件范围之外呈现出ImageView的内容。
那么解决方法也就出来了:
我不该移动ImageView的位置,而是应考虑滑动时需要把图片的哪一部分显示在ImageView中
↑蓝框表示ImageView控件,右边为我想显示的大图,被填充的区域为大图需要显示在ImageView中的部分
但是默认的ImageView似乎并没有这个功能,所以我决定试着写一个能实现上述功能的自定义View控件类。
这个控件的功能呢,就是被拖动时,计算在原图中需要截取的图片的起始位置。
你问我为什么不需要知道宽和高?因为宽和高就是获取到的设备屏幕的宽和高呀。
你问我怎么获取设备的宽和高?其实很简单,我也是从网上查的,贴在这好啦:
DisplayMetrics dm=new DisplayMetrics(); super.getWindowManager().getDefaultDisplay().getMetrics(dm);//dm.widthPixels和dm.heightPixels就是屏幕的宽和高啦//正如其变量名所示,是以像素为单位的
那么获取到显示图片的宽和高,该如何计算从哪个位置开始截取图片呢?
这里我们就需要重写View类的 onTouchEvent(MotionEvent event)
函数
//自定义View类的成员变量://lastX、lastY:上一个触摸点的位置坐标//startX、startY:截取图片相对于原图的起始坐标//bmWidth、bmHeight:原图的宽和高 @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { //手刚按下时,记录起始点的位置 case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); break; //手开始移动,获取此时手的位置,与起始位置做差 //得到移动位置和起始位置的差值dx、dy case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; //此处注意是减去dx和dy //因为手的拖动和图片截取的位置是个相对运动 //如:手从左往右,触摸点的x坐标在变大 //而截取图片的起始点x坐标在变小 //(新截取的图在原来截取的图的左边儿) startX-=dx; startY-=dy; //以下俩if..else是用来防止拖动到原图以外的区域 if(startX<0) { startX=0; } else if(startX+dm.widthPixels>bmWidth) { startX=bmWidth-dm.widthPixels; } if(startY<0) { startY=0; } else if(startY+dm.heightPixels>bmHeight) { startY=bmHeight-dm.heightPixels; } //再次获取当前的坐标作为下一次计算的起始值 lastX=(int) event.getRawX(); lastY=(int) event.getRawY(); //调用onDraw函数 invalidate(); break; case MotionEvent.ACTION_UP: break; } return true; }
这里得到的startX和startY就是截取图片相对于原图左下角的坐标啦。得到之后,得把它画出来啊,所以我还得把onDraw(Canvas canvas)
函数也重写一下:
//成员变量://bitmap:就是需要显示的原图啦//act:我放置自定义View控件的某个Activity@Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); //获取原图上需要截取的区域 Rect src=new Rect(startX,startY,startX+dm.widthPixels,startY+dm.heightPixels); //把需要在屏幕上绘制的区域框出来 Rect dst=new Rect(0,0,dm.widthPixels,dm.heightPixels); //在屏幕指定区域画出截取区域 canvas.drawBitmap(bitmap, src, dst, null); //大图上面有小图img_me,也需要跟着一起动 //因此在这里获取到activity里的img_me,改变其坐标 act.img_me.setTranslationX(-startX+1200); act.img_me.setTranslationY(-startY+600); }
这样,我自定义的View控件的核心功能就完成了,在触摸回调函数里计算截取区域的位置,在绘制回调函数里画出截取区域。
然后,就可以在Activity里放入这个控件以显示了~
<!--这是该Activity的布局文件里需要添加的--><com.test.my.MyView android:id="@+id/myView" android:layout_width="match_parent" android:layout_height="match_parent"/>
但是,运行时报错了,会是什么地方出错了呢?
嗯~自定义View一定不要忘记,要重写其构造函数哦!
//1个参数的构造函数//如果该View是用java代码创建的,那么就会调用此构造函数//这里其实没用到这个构造函数//不过为了保险起见还是写上为好public MyView(Context context) { super(context); // 此处进行了必要的初始化 bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.map3); bmWidth=bitmap.getWidth(); bmHeight=bitmap.getHeight(); }//2个参数的构造函数//如果该View直接添加到了xml布局文件里,会调用此函数public MyView(Context context, AttributeSet attrs) { super(context, attrs); // 此处进行了必要的初始化 bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.map3); bmWidth=bitmap.getWidth(); bmHeight=bitmap.getHeight(); }//3个参数的构造函数//这个没有必要加,因为如果你去看2参调用的super(context, attrs);//它调用的就是这个3参的构造函数public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 所以我就没在这加初始化 }
运行一下,诶,还是报错?
因为我一开始图省事儿,直接把该View类定义在需要显示它的Activity类的内部,作为一个内部类。而我估计在读取xml布局文件时,内部类还没有被编译,所以提示“找不到控件类”。
所以还需要注意:自定义控件需要单独写在一个类里。
然后万事大吉~现在可以任意的拖动大图片查看它的各个部分啦!
要说这个可以应用在何处?我猜用JAVA和Eclipse开发的安卓游戏里,如果需要查看大地图的话,应该就可以用这个方法解决吧~
不过我想一定也有其他的好的解决方法,如果你知道的话,请一定告诉我><我也想多学点儿呢
- 安卓canvas实现拖动显示大背景图片
- 安卓大图显示不OOM方案,极简代码,实现拖动、缩放等功能
- 安卓添加背景图片
- 设置安卓背景图片
- 安卓拖动条
- 安卓控件拖动
- 安卓实现Iphone的图片拖动效果
- 安卓canvas
- 安卓Canvas
- 安卓拖动条(SeekBar)
- 【实例】html5-canvas中实现背景图片的移动
- JS canvas实现图片显示
- 安卓Canvas类介绍
- 安卓api canvas.drawText()
- [转]CSS实现背景图片部分显示
- 在div底部显示背景图片实现代码
- HTML+CSS实现背景图片全屏显示
- 安卓实现显示记住密码
- KMP字符串模式匹配详解
- 树的父指针表示法(并查算法 重量权衡合并规则 路径压缩)
- 逆序与回文
- C语言第二章:运算符
- Perl中use strict
- 安卓canvas实现拖动显示大背景图片
- 浏览器插件之ActiveX开发
- Hello World!
- Android应用中OOM问题剖析和解决方案
- Corona学习之composer<1>
- Perl中的函数的定义和使用
- uvaoj 10253 - Series-Parallel Networks
- 指针就算指向了常量也不能修改这个常量
- Python代码的多线程改造