600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > android按比例增加坐标图片 Android:为超大图增加一个导航图

android按比例增加坐标图片 Android:为超大图增加一个导航图

时间:2023-11-01 07:30:23

相关推荐

android按比例增加坐标图片 Android:为超大图增加一个导航图

地图

要做的功能如上面demo所示,在图片缩放时,增加一个展示当前局部位置的导航图。要求是:支持超大图;

导航图红框定位当前局部位置;

导航图支持滑动,快速定位大图位置;

支持图钉显示,随图片放大更新透明度。

简书记录下开发过程,demo可以在github找到

加载超大图

测试用的是一张21m大的图片(上传代码里换了张小的),无论如何不能一次载入内存显示。github里找到一个显示超大图的控件subsampling-scale-image-view,原理是使用Android的BitmapRegionDecoder局部加载图片。

创建一个自定义LargeBitmapView,继承SubsamplingScaleImageView。加载图片使用setImage方法,图片来源可以多种,通过ImageSource获取。lav_bitmap.setImage(ImageSource.resource(R.mipmap.large_world_map));

监听图片加载过程使用OnImageEventListener,回调丰富。lav_bitmap.setOnImageEventListener(newSubsamplingScaleImageView.OnImageEventListener(){@Override

publicvoidonReady(){}@Override

publicvoidonImageLoaded(){}@Override

publicvoidonPreviewLoadError(Exceptione){}@Override

publicvoidonImageLoadError(Exceptione){}@Override

publicvoidonTileLoadError(Exceptione){}@Override

publicvoidonPreviewReleased(){}

});

加载导航图

大图加载完后调用showNavigation设置导航图,并加载一张缩略的Bitmap。导航图使用自定义的NavigateImageView,继承ImageView。privatevoidshowNavigation(){intnavigationWidth=(int)(lav_bitmap.getWidth()*NAVIGATION_SCREEN_WIDTH_SCALE);

mScale=(float)navigationWidth/lav_bitmap.getSWidth();intnavigationHeight=(int)(lav_bitmap.getSHeight()*mScale);//控件大小

ViewUtil.setWidth(iv_navigate,navigationWidth);

ViewUtil.setHeight(iv_navigate,navigationHeight);//生成缩略图

Bitmapthumbnail=BitmapUtils.decodeSampledBitmapFromResource(getResources(),R.mipmap.large_world_map,navigationWidth,navigationHeight);

iv_navigate.setImageBitmap(thumbnail);

}

重点要算出导航图和原图的比例mScale,然后通过目标宽高获取缩略图。BitmapUtils网上资料很多,就不多介绍。

导航图红框

大图缩放时,导航图要用红框展示当前局部位置。lav_bitmap.setOnStateChangedListener(newSubsamplingScaleImageView.OnStateChangedListener(){@Override

publicvoidonScaleChanged(floatscale,intorientation){

}@Override

publicvoidonCenterChanged(PointFpointF,intorientation){

}

});

大图的变化使用OnStateChangedListener监听,可以获取缩放比、图片当前中点位置和图片方向的变化。这里只需要知道图片当前中点位置变化就行,在onCenterChanged里调用drawFrame。privatevoiddrawFrame(PointFpointF){//中点在view位置

PointFcenterInViewPointF=lav_bitmap.sourceToViewCoord(pointF);//view的四个点

floatviewLeft=lav_bitmap.getWidth()/2-centerInViewPointF.x;floatviewTop=lav_bitmap.getHeight()/2-centerInViewPointF.y;floatviewRight=viewLeft+lav_bitmap.getWidth();floatviewBottom=viewTop+lav_bitmap.getHeight();//view对应大图的位置

PointFpoint1=lav_bitmap.viewToSourceCoord(viewLeft,viewTop);

PointFpoint2=lav_bitmap.viewToSourceCoord(viewRight,viewTop);

PointFpoint3=lav_bitmap.viewToSourceCoord(viewLeft,viewBottom);//PointFpoint4

//比例

floatleft=point1.x*mScale;floattop=point1.y*mScale;floatright=point2.x*mScale;floatbottom=point3.y*mScale;

iv_navigate.refreshFrame(left,top,right,bottom);

}

