上一节说了通过自定义来加载超大图片,同时实现手指的拖动效果。不过,另一种情况就是,我们希望应用能够加载整张图片,如果图片太大就先压缩,如果小于屏幕就直接显示,同时用户可以拖拽移动和缩放图片大小,梳理下流程: 1.自定义View继承ImageView,重新onDraw方法 2.在onDraw先画图片,图片大于屏幕就把图片缩小后显示,图片小于屏幕就直接显示,显示之前要计算显示图片的Rect,Rect是其实就是四个坐标,用来控制显示图片的范围,这个Rect是根据图片的长宽比例计算而来,显示在屏幕中间。
上一节说了通过自定义来加载超大图片,同时实现手指的拖动效果。不过,另一种情况就是,我们希望应用能够加载整张图片,如果图片太大就先压缩,如果小于屏幕就直接显示,同时用户可以拖拽移动和缩放图片大小,梳理下流程:
1.自定义View继承ImageView,重新onDraw方法

2.在 onDraw 先画图片,图片大于屏幕就把图片缩小后显示,图片小于屏幕就直接显示,显示之前要计算显示图片的Rect,Rect是其实就是四个坐标,用来控制显示图片的范围,这个Rect是根据图片的长宽比例计算而来,显示在屏幕中间。

3.重写 onTouchEvent方法,处理 View随着手指移动的相关操作:在touchEvent事件中处理好按下和松开事件之后,剩下的就是移动事件,通过不断的改变Rect的坐标,然后不断的调用invalidate(),该方法用来重新绘制我们的View

看下DragImageView.java

