网络图片刷新组件(二)

这篇本来想是 作为上一篇的部分来写的,结果写到后来才发现篇幅可能会有点大,而且也超过上一篇的讨论范畴,所以就作为它的姊妹篇写出来吧!

主要功能:

        1.加载网络图片,handler来异步刷新组件。

         2.加载图片的时候,图片的满屏而不超过屏幕范围,即恰好而屏幕边界齐,当然图片是按比例缩放的。

         3.添加手势操作,对图片单点满屏,双击就退出当前活动,长按就显示保存组件,支持双点缩放操作。

项目源码

好了下面就给代码吧。

起始活动:

public class TestMyImg extends Activity implements OnClickListener {
	private Button skip;
	private Intent intent;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		skip = (Button) findViewById(R.id.btn_skip);
		skip.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if (v == skip) {
			intent = new Intent(this, TestMyPicture.class);
			intent.putExtra(
					"url",
					"http://y1.ifengimg.com/f04c9b92453d105f/2014/0330/xes_e3816df8889ea27b4b3b67011deb880a.jpg");
			startActivity(intent);
		}
	}
}

该活动的界面只是个按钮,点击就跳转到加载图片的页面。

public class TestMyPicture extends Activity implements OnClickListener {
	private ZoomImageView img;
	private TextView save;
	private MyPctureThread mypic;
	private Handler handler;
	private Bitmap mybit;
	private Intent intent;
	private URL url;
        private ProgressDialog priDialog=null;

        @Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.acy_pic);
		initView();
	}

	public void initView() {
		img = (ZoomImageView) findViewById(R.id.img_pic);
		save = (TextView) findViewById(R.id.tv_txt);

		intent = getIntent();
		if (null != intent.getExtras().get("url")) {
			try {
                               priDialog=ProgressDialog.show(TestMyPicture.this,null,"加载数据中....",true);
                                url = new URL((String) intent.getExtras().get("url"));
				mypic = new MyPctureThread();
				Thread t = new Thread(mypic);
				t.start();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
				if (0 == msg.what) {
					img.setImageBitmap(mybit);
					img.setActivityContext(TestMyPicture.this);
                                        priDialo.dismiss();
                                 }
				super.handleMessage(msg);
			}
		};
	}

	public void setVisiableSave(boolean isvisiable) {
		if (isvisiable) {
			save.setVisibility(View.VISIBLE);
		} else {
			save.setVisibility(View.GONE);
		}
	}

	class MyPctureThread implements Runnable {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				HttpURLConnection con = (HttpURLConnection) url
						.openConnection();
				con.setRequestMethod("GET");
				con.setConnectTimeout(5000);
				con.connect();
				InputStream in = con.getInputStream();
				mybit = BitmapFactory.decodeStream(in);

				handler.sendEmptyMessage(0);
				in.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
	}
}
该活动加载网络图片,并异步刷新。

界面:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.testandroid.ZoomImageView
        android:id="@+id/img_pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

    <TextView
        android:id="@+id/tv_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="20dp"
        android:text="保存"
        android:visibility="gone" />

</RelativeLayout>
组件一个是自定义的view,一个是保存的组件(只是有出现或者消失的事件,其他功能就自己扩展吧)。

/**
 * 自定义view
 */
public class ZoomImageView extends View {
	public static final int STATUS_INIT = 1;// 常量初始化
	public static final int STATUS_ZOOM_OUT = 2;// 图片放大状态常量
	public static final int STATUS_ZOOM_IN = 3;// 图片缩小状态常量
	public static final int STATUS_MOVE = 4;// 图片拖动状态常量
	private Matrix matrix = new Matrix();// 对图片进行移动和缩放变换的矩阵
	private Bitmap sourceBitmap;// 待展示的Bitmap对象
	private int currentStatus;// 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
	private int width;// ZoomImageView控件的宽度
	private int height;// ZoomImageView控件的高度
	private float centerPointX;// 记录两指同时放在屏幕上时,中心点的横坐标值
	private float centerPointY;// 记录两指同时放在屏幕上时,中心点的纵坐标值
	private float currentBitmapWidth;// 记录当前图片的宽度,图片被缩放时,这个值会一起变动
	private float currentBitmapHeight;// 记录当前图片的高度,图片被缩放时,这个值会一起变动
	private float lastXMove = -1;// 记录上次手指移动时的横坐标
	private float lastYMove = -1;// 记录上次手指移动时的纵坐标
	private float movedDistanceX;// 记录手指在横坐标方向上的移动距离
	private float movedDistanceY;// 记录手指在纵坐标方向上的移动距离
	private float totalTranslateX;// 记录图片在矩阵上的横向偏移值
	private float totalTranslateY;// 记录图片在矩阵上的纵向偏移值
	private float totalRatio;// 记录图片在矩阵上的总缩放比例
	private float scaledRatio;// 记录手指移动的距离所造成的缩放比例
	private float initRatio;// 记录图片初始化时的缩放比例
	private double lastFingerDis;// 记录上次两指之间的距离

