废话不多说,直接代码。该imageview 只能代码里new出来使用。不能xml布局配置。有空再修改成可以配置使用的。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
float x_down = 0;
float y_down = 0;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float oldRotation = 0;
Matrix matrix = new Matrix();
Matrix matrix1 = new Matrix();
Matrix savedMatrix = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
int mode = NONE;
boolean matrixCheck = false;
int widthScreen;
int heightScreen;
//变换类型
private static final int TYPE_WIDTH = 1;//只变宽度
private static final int TYPE_HIGHT = 2;//只变高度
private static final int TYPE_ALL = 3;//宽高都变
private static final int TYPE_NONE = 4;//无变换
Bitmap gintama;
public TouchImageView(Context ctx, Bitmap bmp, int screenWPix, int screenHPix) {
super(ctx);
gintama = bmp;
widthScreen = screenWPix;
heightScreen = screenHPix;
matrix = new Matrix();
initBitmap();
}
@Override
public void setImageBitmap(Bitmap bm) {
// TODO Auto-generated method stub
gintama = bm;
initBitmap();
}
@Override
public void setImageResource(int resId) {
// TODO Auto-generated method stub
gintama = BitmapFactory.decodeResource(getResources(), resId);
initBitmap();
}
protected void onDraw(Canvas canvas) {
if(gintama == null) return;
canvas.save();
canvas.drawBitmap(gintama, matrix, null);
canvas.restore();
}
private void initBitmap()
{
if(gintama == null) return;
float srcWidth = gintama.getWidth();
float srcHight = gintama.getHeight();
matrix.reset();
//偏移屏幕宽度的10%像素
float offset = widthScreen * 0.1f;
float width = widthScreen - offset;
float hight = heightScreen - offset;
//初始化移动距离
float dx = (widthScreen - srcWidth)/2f;
float dy = (heightScreen - srcHight)/2f;
int type = TYPE_NONE;
float scale = 1f;
if(srcWidth > width)
{
scale = width / srcWidth;
type = TYPE_WIDTH;
if(srcHight > hight)
{
float temp = hight / srcHight;
type = TYPE_ALL;
if(scale > temp)
{
scale = temp;
}
}
}else{
if(srcHight > hight)
{
scale = heightScreen / srcHight;
type = TYPE_HIGHT;
}
}
if(scale != 1f){
//缩放
matrix.postScale(scale, scale);
}
//移动
switch(type)
{
case TYPE_ALL:
case TYPE_HIGHT:
case TYPE_WIDTH:
dx = (widthScreen - srcWidth * scale) / 2f;
dy = (heightScreen - srcHight * scale) / 2f;
break;
}
matrix.postTranslate(dx, dy);
invalidate();
}
private long begin,end;
public boolean onTouchEvent(MotionEvent event) {
if(gintama == null) return super.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
begin = System.currentTimeMillis();
x_down = event.getX();
y_down = event.getY();
savedMatrix.set(matrix);
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
oldDist = spacing(event);
oldRotation = rotation(event);
savedMatrix.set(matrix);
midPoint(mid, event);
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM) {
matrix1.set(savedMatrix);
float rotation = rotation(event) - oldRotation;
float newDist = spacing(event);
float scale = newDist / oldDist;
matrix1.postScale(scale, scale, mid.x, mid.y);// 縮放
matrix1.postRotate(rotation, mid.x, mid.y);// 旋轉
matrixCheck = matrixCheck();
if (matrixCheck == false) {
matrix.set(matrix1);
invalidate();
}
} else if (mode == DRAG) {
matrix1.set(savedMatrix);
matrix1.postTranslate(event.getX() - x_down, event.getY()
- y_down);// 平移
matrixCheck = matrixCheck();
if (matrixCheck == false) {
matrix.set(matrix1);
invalidate();
}
}
break;
case MotionEvent.ACTION_UP:
end = System.currentTimeMillis();
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
//点击时间区分是否是关闭
if((end - begin) < 150)
{
return super.onTouchEvent(event);
}else{
return true;
}
}
private boolean matrixCheck() {
float[] f = new float[9];
matrix1.getValues(f);
// 图片4个顶点的坐标
float x1 = f[0] * 0 + f[1] * 0 + f[2];
float y1 = f[3] * 0 + f[4] * 0 + f[5];
float x2 = f[0] * gintama.getWidth() + f[1] * 0 + f[2];
float y2 = f[3] * gintama.getWidth() + f[4] * 0 + f[5];
float x3 = f[0] * 0 + f[1] * gintama.getHeight() + f[2];
float y3 = f[3] * 0 + f[4] * gintama.getHeight() + f[5];
float x4 = f[0] * gintama.getWidth() + f[1] * gintama.getHeight() + f[2];
float y4 = f[3] * gintama.getWidth() + f[4] * gintama.getHeight() + f[5];
// 图片现宽度
double width = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
// 缩放比率判断
if (width < widthScreen / 3 || width > widthScreen * 3) {
return true;
}
// 出界判断
if ((x1 < widthScreen / 3 && x2 < widthScreen / 3
&& x3 < widthScreen / 3 && x4 < widthScreen / 3)
|| (x1 > widthScreen * 2 / 3 && x2 > widthScreen * 2 / 3
&& x3 > widthScreen * 2 / 3 && x4 > widthScreen * 2 / 3)
|| (y1 < heightScreen / 3 && y2 < heightScreen / 3
&& y3 < heightScreen / 3 && y4 < heightScreen / 3)
|| (y1 > heightScreen * 2 / 3 && y2 > heightScreen * 2 / 3
&& y3 > heightScreen * 2 / 3 && y4 > heightScreen * 2 / 3)) {
return true;
}
return false;
}
// 触碰两点间距离
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);
}
// 取旋转角度
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
相关推荐
【标题】"图片缩放、拖动、自动居中 (工具类)" 描述了一种用于处理图片显示的技术,它涉及到图像处理、用户交互以及界面布局等多个方面。在UI设计和开发中,这样的功能是非常常见的,尤其在移动应用或桌面应用中,...
当我们在Android应用中加载图片时,有时需要对图片进行自动缩放,以适应不同的屏幕尺寸和分辨率,确保用户体验良好。本文将深入探讨如何在Android的布局中实现图片的自动缩放。 首先,我们来理解一下为什么需要对...
7. **资源尺寸适配**: 为了在不同分辨率的设备上提供良好的视觉体验,开发者应根据Android的密度独立像素(dp)和屏幕密度(dpi)来适配图片资源。使用不同的资源目录(如hdpi, xhdpi等)存放不同尺寸的图片,系统会...
在实际项目中,可能还需要考虑图片加载库如Glide或Picasso的使用,它们在加载网络图片时能自动处理图片的缩放和尺寸适配。例如,使用Glide可以这样加载图片: ```java Glide.with(context) .load("your_image_url...
例如,CENTER_CROP保持宽高比填充视图,FIT_CENTER按比例缩放图片居中显示。 5. 自定义View:在处理复杂的图片显示,如微博长图时,可能需要自定义View来实现特定功能,比如滚动和缩放。这可能涉及到计算视图的滚动...
3. **自动适配和居中**:为了让图片在不同尺寸的屏幕上都能正确显示,需要使用`LayoutParams`来调整`ImageView`的布局参数,实现自动适应屏幕宽度或高度。同时,通过设置`Gravity.CENTER`可以使图片在`ImageView`内...
通过设置ImageView的scaleType属性,可以控制图片在视图中的显示方式,如居中、填充、缩放等。源码中可能会对ImageView进行定制,以满足特定的图片浏览需求。 3. **手势识别**:为了实现图片的滑动浏览,源码中会...
因此,通常会使用图片加载库,如Glide、Picasso或 Fresco,它们能进行图片的内存和磁盘缓存管理,并支持按需加载和缩放图片,减少内存占用。 7. **性能优化**: 当图片过大时,需要考虑使用`BitmapFactory.Options...
对于图片的适配,`ImageView`的`android:scaleType`属性至关重要,它决定了图片如何根据ImageView的大小进行缩放和移动。常见的取值有: - `center`:图片居中显示,不缩放。 - `centerCrop`:保持宽高比缩放图片,...
在Android开发中,ImageView是用于显示图像的常见控件,其ScaleType属性是决定图片如何在ImageView内适配的关键设置。本篇文章将深入探讨ImageView的ScaleType属性,并通过源码解析来理解其工作原理。 ScaleType...
例如,`centerCrop`可以使图片保持纵横比填充`ImageView`,`fitCenter`则会居中显示并保持比例,而`matrix`则允许自定义矩阵进行更复杂的缩放和位移操作。对于图片的放大,可以结合手势识别库(如`GestureDetector`...
对于图片的展示,`android:scaleType`是ImageView的重要属性,它决定了图片如何缩放以适应ImageView的大小。常见的取值有center、centerCrop、centerInside等,开发者可以根据需求选择合适的缩放模式。 总的来说,...
6. 当图片加载时,可以通过调整Matrix确保图片居中显示,并适配屏幕大小。 需要注意的是,事件分发机制也是关键。通常,Activity或Fragment会先接收到触摸事件,然后通过`dispatchTouchEvent()`分发给View。我们...
3. **图片缩放**:在描述中提到了“图片缩放”,在Android中,我们可以使用`ImageView`的`scaleType`属性来控制图片的显示方式,比如`centerCrop`用于填充视图,`fitCenter`则保持宽高比居中显示。若需要用户手动...
在实际项目中,你可能还需要考虑其他细节,比如手势冲突的处理、触摸事件的分发、以及在不同设备和屏幕尺寸上的适配等。此外,对于复杂的滑动和缩放效果,可能还需要借助`RecyclerView`、`PagerAdapter`等组件来实现...
4. **图片适配**:为了适应不同尺寸的屏幕,可以使用比例缩放或者使用Nine-Patch图片。Nine-Patch是一种特殊格式的图片,可以定义拉伸区域,使得图片在不同尺寸下仍保持正确显示。 5. **手势操作**:为了提供更丰富...
5. **图片加载库**:Glide和Picasso是Android中常用的图片加载库,它们能高效地加载网络和本地资源图片,自动处理内存缓存和磁盘缓存,支持图片的裁剪、圆角、模糊等效果,同时提供了一种优雅的方式来解决图片加载的...
在实际应用中,这种技术可以用于处理图片的适配,特别是在响应式设计中,确保图片在各种分辨率和尺寸的屏幕上都能正确显示。同时,这也体现了Android开发中灵活性和自定义性的特点,开发者可以根据具体需求调整和...
在显示图片时,可能需要对图片进行缩放和裁剪以适应`ImageView`的大小。`BitmapFactory.Options`类可以用于控制图片的解码过程,减少内存占用。`Matrix`类可用于动态调整图片的缩放和平移。 5. **手势检测**: `...
除了`src`,还可以使用`android:scaleType`属性来控制图片的缩放方式,如填充、居中、按比例缩放等。 5. Toast: Toast是一种轻量级的信息提示组件,它不会占用屏幕空间,用户可以继续执行当前操作,而不会被打断。...