这里要分清楚图片坐标和屏幕坐标,SubsamplingScaleImageView提供sourceToViewCoord和viewToSourceCoord对两种坐标进行转换。

入参pointF是大图当前中点坐标,目标是得到当前图片局部的四个角坐标,所以要获取控件在屏幕四个角的坐标,然后viewToSourceCoord获取对应在大图上的坐标。最后,结果乘以mScale,就是红框在导航图上的坐标。

在导航图上画一个红色矩形就比较简单了,View的measure、layout、draw工作流程理应人人熟悉。privatePaintmPolygonSidePaint=newPaint();privateRectFmFrameRectF=newRectF();

在NavigateImageView里增加两个变量,mPolygonSidePaint是画笔,mFrameRectF记录矩形的四个坐标。publicvoidrefreshFrame(floatleft,floattop,floatright,floatbottom){if(left

left=0;

}if(top

top=0;

}if(right>getWidth()){

right=getWidth();

}if(bottom>getHeight()){

bottom=getHeight();

}

mFrameRectF.set(left,top,right,bottom);

invalidate();

}@OverrideprotectedvoidonDraw(Canvascanvas){super.onDraw(canvas);

drawFrame(canvas);

}privatevoiddrawFrame(Canvascanvas){if(mFrameRectF!=null){

Pathpath=newPath();

path.addRect(mFrameRectF,Path.Direction.CW);

canvas.drawPath(path,mPolygonSidePaint);

}

}

refreshFrame设置了mFrameRectF,然后重写onDraw方法,增加drawFrame方法,用drawPath画出矩形。

滑动导航图

导航图需要支持滑动,对应切换大图的焦点,实现快速移动到大图某个局部。iv_navigate.setOnTouchListener(newView.OnTouchListener(){@Override

publicbooleanonTouch(Viewv,MotionEventevent){floattargetX=event.getX()/mScale;floattargetY=event.getY()/mScale;

lav_bitmap.animateCenter(newPointF(targetX,targetY))

.withDuration(1)

.start();returntrue;

}

});

在NavigateImageView的onTouch里增加处理方法,覆盖DOWN、MOVE、UP三种MotionEvent。将导航图点击坐标乘以mScale,得到对应大图中点坐标,然后调用animateCenter移动到指定局部。

增加图钉

需要在大图上展示图钉,为了避免图钉非常密集的情况下遮挡图片,所以初始时图钉有一定透明度,随着图片放大,减少透明度。publicvoidrefreshPinAlpha(){intalpha=(int)(MAX_ALPHA*getScale()/getMaxScale()+INITIAL_ALPHA);if(alpha>MAX_ALPHA){

alpha=MAX_ALPHA;

}this.mPinAlpha=alpha;

}privatevoiddrawPin(Canvascanvas){

mBitmapPaint.setAlpha(mPinAlpha);

mTextPaint.setAlpha(mPinAlpha);for(Pinpin:mPinList){

PointFvPointF=sourceToViewCoord(pin.getPointF().x,pin.getPointF().y);floatvCenterX=vPointF.x-mPinBitmap.getWidth()/2;floatvCenterY=vPointF.y-mPinBitmap.getHeight();

canvas.drawBitmap(mPinBitmap,vCenterX,vCenterY,mBitmapPaint);if(!TextUtils.isEmpty(pin.getName())){//获取字体高度

Paint.FontMetricsfm=newPaint.FontMetrics();

mTextPaint.getFontMetrics(fm);floatfontHeight=fm.top+fm.bottom;//显示名称

floattextX=vPointF.x+mPinBitmap.getWidth()/2;floattextY=vCenterY-fontHeight;

canvas.drawText(pin.getName(),textX,textY,mTextPaint);

}

}

}

图钉的绘画,和导航图红框的原理是一样的,在onDraw里增加drawPin方法。没有什么特别要说,唯一一点是要认真通过计算,让图钉尖画在坐标上。

后记

磨刀不误砍柴,做出了demo,再移到项目中,不过是个优化过程。后续继续了解图片局部加载的原理,和回顾View的工作原理。

作者:展翅而飞

链接:/p/3796d69b24b0

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。