十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
android界面实现整体缩放
创新互联公司是一家专业从事网站建设、网络营销、微信小程序定制开发、网站运营为一体的建站企业;在网站建设告别千篇一律,告别似曾相识,这一次我们重新定义网站建设,让您的网站别具一格。响应式网站建设,实现全网营销!一站适应多终端,一样的建站,不一样的体验!
代码:
float basevectorX = 0.0f
float basevectorY = 0.0f
//浮点坐标 左上角坐标
float FfrogX = 0.0f;
float FfrogY = 0.0f;
//整形坐标 左上角坐标
int frogX = 0;
int frogY = 0;
Rect rect = new Rect();
FfrogX = FfrogX+basevectorX;
frogX = (int)FfrogX;
FfrogY = FfrogY+basevectorY;
frogY = (int) FfrogY;
rect.left= frogX;
rect.right= ScreenWidth-rect.left-Width; //640
rect.top= frogY; //480
rect.bottom= ScreenHeight-rect.top-Height; //480
((MarginLayoutParams) frogview.getLayoutParams()).setMargins(rect.left, rect.top, rect.right, rect.bottom);
//这个可以放 大缩小,和移动。
CenterX = rect.left + Width/2; //中心点X坐标 用来判断的 用于2d
CenterY = rect.top + Height/2; //中心点Y坐标 用来判断的 用于2d
android 缩放和压缩图片可以如下解释:
压缩图片
这里简单的将一个图片文件转换为 Bitmap ,并且在转换的过程中对图片质量进行简单压缩:
bitmap.compress(Bitmap.CompressFormat.JPEG, int quality, FileOutputStream fos);
注意这里的 quality 的范围为 0~100 ,经过测试如果这个值设置比较低的话图片会非常不清晰, 基本不可用, 0~100 的值可以参考类似Photoshop之类输出图片时选择的图片质量.
此方法只是单纯对图片质量进行处理, 并不会改变其大小, 如果需要改变图片文件的大小, 最好是使用缩放, 这个可以在保证一定的图片清晰度的情况下减少了图片大小, 毕竟手机屏幕就那么点, 你把 2000px * 1000px 的图片改为 500px * 250px 在手机用户看来也不会有太严重的不适感, 而如果你只设置图片的 quality 想来改变文件大小, 你最后会发现得到的是一个 2000px * 1000px 的几个色块.
缩放图片
先提代码看看:
[java] view plain copy
/**
* 保持长宽比缩小Bitmap
*
* @param bitmap
* @param maxWidth
* @param maxHeight
* @return
*/
public Bitmap resizeBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
int originWidth = bitmap.getWidth();
int originHeight = bitmap.getHeight();
// no need to resize
if (originWidth maxWidth originHeight maxHeight) {
return bitmap;
}
int width = originWidth;
int height = originHeight;
// 若图片过宽, 则保持长宽比缩放图片
if (originWidth maxWidth) {
width = maxWidth;
double i = originWidth * 1.0 / maxWidth;
height = (int) Math.floor(originHeight / i);
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
}
// 若图片过长, 则从上端截取
if (height maxHeight) {
height = maxHeight;
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
}
// Log.i(TAG, width + " width");
// Log.i(TAG, height + " height");
return bitmap;
}
这里演示是将图片缩小到一个max范围内, 而不是直接将变成硬性的变成某个尺寸的图片, 因为一般来说这种设置max的方式符合大部分需要, 如果必须将图片变成某个指定尺寸可以直接使用 Bitmap.createScaledBitmap 方法, 也是下面要介绍的.
此函数主要就是使用了 Bitmap 的两个静态方法, 一个是:
public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
此方法就会把一个 Bitmap 图片 缩放 成指定的尺寸.
先上效果图
源码
单点拖动图片对图片进行平移操作。双手缩放图片大小和旋转图片到一定的角度。图片缩放的时候 不能大于最大的缩放因子和小于最小的缩放因子。大于最大缩放因子或者小于最小缩放因子需要对图像进行回弹。图片旋转的角度只能为90度的倍数,不满足90度要进行回弹。图片回弹要一个渐变的效果。
大体思路: 首先,Android中提供了Matrix类可以对图像进行处理。其次,要显示一张图片最容易想到的就是ImageView。回弹要求渐变的过程,可以通过属性动画进行设置。所以大体的思路是:继承ImageView,重写onTouchEvent()方法,判断事件类型,在对应的事件使用Matrix对图像进行变换。
Matrix是一个已经封装好的矩阵,最重要的作用就是对坐标点进行变换。
举个栗子:
1.某个点(x0,y0,1)通过单位矩阵E映射得到的点还是(x0,y0,1)。
3.点(x0,y0,1)通过矩阵T映射得到的点就会做如下的变换
可以看到点(x0,y0,1)经过T矩阵在x轴方向上平移了dx,在y轴方向上平移了dy。
通过以上的变换可以得到具体的思路: 我们维护一个图像对应的矩阵mCurrentMatrix,该矩阵主要是对ImageView中的图像的各个点进行映射。ImageView在容器位置摆放完成之后,置mCurrentMatrix矩阵为单位矩阵。当onTouchEvent()方法中触发单点触控并且手指进行平移的时候,调用矩阵mCurrentMatrix的postTranslate(dx,dy),对mCurrentMatrix进行变换。当手指抬起,利用变换结束后的矩阵对图像的各个点进行映射,从而得到平移变换后的图像。同理可得,在两只手指进行缩放旋转的时候,我们对矩阵mCurrentMatrix进行各种变换,当缩放旋转的事件结束再利用变换完的矩阵去映射图像的各个点,从而得到缩放、旋转后的图像。
安卓自定义View进阶 - Matrix原理
安卓自定义View进阶 - Matrix详解
首先理清事件的逻辑:
初始化图像大小和位置
缩放图像大小和控件大小自适应,平移图像中心和控件中心重合
onTouchEvent()函数
平移操作
将图像对应的矩阵进行变换。
缩放操作
mBoundRectF为记录图像边界的矩形。缩放的时候选取图像的中心进行缩放。
旋转操作
旋转的时候旋转的旋转中心也是图像的中心
图像中各个点的映射
调用ImageView的setImageMatrix(Matrix matrix)会让ImageView根据设置的matrix去重新绘制图像。
更新图像的矩形边界
获得图像的矩形,并根据矩阵映射矩形各个点的坐标。
缩放回弹
旋转回弹
一些计算方法
要求图像的变换是一个渐变的过程,很容易想到的就是属性动画。因为属性动画本身就是对值进行不断set的过程。而我们维护的矩阵也是一个值,所以很自然可以想到,如果得到回弹之前的矩阵的值以及回弹之后矩阵的值,就可以根据动画监听器中动画当前的系数值去改变矩阵的值。
对animator对象设置完监听器之后,就可以在手指抬起的时候调用属性动画的start()方法开启动画。
自定义可平移、缩放、旋转的控件主要点有两个方面:一是onTouchEvent()中判断平移、旋转、缩放的触发条件,平移位移量、缩放比例因子、旋转角度的计算。二是Matrix矩阵的应用。
将以下代码写到MulitPointTouchListener.java中,然后对你相应的图片进行OnTouchListener。
例如:imageView.setOnTouchListener(new MulitPointTouchListener ());
在xml中要将ImageView的缩放格式改成Matrix
例如:android:scaleType="matrix"
就可以实现android界面整体缩放
下面是MulitPointTouchListener.java代码:public class MulitPointTouchListener implements OnTouchListener { private static final String TAG = "Touch"; // These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; // Remember some things for zooming PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; // Log.e("view_width", // view.getImageMatrix()..toString()+"*"+v.getWidth()); // Dump touch event to log dumpEvent(event); // Handle touch events here... switch (event.getAction() MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: matrix.set(view.getImageMatrix()); savedMatrix.set(matrix); start.set(event.getX(), event.getY()); //Log.d(TAG, "mode=DRAG"); mode = DRAG; //Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); //Log.d(TAG, "oldDist=" + oldDist); if (oldDist 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; //Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; //Log.e("view.getWidth", view.getWidth() + ""); //Log.e("view.getHeight", view.getHeight() + ""); break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { // ... matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); //Log.d(TAG, "newDist=" + newDist); if (newDist 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); return true; // indicate event was handled } private void dumpEvent(MotionEvent event) { String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action MotionEvent.ACTION_MASK; sb.append("event ACTION_").append(names[actionCode]); if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) { sb.append("(pid ").append( action MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append(")"); } sb.append("["); for (int i = 0; i event.getPointerCount(); i++) { sb.append("#").append(i); sb.append("(pid ").append(event.getPointerId(i)); sb.append(")=").append((int) event.getX(i)); sb.append(",").append((int) event.getY(i)); if (i + 1 event.getPointerCount()) sb.append(";"); } sb.append("]"); //Log.d(TAG, sb.toString()); } private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } }