自定义viewpager与自定义imageview实现图片显示
2017-01-22 11:23
459 查看
自定义放大缩小imageview import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; /** * @ClassName: MatrixImageView * @Description: 带放大、缩小、移动效果的ImageView * */ public class MatrixImageView extends ImageView{ public final static String TAG="MatrixImageView"; private GestureDetector mGestureDetector; /** 模板Matrix,用以初始化 */ private Matrix mMatrix=new Matrix(); /** 图片长度*/ private float mImageWidth; /** 图片高度 */ private float mImageHeight; /** 原始缩放级别 */ private float mScale ; private OnMovingListener moveListener; private OnSingleTapListener singleTapListener; public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); MatrixTouchListener mListener=new MatrixTouchListener(); setOnTouchListener(mListener); mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener)); //背景设置为balck setBackgroundColor(Color.BLACK); //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高 setScaleType(ScaleType.FIT_CENTER); } public MatrixImageView(Context context) { super(context, null); MatrixTouchListener mListener=new MatrixTouchListener(); setOnTouchListener(mListener); mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener)); //背景设置为balck setBackgroundColor(Color.BLACK); //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高 setScaleType(ScaleType.FIT_CENTER); } public void setOnMovingListener(OnMovingListener listener){ moveListener=listener; } public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) { this.singleTapListener = onSingleTapListener; } @Override public void setImageBitmap(Bitmap bm) { // TODO Auto-generated method stub super.setImageBitmap(bm); //大小为0 表示当前控件大小未测量 设置监听函数 在绘制前赋值 if(getWidth()==0){ ViewTreeObserver vto = getViewTreeObserver(); vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { initData(); //赋值结束后,移除该监听函数 MatrixImageView.this.getViewTreeObserver().removeOnPreDrawListener(this); return true; } }); }else { initData(); } } /** * 初始化模板Matrix和图片的其他数据 */ private void initData() { //设置完图片后,获取该图片的坐标变换矩阵 mMatrix.set(getImageMatrix()); float[] values=new float[9]; mMatrix.getValues(values); //图片宽度为屏幕宽度除缩放倍数 mImageWidth=getWidth()/values[Matrix.MSCALE_X]; mImageHeight=(getHeight()-values[Matrix.MTRANS_Y]*2)/values[Matrix.MSCALE_Y]; mScale=values[Matrix.MSCALE_X]; } public class MatrixTouchListener implements OnTouchListener{ /** 拖拉照片模式 */ private static final int MODE_DRAG = 1; /** 放大缩小照片模式 */ private static final int MODE_ZOOM = 2; /** 不支持Matrix */ private static final int MODE_UNABLE=3; /** 最大缩放级别*/ float mMaxScale=6; /** 双击时的缩放级别*/ float mDobleClickScale=2; private int mMode = 0;// /** 缩放开始时的手指间距 */ private float mStartDis; /** 当前Matrix*/ private Matrix mCurrentMatrix = new Matrix(); /** 用于记录开始时候的坐标位置 */ /** 和ViewPager交互相关,判断当前是否可以左移、右移 */ boolean mLeftDragable; boolean mRightDragable; /** 是否第一次移动 */ boolean mFirstMove=false; private PointF mStartPoint = new PointF(); @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: //设置拖动模式 mMode=MODE_DRAG; mStartPoint.set(event.getX(), event.getY()); isMatrixEnable(); startDrag(); checkDragable(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: reSetMatrix(); stopDrag(); break; case MotionEvent.ACTION_MOVE: if (mMode == MODE_ZOOM) { setZoomMatrix(event); }else if (mMode==MODE_DRAG) { setDragMatrix(event); }else { stopDrag(); } break; case MotionEvent.ACTION_POINTER_DOWN: if(mMode==MODE_UNABLE) return true; mMode=MODE_ZOOM; mStartDis = distance(event); break; case MotionEvent.ACTION_POINTER_UP: break; default: break; } return mGestureDetector.onTouchEvent(event); } /** * 子控件开始进入移动状态,令ViewPager无法拦截对子控件的Touch事件 */ private void startDrag(){ if(moveListener!=null) moveListener.startDrag(); } /** * 子控件开始停止移动状态,ViewPager将拦截对子控件的Touch事件 */ private void stopDrag(){ if(moveListener!=null) moveListener.stopDrag(); } /** * 根据当前图片左右边缘设置可拖拽状态 */ private void checkDragable() { mLeftDragable=true; mRightDragable=true; mFirstMove=true; float[] values=new float[9]; getImageMatrix().getValues(values); //图片左边缘离开左边界,表示不可右移 if(values[Matrix.MTRANS_X]>=0) mRightDragable=false; //图片右边缘离开右边界,表示不可左移 if((mImageWidth)*values[Matrix.MSCALE_X]+values[Matrix.MTRANS_X]<=getWidth()){ mLeftDragable=false; } } /** * 设置拖拽状态下的Matrix * @param event */ public void setDragMatrix(MotionEvent event) { if(isZoomChanged()){ float dx = event.getX() - mStartPoint.x; // 得到x轴的移动距离 float dy = event.getY() - mStartPoint.y; // 得到x轴的移动距离 //避免和双击冲突,大于10f才算是拖动 if(Math.sqrt(dx*dx+dy*dy)>10f){ mStartPoint.set(event.getX(), event.getY()); //在当前基础上移动 mCurrentMatrix.set(getImageMatrix()); float[] values=new float[9]; mCurrentMatrix.getValues(values); dy=checkDyBound(values,dy); dx=checkDxBound(values,dx,dy); mCurrentMatrix.postTranslate(dx, dy); setImageMatrix(mCurrentMatrix); } }else { stopDrag(); } } /** * 判断缩放级别是否是改变过 * @return true表示非初始值,false表示初始值 */ private boolean isZoomChanged() { float[] values=new float[9]; getImageMatrix().getValues(values); //获取当前X轴缩放级别 float scale=values[Matrix.MSCALE_X]; //获取模板的X轴缩放级别,两者做比较 return scale!=mScale; } /** * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界 * @param values * @param dy * @return */ private float checkDyBound(float[] values, float dy) { float height=getHeight(); if(mImageHeight*values[Matrix.MSCALE_Y]<height) return 0; if(values[Matrix.MTRANS_Y]+dy>0) dy=-values[Matrix.MTRANS_Y]; else if(values[Matrix.MTRANS_Y]+dy<-(mImageHeight*values[Matrix.MSCALE_Y]-height)) dy=-(mImageHeight*values[Matrix.MSCALE_Y]-height)-values[Matrix.MTRANS_Y]; return dy; } /** * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界 * @param values * @param dx * @return */ private float checkDxBound(float[] values,float dx,float dy) { float width=getWidth(); if(!mLeftDragable&&dx<0){ //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){ stopDrag(); } return 0; } if(!mRightDragable&&dx>0){ //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){ stopDrag(); } return 0; } mLeftDragable=true; mRightDragable=true; if(mFirstMove) mFirstMove=false; if(mImageWidth*values[Matrix.MSCALE_X]<width){ return 0; } if(values[Matrix.MTRANS_X]+dx>0){ dx=-values[Matrix.MTRANS_X]; } else if(values[Matrix.MTRANS_X]+dx<-(mImageWidth*values[Matrix.MSCALE_X]-width)){ dx=-(mImageWidth*values[Matrix.MSCALE_X]-width)-values[Matrix.MTRANS_X]; } return dx; } /** * 设置缩放Matrix * @param event */ private void setZoomMatrix(MotionEvent event) { //只有同时触屏两个点的时候才执行 if(event.getPointerCount()<2) return; float endDis = distance(event);// 结束距离 if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10 float scale = endDis / mStartDis;// 得到缩放倍数 mStartDis=endDis;//重置距离 mCurrentMatrix.set(getImageMatrix());//初始化Matrix float[] values=new float[9]; mCurrentMatrix.getValues(values); scale = checkMaxScale(scale, values); PointF centerF=getCenter(scale,values); mCurrentMatrix.postScale(scale, scale,centerF.x,centerF.y); setImageMatrix(mCurrentMatrix); } } /** * 获取缩放的中心点。 * @param scale * @param values * @return */ private PointF getCenter(float scale,float[] values) { //缩放级别小于原始缩放级别时或者为放大状态时,返回ImageView中心点作为缩放中心点 if(scale*values[Matrix.MSCALE_X]<mScale||scale>=1){ return new PointF(getWidth()/2,getHeight()/2); } float cx=getWidth()/2; float cy=getHeight()/2; //以ImageView中心点为缩放中心,判断缩放后的图片左边缘是否会离开ImageView左边缘,是的话以左边缘为X轴中心 if((getWidth()/2-values[Matrix.MTRANS_X])*scale<getWidth()/2) cx=0; //判断缩放后的右边缘是否会离开ImageView右边缘,是的话以右边缘为X轴中心 if((mImageWidth*values[Matrix.MSCALE_X]+values[Matrix.MTRANS_X])*scale<getWidth()) cx=getWidth(); return new PointF(cx,cy); } /** * 检验scale,使图像缩放后不会超出最大倍数 * @param scale * @param values * @return */ private float checkMaxScale(float scale, float[] values) { if(scale*values[Matrix.MSCALE_X]>mMaxScale) scale=mMaxScale/values[Matrix.MSCALE_X]; return scale; } /** * 重置Matrix */ private void reSetMatrix() { if(checkRest()){ mCurrentMatrix.set(mMatrix); setImageMatrix(mCurrentMatrix); }else { //判断Y轴是否需要更正 float[] values=new float[9]; getImageMatrix().getValues(values); float height=mImageHeight*values[Matrix.MSCALE_Y]; if(height<getHeight()){ //在图片真实高度小于容器高度时,Y轴居中,Y轴理想偏移量为两者高度差/2, float topMargin=(getHeight()-height)/2; if(topMargin!=values[Matrix.MTRANS_Y]){ mCurrentMatrix.set(getImageMatrix()); mCurrentMatrix.postTranslate(0, topMargin-values[Matrix.MTRANS_Y]); setImageMatrix(mCurrentMatrix); } } } } /** * 判断是否需要重置 * @return 当前缩放级别小于模板缩放级别时,重置 */ private boolean checkRest() { // TODO Auto-generated method stub float[] values=new float[9]; getImageMatrix().getValues(values); //获取当前X轴缩放级别 float scale=values[Matrix.MSCALE_X]; //获取模板的X轴缩放级别,两者做比较 return scale<mScale; } /** * 判断是否支持Matrix */ private void isMatrixEnable() { //当加载出错时,不可缩放 if(getScaleType()!=ScaleType.CENTER){ setScaleType(ScaleType.MATRIX); }else { mMode=MODE_UNABLE;//设置为不支持手势 } } /** * 计算两个手指间的距离 * @param event * @return */ private float distance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); /** 使用勾股定理返回两点之间的距离 */ return (float) Math.sqrt(dx * dx + dy * dy); } /** * 双击时触发 */ public void onDoubleClick(){ float scale=isZoomChanged()?1:mDobleClickScale; mCurrentMatrix.set(mMatrix);//初始化Matrix mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2); setImageMatrix(mCurrentMatrix); } } private class GestureListener extends SimpleOnGestureListener{ private final MatrixTouchListener listener; public GestureListener(MatrixTouchListener listener) { this.listener=listener; } @Override public boolean onDown(MotionEvent e) { //捕获Down事件 return true; } @Override public boolean onDoubleTap(MotionEvent e) { //触发双击事件 listener.onDoubleClick(); return true; } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return super.onFling(e1, e2, velocityX, velocityY); } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub super.onShowPress(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) { // TODO Auto-generated method stub return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { if(singleTapListener!=null) singleTapListener.onSingleTap(); return super.onSingleTapConfirmed(e); } } /** * @ClassName: OnChildMovingListener * @Description: MatrixImageView移动监听接口,用以组织ViewPager对Move操作的拦截 * */ public interface OnMovingListener{ public void startDrag(); public void stopDrag(); } /** * @ClassName: OnSingleTapListener * @Description: 监听ViewPager屏幕单击事件,本质是监听子控件MatrixImageView的单击事件 * */ public interface OnSingleTapListener{ public void onSingleTap(); } 自定义viewpager
import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; /** * @author LinJ * @ClassName: AlbumViewPager * @Description: 自定义viewpager 优化了事件拦截 */ public class AlbumViewPager extends ViewPager implements MatrixImageView.OnMovingListener { public final static String TAG = "AlbumViewPager"; /** * 当前子控件是否处理拖动状态 */ private boolean mChildIsBeingDragged = false; public AlbumViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent arg0) { if (mChildIsBeingDragged) return false; return super.onInterceptTouchEvent(arg0); } @Override public void startDrag() { mChildIsBeingDragged = true; } @Override public void stopDrag() { mChildIsBeingDragged = false; }}
相关文章推荐
- 安卓学习笔记---自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示(矩形圆角加边框)
- 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)
- Android自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示
- 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)
- Android自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示
- Android自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示
- Android:自定义imageview实现两条线裁剪图片,不在区域内显示阴影
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- Android开发之自定义圆角矩形图片ImageView的实现 - Jamy Cai
- Android开发之自定义圆角矩形图片ImageView的实现
- 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- qt利用委托:QStyledItemDelegate,实现tableview 的表格项的自定义显示,如插入图片,绘制控件
- 使用GridView和ImageView组件实现图片显示效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- 自定义imageview,实现仿微信的气泡型的图片
- 自定义ImageView显示gif图片
- android 自定义imageview实现 图片放大缩小
- 实现ImageView中两张图片重叠显示
- 自定义类继承ImageView 实现多点图片触碰的拖动和缩放