	private Context context;
	private GestureDetector getstureDetector;

	/**
	 * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
	 * 
	 */
	public ZoomImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		currentStatus = STATUS_INIT;
		getstureDetector = new GestureDetector(context, new MyGestureListener());
	}

	/*
	 * 将待展示的图片设置进来。
	 * 
	 * @param bitmap 待展示的Bitmap对象
	 */
	public void setImageBitmap(Bitmap bitmap) {
		sourceBitmap = bitmap;
		invalidate();
	}

	/*
	 * 将活动的context对象传递过来
	 */
	public void setActivityContext(Context context) {
		this.context = context;
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		if (changed) {
			// 分别获取到ZoomImageView的宽度和高度,获取当前屏幕的参数
			width = getWidth();
			height = getHeight();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		getstureDetector.onTouchEvent(event);
		if (initRatio == totalRatio) {
			getParent().requestDisallowInterceptTouchEvent(false);
		} else {
			getParent().requestDisallowInterceptTouchEvent(true);
		}
		switch (event.getActionMasked()) {
		case MotionEvent.ACTION_POINTER_DOWN:
			if (event.getPointerCount() == 2) {
				// 当有两个手指按在屏幕上时,计算两指之间的距离
				lastFingerDis = distanceBetweenFingers(event);
			}
			break;
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_MOVE:
			if (event.getPointerCount() == 1) {
				// 只有单指按在屏幕上移动时,为拖动状态
				float xMove = event.getX();
				float yMove = event.getY();
				if (lastXMove == -1 && lastYMove == -1) {
					lastXMove = xMove;
					lastYMove = yMove;
				}
				currentStatus = STATUS_MOVE;
				// 手指移动的距离
				movedDistanceX = xMove - lastXMove;
				movedDistanceY = yMove - lastYMove;
				// 进行边界检查,不允许将图片拖出边界
				if (totalTranslateX + movedDistanceX > 0) {
					movedDistanceX = 0;
				} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
					movedDistanceX = 0;
				}
				if (totalTranslateY + movedDistanceY > 0) {
					movedDistanceY = 0;
				} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
					movedDistanceY = 0;
				}
				// 调用onDraw()方法绘制图片
				invalidate();
				lastXMove = xMove;
				lastYMove = yMove;
			} else if (event.getPointerCount() == 2) {
				// 有两个手指按在屏幕上移动时,为缩放状态
				centerPointBetweenFingers(event);
				double fingerDis = distanceBetweenFingers(event);
				if (fingerDis > lastFingerDis) {
					currentStatus = STATUS_ZOOM_OUT;
				} else {
					currentStatus = STATUS_ZOOM_IN;
				}
				// 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
				if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
						|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
					scaledRatio = (float) (fingerDis / lastFingerDis);
					totalRatio = totalRatio * scaledRatio;
					if (totalRatio > 4 * initRatio) {
						totalRatio = 4 * initRatio;
					} else if (totalRatio < initRatio) {
						totalRatio = initRatio;
					}
					// 调用onDraw()方法绘制图片
					invalidate();
					lastFingerDis = fingerDis;
				}
			}
			break;
		case MotionEvent.ACTION_POINTER_UP:
			if (event.getPointerCount() == 2) {
				// 手指离开屏幕时将临时值还原
				lastXMove = -1;
				lastYMove = -1;
			}
			break;
		case MotionEvent.ACTION_UP:
			// 手指离开屏幕时将临时值还原
			lastXMove = -1;
			lastYMove = -1;
			break;
		case MotionEvent.ACTION_DOWN:
			// 隐藏显示的保存控件
			((TestMyPicture) context).setVisiableSave(false);
			break;
		default:
			break;
		}
		return true;
	}

	/* 根据currentStatus的值来决定对图片进行什么样的绘制操作。 */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		switch (currentStatus) {
		case STATUS_ZOOM_OUT:
		case STATUS_ZOOM_IN:
			zoom(canvas);
			break;
		case STATUS_MOVE:
			move(canvas);
			break;
		case STATUS_INIT:
			initBitmap(canvas);
		default:
			if (sourceBitmap != null) {
				canvas.drawBitmap(sourceBitmap, matrix, null);
			}
			break;
		}
	}

	/**
	 * 对图片进行缩放处理。
	 * 
	 * @param canvas
	 */
	private void zoom(Canvas canvas) {
		matrix.reset();
		// 将图片按总缩放比例进行缩放
		matrix.postScale(totalRatio, totalRatio);
		float scaledWidth = sourceBitmap.getWidth() * totalRatio;
		float scaledHeight = sourceBitmap.getHeight() * totalRatio;
		float translateX = 0f;
		float translateY = 0f;
		// 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放
		if (currentBitmapWidth < width) {
			translateX = (width - scaledWidth) / 2f;
		} else {
			translateX = totalTranslateX * scaledRatio + centerPointX
					* (1 - scaledRatio);
			// 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕
			if (translateX > 0) {
				translateX = 0;
			} else if (width - translateX > scaledWidth) {
				translateX = width - scaledWidth;
			}
		}
		// 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
		if (currentBitmapHeight < height) {
			translateY = (height - scaledHeight) / 2f;
		} else {
			translateY = totalTranslateY * scaledRatio + centerPointY
					* (1 - scaledRatio);
			// 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕
			if (translateY > 0) {
				translateY = 0;
			} else if (height - translateY > scaledHeight) {
				translateY = height - scaledHeight;
			}
		}
		// 缩放后对图片进行偏移,以保证缩放后中心点位置不变
		matrix.postTranslate(translateX, translateY);
		totalTranslateX = translateX;
		totalTranslateY = translateY;
		currentBitmapWidth = scaledWidth;
		currentBitmapHeight = scaledHeight;
		canvas.drawBitmap(sourceBitmap, matrix, null);
	}

	/**
	 * 对图片进行平移处理
	 * 
	 */
	private void move(Canvas canvas) {
		matrix.reset();
		// 根据手指移动的距离计算出总偏移值
		float translateX = totalTranslateX + movedDistanceX;
		float translateY = totalTranslateY + movedDistanceY;
		// 先按照已有的缩放比例对图片进行缩放
		matrix.postScale(totalRatio, totalRatio);
		// 再根据移动距离进行偏移
		matrix.postTranslate(translateX, translateY);
		totalTranslateX = translateX;
		totalTranslateY = translateY;
		canvas.drawBitmap(sourceBitmap, matrix, null);
	}

	/**
	 * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。 添加让图片初始化的时候就全屏的效果
	 * 
	 * @param canvas
	 */
	private void initBitmap(Canvas canvas) {
		if (sourceBitmap != null) {
			matrix.reset();
			// 图片原始宽度
			int bitmapWidth = sourceBitmap.getWidth();
			// 图片原始高度
			int bitmapHeight = sourceBitmap.getHeight();
			// 获取假如全屏时候的压缩比
			float scalewidth = width / bitmapWidth;
			float scaleheight = height / bitmapHeight;
			/**
			 * 在初始化的时候,绘制图片全屏显示但不能超过边界。通过计算得知,我们按屏幕和图片的宽高经行比值,按值小的比例作为缩放比例(
			 * 省略推导过程)。
			 */
			// 当宽度比小于高度比时,将图片等宽度比例压缩,使它可以完全显示出来
			if (scalewidth < scaleheight) {
				float ratio = width / (bitmapWidth * 1.0f);
				matrix.postScale(ratio, ratio);
				// 获取等比压缩后,高度要移动的距离
				float translateY = (height - (bitmapHeight * ratio)) / 2f;
				// 在纵坐标方向上进行偏移,以保证图片居中显示
				matrix.postTranslate(0, translateY);
				totalTranslateY = translateY;
				totalRatio = initRatio = ratio;
			}
			// 当高度比小于宽度比时,将图片按高度等比例压缩,使它可以完全显示出来
			else {
				float ratio = height / (bitmapHeight * 1.0f);
				matrix.postScale(ratio, ratio);
				// 获取等比压缩后,宽度要移动的距离
				float translateX = (width - (bitmapWidth * ratio)) / 2f;
				// 在横坐标方向上进行偏移,以保证图片居中显示
				matrix.postTranslate(translateX, 0);
				totalTranslateX = translateX;
				totalRatio = initRatio = ratio;
			}
			currentBitmapWidth = bitmapWidth * initRatio;
			currentBitmapHeight = bitmapHeight * initRatio;
			// 绘制图形
			canvas.drawBitmap(sourceBitmap, matrix, null);
		}
	}

	/**
	 * 计算两个手指之间的距离。
	 * 
	 * @param event
	 * @return 两个手指之间的距离
	 */
	private double distanceBetweenFingers(MotionEvent event) {
		float disX = Math.abs(event.getX(0) - event.getX(1));
		float disY = Math.abs(event.getY(0) - event.getY(1));
		return Math.sqrt(disX * disX + disY * disY);
	}

	/**
	 * 计算两个手指之间中心点的坐标。
	 * 
	 * @param event
	 */
	private void centerPointBetweenFingers(MotionEvent event) {
		float xPoint0 = event.getX(0);
		float yPoint0 = event.getY(0);
		float xPoint1 = event.getX(1);
		float yPoint1 = event.getY(1);
		centerPointX = (xPoint0 + xPoint1) / 2;
		centerPointY = (yPoint0 + yPoint1) / 2;
	}

	/**
	 * 新建手势封装类
	 */
	class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
		// 双点击就退出活动
		@Override
		public boolean onDoubleTap(MotionEvent e) {
			// TODO Auto-generated method stub
			((TestMyPicture) context).finish();
			return false;
		}

		// 长按就显示保存字体
		@Override
		public void onLongPress(MotionEvent e) {
			// TODO Auto-generated method stub
			((TestMyPicture) context).setVisiableSave(true);
			super.onLongPress(e);
		}

		// 单击恢复到初始化大小
		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			// TODO Auto-generated method stub
			// 图片原始宽度
			int bitmapWidth = sourceBitmap.getWidth();
			// 图片原始高度
			int bitmapHeight = sourceBitmap.getHeight();
			// 获取假如全屏时候的压缩比
			float scalewidth = width / bitmapWidth;
			float scaleheight = height / bitmapHeight;
			/**
			 * 在初始化的时候,绘制图片全屏显示但不能超过边界。通过计算得知,我们按屏幕和图片的宽高经行比值,按值小的比例作为缩放比例(
			 * 省略推导过程)。
			 */
			// 当宽度比小于高度比时,将图片等宽度比例压缩,使它可以完全显示出来
			if (scalewidth < scaleheight) {
				float ratio = width / (bitmapWidth * 1.0f);
				matrix.postScale(ratio, ratio);
				// 获取等比压缩后,高度要移动的距离
				float translateY = (height - (bitmapHeight * ratio)) / 2f;
				// 在纵坐标方向上进行偏移,以保证图片居中显示
				matrix.postTranslate(0, translateY);
				totalTranslateY = translateY;
				totalRatio = initRatio = ratio;
			}
			// 当高度比小于宽度比时,将图片按高度等比例压缩,使它可以完全显示出来
			else {
				float ratio = height / (bitmapHeight * 1.0f);
				matrix.postScale(ratio, ratio);
				// 获取等比压缩后,宽度要移动的距离
				float translateX = (width - (bitmapWidth * ratio)) / 2f;
				// 在横坐标方向上进行偏移,以保证图片居中显示
				matrix.postTranslate(translateX, 0);
				totalTranslateX = translateX;
				totalRatio = initRatio = ratio;
			}
			currentBitmapWidth = bitmapWidth * initRatio;
			currentBitmapHeight = bitmapHeight * initRatio;
			// 缩小到满屏
			currentStatus = STATUS_ZOOM_IN;
			invalidate();
			return false;
		}
	}

}

运行效果:

1.起始界面:

网络图片刷新组件(二)_第1张图片

2.点击跳转就加载网络图片,显示效果:

网络图片刷新组件(二)_第2张图片

3.当缩放后:

网络图片刷新组件(二)_第3张图片

4.长按,就显示保存组件:

网络图片刷新组件(二)_第4张图片

当然,双击就退出当前活动了。

注意:

        1.在网页图片没加载出来的时候,需要进度条来显示加载数据,图片显示了才可以操作。这个是系统的进度条,需要的童鞋可以自己定义。


你可能感兴趣的:(canvas,网络,图形)