public class DragImageView extends ImageView {
private Drawable mDrawable;
private Rect mDrawableRect;
private Context mContext;
private float mRation_WH = 0;
private float mOldX = 0;
private float mOldY = 0;
private double mD1;
private boolean isFirst = true;
private int NONE = 0;// 无操作
private int SINGAL_MOVE = 1;// 单点移动
private int MUTIL_MOVE = 2;// 双点拖拽
private int mStatus = 0;
public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
public DragImageView(Context context) {
super(context);
this.mContext = context;
mDrawableRect = new Rect();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// getIntrinsicHeight为返回对象的实际高度
if (mDrawable == null || mDrawable.getIntrinsicHeight() == 0
|| mDrawable.getIntrinsicWidth() == 0) {
return;
setBounds(); // 设置图片
mDrawable.draw(canvas);
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mOldX = event.getX();
mOldY = event.getY();
break;
case MotionEvent.ACTION_UP:
mStatus = NONE;
checkBounds();
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1)
mStatus = SINGAL_MOVE;
mStatus = MUTIL_MOVE;
onTouchMove(event);
break;
default:
break;
return true;
private void onTouchMove(MotionEvent event) {
// 判断有几个触摸点
if (mStatus == SINGAL_MOVE) {
int offsetWidth = (int) (event.getX() - mOldX);
int offsetHeight = (int) (event.getY() - mOldY);
mOldX = event.getX();
mOldY = event.getY();
mDrawableRect.offset(offsetWidth, offsetHeight);
invalidate();
} else if (mStatus == MUTIL_MOVE) {
float X0 = event.getX(0);
float Y0 = event.getY(0);
float X1 = event.getX(1);
float Y1 = event.getY(1);
double mD2 = Math.sqrt(Math.pow(X0 - X1, 2) + Math.pow(Y0 - Y1, 2));
if (mD1 < mD2) {
// 放大操作
if (mDrawableRect.width() < mContext.getResources()
.getDisplayMetrics().widthPixels * 2) {
int offsetwidth = 10;
int offsettop = (int) (offsetwidth / mRation_WH);
mDrawableRect.set(mDrawableRect.left - offsetwidth,
mDrawableRect.top - offsettop, mDrawableRect.right
+ offsetwidth, mDrawableRect.bottom
+ offsettop);
invalidate();
} else {
// 设置为只能缩小为屏幕的1/3,可以根据需要自己调整
if (mDrawableRect.width() > mContext.getResources()
.getDisplayMetrics().widthPixels / 3) {
int offsetwidth = 10;
int offsettop = (int) (offsetwidth / mRation_WH);
mDrawableRect.set(mDrawableRect.left + offsetwidth,
mDrawableRect.top + offsettop, mDrawableRect.right
- offsetwidth, mDrawableRect.bottom
- offsettop);
invalidate();
mD1 = mD2;
* 设置mDrawable
public void setBounds() {
if (isFirst) {
// 图片宽高比
mRation_WH = (float) mDrawable.getIntrinsicWidth()
/ (float) mDrawable.getIntrinsicHeight();
// 取屏幕宽和图片宽较小的一个
int px_w = Math.min(getWidth(),
dp2px(mContext, mDrawable.getIntrinsicWidth()));
int px_h = (int) (px_w / mRation_WH);// 获得图片高
int left = (getWidth() - px_w) / 2;
int top = (getHeight() - px_h) / 2;
int right = px_w + left;
int bottom = px_h + top;
mDrawableRect.set(left, top, right, bottom);
isFirst = false;
mDrawable.setBounds(mDrawableRect);
* 检测边框范围
public void checkBounds() {
int newLeft = mDrawableRect.left;
int newTop = mDrawableRect.top;
boolean isChange = false;
// 向左移动范围<=屏幕宽度
if (newLeft < -mDrawableRect.width()) {
newLeft = -mDrawableRect.width();
isChange = true;
// 向上移动范围<=屏幕高度
if (newTop < -mDrawableRect.height()) {
newTop = -mDrawableRect.height();
isChange = true;
// 向右移动范围<=屏幕宽度
if (newLeft > getWidth()) {
newLeft = getWidth();
isChange = true;
// 向下移动范围<=屏幕高度
if (newTop > getHeight()) {
newTop = getHeight();
isChange = true;
if (isChange) {
mDrawableRect.offsetTo(newLeft, newTop);
invalidate();
public Drawable getmDrawable() {
return mDrawable;
public void setmDrawable(Drawable mDrawable) {
this.mDrawable = mDrawable;
* 将dp单位换算成px
* @param context
* @param value
* @return
public int dp2px(Context context, int value) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (value * scale + 0.5f);
在java类中直接调用即可
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
DragImageView mView = new DragImageView(this);
mView.setmDrawable(getResources().getDrawable(R.drawable.bg));
setContentView(mView);

效果如下:

一款简单的缩放拖拽图片控件
本文介绍一个针对 .NET 桌面应用程序的独立图片缩放拖拽显示控件 [SQPhoto](https://www.nuget.org/packages/SQPhoto/)。
需求:ImageView显示的图片,上方的两个角是圆角,下方的两个角是直角。 ![需求图](https://img-blog.csdn.net/20180125151146126?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjYyODc0MzU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Android - 条纹进度条实现,调整view宽度仿进度条
相关代码请参阅: https://github.com/RustFisher/aboutView/blob/master/app/src/main/java/com/rust/aboutview/activity/RoundCornerActivity.java 美工同学指定了一个进度条样式 这斑斓的进度条,如果要自己画实在是劳民伤财。
//设置可以获取imageView缓存 imageView.setDrawingCacheEnabled(true); //然后通过getDrawingCache方法获取BitMap Bitmap drawingCache = imageView. 终于建了一个自己个人小站:https://huangtianyu.gitee.io,以后优先更新小站博客,欢迎进站,O(∩_∩)O~~ 在今日头条里面Home按钮点击时候,能出现旋转的动画。这里模仿今日头条的Home按钮效果,通过自定义View来实现该效果。 Android ImageView加载圆形图片且同时绘制圆形图片的外部边缘边线及边框 在Android早期的开发中,如果涉及到圆形图片的处理,往往需要借助于第三方的实现,见附录文章1,2。