自定义ImageView
来源:互联网 发布:淘宝怎么装修店铺视频 编辑:程序博客网 时间:2024/05/16 02:18
继续坚持写博客,懒毛病尽快改掉。今天写了一个图片查看控件。初步功能具有移动,缩放效果。并且限制了移动的范围,使它不能完全移出边界。放大倍数限制默认给了4,有特别需要的同学可以自己修改,给个自定义参数来设置。双击图片能还原回初始大小和中间对齐的状态。效果图如下:
上面是初始中间对齐状态。
这个是移动状态
这个是缩放状态。
好了,下面贴上代码:
package com.example.huangyi.test.widge;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PointF;import android.graphics.RectF;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.support.annotation.Nullable;import android.support.v4.view.GestureDetectorCompat;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import com.example.huangyi.test.R;/** * Created by huangyi on 17-5-25. */public class ZoomImageView extends View { private static final int DEF_SIZE = 200; private static final float MAX_MULTIPLE = 4; //允许放大的最大倍数 private static final float SIZDE_PADDING = 50; //最大剩余的值,不让全移除边界 private Bitmap mBitmap; private Paint mPaint; private Matrix mMatrix; //用于对图片进行变换的矩阵 private RectF originalRect; //图片初始时边框所对应的矩形 private RectF translateRect; //变换后图片边框所对应的矩形 private int pointer = 0; //触摸点个数 private PointF lastP = new PointF(); //在移动图片中,记录上一次的触摸点 private int lastPId = -1; //在移动图片中,上次触摸点的id,避免多根手指触摸,然后第一根抬起后造成图片跳动 private float lastDistance = -1; //缩放图片时,上一次两个手指的距离. private GestureDetectorCompat gestureDetector; public ZoomImageView(Context context) { super(context); init(context,null); } public ZoomImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public ZoomImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context,attrs); } private void init(Context context, AttributeSet attrs){ if(attrs != null){ TypedArray ta = context.getResources().obtainAttributes(attrs, R.styleable.ZoomImageView); Drawable image = ta.getDrawable(R.styleable.ZoomImageView_ximage); mBitmap = drawable2Bitmap(image); ta.recycle(); } mPaint = new Paint(); mPaint.setAntiAlias(true); mMatrix = new Matrix(); translateRect = new RectF(0,0,mBitmap.getWidth(),mBitmap.getHeight()); originalRect = new RectF(translateRect); ZoomGestureListener zoomGestureListener = new ZoomGestureListener(); gestureDetector = new GestureDetectorCompat(getContext(),zoomGestureListener); gestureDetector.setOnDoubleTapListener(zoomGestureListener); } //双击就使图片恢复初始中心对齐状态 class ZoomGestureListener extends GestureDetector.SimpleOnGestureListener{ @Override public boolean onDoubleTap(MotionEvent e) { mMatrix.reset(); //让图片初始的时候与空间中心对齐 mMatrix.postTranslate(getWidth()/2-mBitmap.getWidth()/2,getHeight()/2-mBitmap.getHeight()/2); mMatrix.mapRect(translateRect); postInvalidate(); return true; } } /** * 把drawable转化为bitmap * @param d * @return */ private Bitmap drawable2Bitmap(Drawable d){ if(d instanceof BitmapDrawable){ return ((BitmapDrawable) d).getBitmap(); }else{ Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(),d.getIntrinsicHeight(),Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight()); d.draw(c); return b; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int wSize = MeasureSpec.getSize(widthMeasureSpec); int hSize = MeasureSpec.getSize(heightMeasureSpec); int wMode = MeasureSpec.getMode(widthMeasureSpec); int hMode = MeasureSpec.getMode(heightMeasureSpec); //在wrap_content的时候就给一个默认的尺寸 if(wMode == MeasureSpec.AT_MOST){ wSize = Math.min(wSize,DEF_SIZE); } if(hMode == MeasureSpec.AT_MOST){ hSize = Math.min(hSize,DEF_SIZE); } setMeasuredDimension(MeasureSpec.makeMeasureSpec(wSize,wMode), MeasureSpec.makeMeasureSpec(hSize,hMode)); mMatrix.reset(); //让图片初始的时候与空间中心对齐 mMatrix.postTranslate(wSize/2-mBitmap.getWidth()/2,hSize/2-mBitmap.getHeight()/2); mMatrix.mapRect(translateRect); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mBitmap,mMatrix,mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { gestureDetector.onTouchEvent(event); switch (event.getActionMasked()){ case MotionEvent.ACTION_DOWN: if(isTouchOnBitmap(event,translateRect)){ //第一个触摸点在图片上才能进行操作 pointer = 1; lastP.set(event.getX(),event.getY()); lastPId = event.getPointerId(0); return true; }else { return false; } case MotionEvent.ACTION_POINTER_DOWN: pointer +=1; lastDistance = (float) getDistance(event.getX(0),event.getY(0),event.getX(1),event.getY(1)); break; case MotionEvent.ACTION_MOVE: if(pointer == 1 && event.getPointerId(0) == lastPId){ //只有一根手指时就是移动 moveBitmap(event); }else if(pointer >= 2){ //两根手指就是放大缩小 scaleBitmap(event); } lastP.set(event.getX(),event.getY()); break; case MotionEvent.ACTION_POINTER_UP: pointer -=1; if(event.getPointerId(0) != lastPId){ //松开了最先按下的那个手指,就要更新第一个点的信息,避免跳动 lastP.set(event.getX(),event.getY()); lastPId = event.getPointerId(0); } break; case MotionEvent.ACTION_UP: pointer = 0; lastDistance = -1; break; } return super.onTouchEvent(event); } /** * 触摸点是否在图片上,只有触摸点在图片上才能移动图片 * @param event * @param rectF * @return */ private boolean isTouchOnBitmap(MotionEvent event,RectF rectF){ return rectF.contains(event.getX(),event.getY()); } /** * 单根手指时移动图片 * @param event */ private void moveBitmap(MotionEvent event){ float disX = event.getX()-lastP.x; float disY = event.getY()-lastP.y; if(translateRect.top + disY > getHeight() - SIZDE_PADDING || //边界检测,不让全移出边界外 translateRect.bottom + disY < SIZDE_PADDING || translateRect.left + disX > getWidth() - SIZDE_PADDING || translateRect.right +disX < SIZDE_PADDING){ return; } mMatrix.postTranslate(disX,disY); mMatrix.mapRect(translateRect,originalRect); //更新translateRect,代表了变换后的图片的位置 postInvalidate(); } /** * 两根手指时放大缩小图片 * @param event */ private void scaleBitmap(MotionEvent event){ float curDis = (float) getDistance(event.getX(0),event.getY(0),event.getX(1),event.getY(1)); if(lastDistance == -1){ lastDistance = curDis; } float scale = curDis/lastDistance; if(translateRect.width()/originalRect.width()*scale > MAX_MULTIPLE){ //倍数不能大于MAX_MULTIPLE return; } lastDistance = curDis; PointF centerP = getCenter(event.getX(0),event.getY(0),event.getX(1),event.getY(1)); mMatrix.postScale(scale,scale,centerP.x,centerP.y); mMatrix.mapRect(translateRect,originalRect); //更新translateRect,代表了变换后的图片的位置 postInvalidate(); } /** * 获得两点的距离 * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private double getDistance(float x1,float y1,float x2,float y2){ return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)) ; } /** * 获得两点的中心点 * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private PointF getCenter(float x1,float y1,float x2,float y2){ return new PointF((x1+x2)/2.0f,(y1+y2)/2.0f); }}
下面是自定义参数,只写了一个。同学们可以根据需要自己写更多的定制项。
<declare-styleable name="ZoomImageView"> <attr name="ximage" format="reference"></attr> </declare-styleable>
布局文件:
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.huangyi.test.MainActivity"> <com.example.huangyi.test.widge.ZoomImageView android:id="@+id/zoom" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" app:ximage="@drawable/carton"/></FrameLayout>
整个代码主要就是围绕对Metrix的操作变换和多点触摸的编写。
阅读全文
0 0
- 自定义ImageView
- 自定义ImageView
- 自定义ImageView
- 自定义 imageView
- 自定义Imageview
- 自定义ImageView
- 自定义imageView
- ImageView 自定义
- imageview 自定义
- 自定义imageview
- 自定义ImageView
- 自定义ImageView
- 自定义imageView
- 自定义ImageView重写onTouchEvent
- 自定义ImageView重写onTouchEvent
- 自定义ImageView放大镜控件
- android自定义一圆角ImageView
- ImageView自定义带边框
- 【Mapreduce】从代码上解决Output directory already exists错误,避免每次调试都要手动删除输出文件夹
- JavaWeb
- 数据结构(查找)
- Linux_MongoDB 安装笔记
- 自定义dialog
- 自定义ImageView
- 导航栏变为透明
- 编译原理中四种文法语言的基本概念
- 【连载】研究EasyUI系统—Tree组件(事件)
- 使用flex布局解决安卓手机上固定在底部的按钮,在键盘弹起后挡住input输入框的问题
- 正确使用Volatile变量
- webuploader在谷歌下提示runtime error解决办法
- Spring 配置文件部分详解
- java代码读取excel数据