最近因为要做一个项目,需要使用到图片的浏览。我就自己在网上找了些资料,然后加以修改整理后出来一个demo,希望可以帮助到需要的人。同时这也是我第一个技术博客。
在做之前首先需要了解一下什么是ViewPager,怎么使用ViewPager。我这里提供一篇文章给大家 http://www.2cto.com/kf/201411/353975.html
好了 了解完可以开始了
PS 我不知道怎么制作那种动态的效果图,如果有谁知道请告诉我 我将万分感谢
一步一步来
首先先要写个布局 ViewPager的布局 activity_main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
3 android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
4 android:paddingRight="@dimen/activity_horizontal_margin"
5 android:paddingTop="@dimen/activity_vertical_margin"
6 android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
7 android:orientation="vertical">
8
9 <LinearLayout
10 android:id="@+id/linearlayout"
11 android:layout_width="300dp"
12 android:layout_height="300dp"
13 android:background="@drawable/bg_common_frames"
14 android:layout_gravity="center"
15 >
16
17 <android.support.v4.view.ViewPager
18 android:id="@+id/viewpager"
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_gravity="center"
22 />
23
24 </LinearLayout>
25
26
27
28 </LinearLayout>
对应的效果是这样的 请看 有点丑 不管啦。用了一张底图 在上面代码中的 LinearLayout
然后是图片详情布局 image_details.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent">
5
6 <android.support.v4.view.ViewPager
7 android:id="@+id/view_pager"
8 android:layout_width="match_parent"
9 android:layout_height="match_parent">
10 </android.support.v4.view.ViewPager>
11
12 <TextView
13 android:id="@+id/page_text"
14 android:layout_width="wrap_content"
15 android:layout_height="wrap_content"
16 android:layout_alignParentBottom="true"
17 android:layout_centerHorizontal="true"
18 android:layout_marginBottom="10dp"
19 android:textColor="#fff"
20 android:textSize="18sp" />
21
22 </RelativeLayout>
最后一个布局是缩放的布局 zoom_image_layout.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <com.higgs.mviewpager.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"
3 android:id="@+id/zoom_image_view"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:background="#000000" >
7
8 </com.higgs.mviewpager.ZoomImageView>
基本的布局我们完成了
再看代码吧
我这里因为迎合大部分朋友的需求 ,改成了从网络上下载图片的方式作为图片来源
先模拟一个图片URL的类
1 package com.higgs.mviewpager;
2
3 public class Images {
4
5 public final static String[] imageUrls = new String[]{
6 "",
7 "",
8 "",
9 "",
10 "",
11 };
12 }
然后就是实现代码了
说一下思路, 先获取ViewPager 然后往ViewPager 添加图片,但是图片是网络上的 所以要先下载后在添加进去,这里处于防止加载比较多的图片时造成OOM问题 所以引入了 LruCache 类缓存技术。先讲下载的图片存入手机里并缓存下来,一为了节省用户的数据流量,二为了之后的加载速度。有了缓冲下次就不用在重复去网络上下载了。 代码如下
1 package com.higgs.mviewpager;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.graphics.Bitmap;
6 import android.graphics.BitmapFactory;
7 import android.os.AsyncTask;
8 import android.os.Bundle;
9 import android.os.Environment;
10 import android.support.v4.view.PagerAdapter;
11 import android.support.v4.view.ViewPager;
12 import android.util.Log;
13 import android.view.View;
14 import android.view.ViewGroup;
15 import android.widget.ImageView;
16 import android.widget.Toast;
17
18 import java.io.BufferedInputStream;
19 import java.io.BufferedOutputStream;
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.net.HttpURLConnection;
27 import java.net.URL;
28 import java.util.ArrayList;
29
30
31 public class MainActivity extends Activity {
32
33 private static final String TAG = "MainActivity";
34 private ImageLoader imageLoader = ImageLoader.getInstance(); //获取图片进行管理的工具类实例。
35
36 private ViewPager viewpager;
37 private ArrayList<View> viewList;
38 // private ImageView imageView1;
39 // private ImageView imageView2;
40 // private ImageView imageView3;
41 @Override
42 protected void onCreate(Bundle savedInstanceState) {
43 super.onCreate(savedInstanceState);
44 setContentView(R.layout.activity_main);
45 initView();
46 }
47
48
49 private void initView() {
50 viewpager = (ViewPager) findViewById(R.id.viewpager); //获取viewpager
51 viewList = new ArrayList<View>(); //保存view,用于PagerAdapter
52 for(int i = 0; i<Images.imageUrls.length; i++){
53 new DownLoadPic().execute(i);//图片有几张就下载几张
54 }
55
56
57
58 //
59 // imageView1 = new ImageView(this);
60 // imageView2 = new ImageView(this);
61 // imageView3 = new ImageView(this);
62 // imageView1.setImageResource(R.drawable.b);
63 // imageView2.setImageResource(R.drawable.c);
64 // imageView3.setImageResource(R.drawable.d);
65 //
66 // viewList.add(imageView1);
67 // viewList.add(imageView2);
68 // viewList.add(imageView3);
69
70 viewpager.setAdapter(pagerAdapter); //加入适配器
71 Log.e("TAG1", "" + viewList.size());
72
73 }
74
75
76 /**
77 * 图片异步下载内部类
78 */
79
80 class DownLoadPic extends AsyncTask<Integer,Void,Bitmap>{
81
82 /**
83 * 记录每个图片对应的位置
84 */
85 private int mposition;
86
87 @Override
88 protected Bitmap doInBackground(Integer... params) {
89
90 mposition = params[0];//获取传过来的图片position (下标)
91 String strurl = Images.imageUrls[mposition]; //通过下标获得图片URL
92 File imageFile = new File(getImagePath(strurl)); //获取图片在本地手机中的位置路径
93 if (!imageFile.exists()) { //判断是否存在手机里
94 doPost(strurl);//如果没有就下载图片
95 }
96 if (strurl != null) {
97 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource(imageFile.getPath(),
98 290); //压缩图片 我这里写的是290
99 if (bitmap != null) {
100 imageLoader.addBitmapToMemoryCache(strurl, bitmap); //将图片加入缓冲 LruCache中
101 return bitmap;
102 }
103 }
104
105
106 return null;
107 }
108
109 @Override
110 protected void onPostExecute(Bitmap o) {
111 ImageView imageView = new ImageView(MainActivity.this);
112 imageView.setImageBitmap(o);
113 imageView.setOnClickListener(new View.OnClickListener() {
114 @Override
115 public void onClick(View v) {
116
117 Intent intent = new Intent(MainActivity.this, ImageDetailsActivity.class);//打开图片详情类
118 intent.putExtra("image_position", mposition);
119 MainActivity.this.startActivity(intent);
120 }
121 });
122
123 viewList.add(imageView);
124 pagerAdapter.notifyDataSetChanged(); //这句话一定不能少 ,不然会有异常
125 Log.e("TAG2", "" + viewList.size());
126
127
128 }
129
130
131 }
132
133 /**
134 * ViewPager的适配器 重写下面几个方法就可以了
135 */
136
137 PagerAdapter pagerAdapter = new PagerAdapter() {
138
139 @Override
140 public int getCount() {
141
142 return viewList.size();
143 }
144
145 @Override
146 public boolean isViewFromObject(View view, Object object) {
147 return view == object;
148 }
149
150 @Override
151 public void destroyItem(ViewGroup container, int position,
152 Object object) {
153 container.removeView(viewList.get(position));
154
155 }
156
157 @Override
158 public int getItemPosition(Object object) {
159
160 return super.getItemPosition(object);
161 }
162
163 @Override
164 public Object instantiateItem(ViewGroup container, int position) {
165 container.addView(viewList.get(position));
166 return viewList.get(position);
167 }
168
169 };
170
171
172 /**
173 * 下载图片方法 并将图片缓冲至手机指定位置中
174 * @param urlstr 图片URL
175 */
176 public void doPost(String urlstr){
177 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
178 Log.d("TAG", "monted sdcard");
179 } else {
180 Log.d("TAG", "has no sdcard");
181 }
182 HttpURLConnection con = null;
183 FileOutputStream fos = null;
184 BufferedOutputStream bos = null;
185 BufferedInputStream bis = null;
186 File imageFile = null;
187 try {
188 URL url = new URL(urlstr);
189 con = (HttpURLConnection) url.openConnection();
190 con.setConnectTimeout(5 * 1000);
191 con.setReadTimeout(15 * 1000);
192 con.setDoInput(true);
193 con.setDoOutput(true);
194 bis = new BufferedInputStream(con.getInputStream());
195 imageFile = new File(getImagePath(urlstr));
196 fos = new FileOutputStream(imageFile);
197 bos = new BufferedOutputStream(fos);
198 byte[] b = new byte[1024];
199 int length;
200 while ((length = bis.read(b)) != -1) {// 写入手机中
201 bos.write(b, 0, length);
202 bos.flush();
203 }
204 } catch (Exception e) {
205 e.printStackTrace();
206 } finally {
207 try {
208 if (bis != null) {
209 bis.close();
210 }
211 if (bos != null) {
212 bos.close();
213 }
214 if (con != null) {
215 con.disconnect();
216 }
217 } catch (IOException e) {
218 e.printStackTrace();
219 }
220 }
221 if (imageFile != null) {
222 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource(imageFile.getPath(),
223 290);
224 if (bitmap != null) {
225 imageLoader.addBitmapToMemoryCache(urlstr, bitmap);
226 }
227 }
228 }
229
230 /**
231 * 获取图片的本地存储路径。
232 *
233 * @param imageUrl
234 * 图片的URL地址。
235 * @return 图片的本地存储路径。
236 */
237 private String getImagePath(String imageUrl) {
238 int lastSlashIndex = imageUrl.lastIndexOf("/");
239 String imageName = imageUrl.substring(lastSlashIndex + 1);
240 String imageDir = Environment.getExternalStorageDirectory().getPath()
241 + "/pwxceshibao/";
242 File file = new File(imageDir);
243 if (!file.exists()) {
244 file.mkdirs();
245 }
246 String imagePath = imageDir + imageName;
247 return imagePath;
248 }
249
250 }
下面是几个工具类。是我从网上找的。个人觉得非常有用。所以就拿过来了。注意了,下面几个工具类都用上了,所以不能少哦
在这里要感谢
第一个是查看大图类 就是图片详情类
1 package com.higgs.mviewpager;
2
3 import android.app.Activity;
4 import android.graphics.Bitmap;
5 import android.graphics.BitmapFactory;
6 import android.os.Bundle;
7 import android.os.Environment;
8 import android.support.v4.view.PagerAdapter;
9 import android.support.v4.view.ViewPager;
10 import android.support.v4.view.ViewPager.OnPageChangeListener;
11 import android.view.LayoutInflater;
12 import android.view.View;
13 import android.view.ViewGroup;
14 import android.view.Window;
15 import android.widget.TextView;
16
17 import java.io.File;
18
19 /**
20 * 查看大图的Activity界面。
21 *
22 * @author guolin
23 */
24 public class ImageDetailsActivity extends Activity implements
25 OnPageChangeListener {
26
27 /**
28 * 用于管理图片的滑动
29 */
30 private ViewPager viewPager;
31
32 /**
33 * 显示当前图片的页数
34 */
35 private TextView pageText;
36
37 @Override
38 protected void onCreate(Bundle savedInstanceState) {
39 super.onCreate(savedInstanceState);
40 requestWindowFeature(Window.FEATURE_NO_TITLE);
41 setContentView(R.layout.image_details);
42 int imagePosition = getIntent().getIntExtra("image_position", 0);
43 pageText = (TextView) findViewById(R.id.page_text);
44 viewPager = (ViewPager) findViewById(R.id.view_pager);
45 ViewPagerAdapter adapter = new ViewPagerAdapter();
46 viewPager.setAdapter(adapter);
47 viewPager.setCurrentItem(imagePosition);
48 viewPager.setOnPageChangeListener(this);
49 viewPager.setEnabled(false);
50 // 设定当前的页数和总页数
51 pageText.setText((imagePosition + 1) + "/" + Images.imageUrls.length);
52 }
53
54 /**
55 * ViewPager的适配器
56 *
57 * @author guolin
58 */
59 class ViewPagerAdapter extends PagerAdapter {
60
61 @Override
62 public Object instantiateItem(ViewGroup container, int position) {
63 String imagePath = getImagePath(Images.imageUrls[position]);
64 Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
65 if (bitmap == null) {
66 bitmap = BitmapFactory.decodeResource(getResources(),
67 R.drawable.empty_photo);
68 }
69 View view = LayoutInflater.from(ImageDetailsActivity.this).inflate(
70 R.layout.zoom_image_layout, null);
71 ZoomImageView zoomImageView = (ZoomImageView) view
72 .findViewById(R.id.zoom_image_view);
73 zoomImageView.setImageBitmap(bitmap);
74 container.addView(view);
75 return view;
76 }
77
78 @Override
79 public int getCount() {
80 return Images.imageUrls.length;
81 }
82
83 @Override
84 public boolean isViewFromObject(View arg0, Object arg1) {
85 return arg0 == arg1;
86 }
87
88 @Override
89 public void destroyItem(ViewGroup container, int position, Object object) {
90 View view = (View) object;
91 container.removeView(view);
92 }
93
94 }
95
96 /**
97 * 获取图片的本地存储路径。
98 *
99 * @param imageUrl
100 * 图片的URL地址。
101 * @return 图片的本地存储路径。
102 */
103 private String getImagePath(String imageUrl) {
104 int lastSlashIndex = imageUrl.lastIndexOf("/");
105 String imageName = imageUrl.substring(lastSlashIndex + 1);
106 String imageDir = Environment.getExternalStorageDirectory().getPath()
107 + "/pwxceshibao/";
108 File file = new File(imageDir);
109 if (!file.exists()) {
110 file.mkdirs();
111 }
112 String imagePath = imageDir + imageName;
113 return imagePath;
114 }
115
116 @Override
117 public void onPageScrollStateChanged(int arg0) {
118
119 }
120
121 @Override
122 public void onPageScrolled(int arg0, float arg1, int arg2) {
123
124 }
125
126 @Override
127 public void onPageSelected(int currentPage) {
128 // 每当页数发生改变时重新设定一遍当前的页数和总页数
129 pageText.setText((currentPage + 1) + "/" + Images.imageUrls.length);
130 }
131
132 }
第二个是图片缩放工具类
1 package com.higgs.mviewpager;
2
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.Canvas;
6 import android.graphics.Matrix;
7 import android.util.AttributeSet;
8 import android.view.MotionEvent;
9 import android.view.View;
10
11 /**
12 * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动
13 *
14 * @author guolin
15 */
16 public class ZoomImageView extends View {
17
18 /**
19 * 初始化状态常量
20 */
21 public static final int STATUS_INIT = 1;
22
23 /**
24 * 图片放大状态常量
25 */
26 public static final int STATUS_ZOOM_OUT = 2;
27
28 /**
29 * 图片缩小状态常量
30 */
31 public static final int STATUS_ZOOM_IN = 3;
32
33 /**
34 * 图片拖动状态常量
35 */
36 public static final int STATUS_MOVE = 4;
37
38 /**
39 * 用于对图片进行移动和缩放变换的矩阵
40 */
41 private Matrix matrix = new Matrix();
42
43 /**
44 * 待展示的Bitmap对象
45 */
46 private Bitmap sourceBitmap;
47
48 /**
49 * 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
50 */
51 private int currentStatus;
52
53 /**
54 * ZoomImageView控件的宽度
55 */
56 private int width;
57
58 /**
59 * ZoomImageView控件的高度
60 */
61 private int height;
62
63 /**
64 * 记录两指同时放在屏幕上时,中心点的横坐标值
65 */
66 private float centerPointX;
67
68 /**
69 * 记录两指同时放在屏幕上时,中心点的纵坐标值
70 */
71 private float centerPointY;
72
73 /**
74 * 记录当前图片的宽度,图片被缩放时,这个值会一起变动
75 */
76 private float currentBitmapWidth;
77
78 /**
79 * 记录当前图片的高度,图片被缩放时,这个值会一起变动
80 */
81 private float currentBitmapHeight;
82
83 /**
84 * 记录上次手指移动时的横坐标
85 */
86 private float lastXMove = -1;
87
88 /**
89 * 记录上次手指移动时的纵坐标
90 */
91 private float lastYMove = -1;
92
93 /**
94 * 记录手指在横坐标方向上的移动距离
95 */
96 private float movedDistanceX;
97
98 /**
99 * 记录手指在纵坐标方向上的移动距离
100 */
101 private float movedDistanceY;
102
103 /**
104 * 记录图片在矩阵上的横向偏移值
105 */
106 private float totalTranslateX;
107
108 /**
109 * 记录图片在矩阵上的纵向偏移值
110 */
111 private float totalTranslateY;
112
113 /**
114 * 记录图片在矩阵上的总缩放比例
115 */
116 private float totalRatio;
117
118 /**
119 * 记录手指移动的距离所造成的缩放比例
120 */
121 private float scaledRatio;
122
123 /**
124 * 记录图片初始化时的缩放比例
125 */
126 private float initRatio;
127
128 /**
129 * 记录上次两指之间的距离
130 */
131 private double lastFingerDis;
132
133 /**
134 * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
135 *
136 * @param context
137 * @param attrs
138 */
139 public ZoomImageView(Context context, AttributeSet attrs) {
140 super(context, attrs);
141 currentStatus = STATUS_INIT;
142 }
143
144 /**
145 * 将待展示的图片设置进来。
146 *
147 * @param bitmap
148 * 待展示的Bitmap对象
149 */
150 public void setImageBitmap(Bitmap bitmap) {
151 sourceBitmap = bitmap;
152 invalidate();
153 }
154
155 @Override
156 protected void onLayout(boolean changed, int left, int top, int right,
157 int bottom) {
158 super.onLayout(changed, left, top, right, bottom);
159 if (changed) {
160 // 分别获取到ZoomImageView的宽度和高度
161 width = getWidth();
162 height = getHeight();
163 }
164 }
165
166 @Override
167 public boolean onTouchEvent(MotionEvent event) {
168 if (initRatio == totalRatio) {
169 getParent().requestDisallowInterceptTouchEvent(false);
170 } else {
171 getParent().requestDisallowInterceptTouchEvent(true);
172 }
173 switch (event.getActionMasked()) {
174 case MotionEvent.ACTION_POINTER_DOWN:
175 if (event.getPointerCount() == 2) {
176 // 当有两个手指按在屏幕上时,计算两指之间的距离
177 lastFingerDis = distanceBetweenFingers(event);
178 }
179 break;
180 case MotionEvent.ACTION_CANCEL:
181 case MotionEvent.ACTION_MOVE:
182 if (event.getPointerCount() == 1) {
183 // 只有单指按在屏幕上移动时,为拖动状态
184 float xMove = event.getX();
185 float yMove = event.getY();
186 if (lastXMove == -1 && lastYMove == -1) {
187 lastXMove = xMove;
188 lastYMove = yMove;
189 }
190 currentStatus = STATUS_MOVE;
191 movedDistanceX = xMove - lastXMove;
192 movedDistanceY = yMove - lastYMove;
193 // 进行边界检查,不允许将图片拖出边界
194 if (totalTranslateX + movedDistanceX > 0) {
195 movedDistanceX = 0;
196 } else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
197 movedDistanceX = 0;
198 }
199 if (totalTranslateY + movedDistanceY > 0) {
200 movedDistanceY = 0;
201 } else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
202 movedDistanceY = 0;
203 }
204 // 调用onDraw()方法绘制图片
205 invalidate();
206 lastXMove = xMove;
207 lastYMove = yMove;
208 } else if (event.getPointerCount() == 2) {
209 // 有两个手指按在屏幕上移动时,为缩放状态
210 centerPointBetweenFingers(event);
211 double fingerDis = distanceBetweenFingers(event);
212 if (fingerDis > lastFingerDis) {
213 currentStatus = STATUS_ZOOM_OUT;
214 } else {
215 currentStatus = STATUS_ZOOM_IN;
216 }
217 // 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
218 if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
219 || (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
220 scaledRatio = (float) (fingerDis / lastFingerDis);
221 totalRatio = totalRatio * scaledRatio;
222 if (totalRatio > 4 * initRatio) {
223 totalRatio = 4 * initRatio;
224 } else if (totalRatio < initRatio) {
225 totalRatio = initRatio;
226 }
227 // 调用onDraw()方法绘制图片
228 invalidate();
229 lastFingerDis = fingerDis;
230 }
231 }
232 break;
233 case MotionEvent.ACTION_POINTER_UP:
234 if (event.getPointerCount() == 2) {
235 // 手指离开屏幕时将临时值还原
236 lastXMove = -1;
237 lastYMove = -1;
238 }
239 break;
240 case MotionEvent.ACTION_UP:
241 // 手指离开屏幕时将临时值还原
242 lastXMove = -1;
243 lastYMove = -1;
244 break;
245 default:
246 break;
247 }
248 return true;
249 }
250
251 /**
252 * 根据currentStatus的值来决定对图片进行什么样的绘制操作。
253 */
254 @Override
255 protected void onDraw(Canvas canvas) {
256 super.onDraw(canvas);
257 switch (currentStatus) {
258 case STATUS_ZOOM_OUT:
259 case STATUS_ZOOM_IN:
260 zoom(canvas);
261 break;
262 case STATUS_MOVE:
263 move(canvas);
264 break;
265 case STATUS_INIT:
266 initBitmap(canvas);
267 default:
268 if (sourceBitmap != null) {
269 canvas.drawBitmap(sourceBitmap, matrix, null);
270 }
271 break;
272 }
273 }
274
275 /**
276 * 对图片进行缩放处理。
277 *
278 * @param canvas
279 */
280 private void zoom(Canvas canvas) {
281 matrix.reset();
282 // 将图片按总缩放比例进行缩放
283 matrix.postScale(totalRatio, totalRatio);
284 float scaledWidth = sourceBitmap.getWidth() * totalRatio;
285 float scaledHeight = sourceBitmap.getHeight() * totalRatio;
286 float translateX = 0f;
287 float translateY = 0f;
288 // 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放
289 if (currentBitmapWidth < width) {
290 translateX = (width - scaledWidth) / 2f;
291 } else {
292 translateX = totalTranslateX * scaledRatio + centerPointX
293 * (1 - scaledRatio);
294 // 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕
295 if (translateX > 0) {
296 translateX = 0;
297 } else if (width - translateX > scaledWidth) {
298 translateX = width - scaledWidth;
299 }
300 }
301 // 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
302 if (currentBitmapHeight < height) {
303 translateY = (height - scaledHeight) / 2f;
304 } else {
305 translateY = totalTranslateY * scaledRatio + centerPointY
306 * (1 - scaledRatio);
307 // 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕
308 if (translateY > 0) {
309 translateY = 0;
310 } else if (height - translateY > scaledHeight) {
311 translateY = height - scaledHeight;
312 }
313 }
314 // 缩放后对图片进行偏移,以保证缩放后中心点位置不变
315 matrix.postTranslate(translateX, translateY);
316 totalTranslateX = translateX;
317 totalTranslateY = translateY;
318 currentBitmapWidth = scaledWidth;
319 currentBitmapHeight = scaledHeight;
320 canvas.drawBitmap(sourceBitmap, matrix, null);
321 }
322
323 /**
324 * 对图片进行平移处理
325 *
326 * @param canvas
327 */
328 private void move(Canvas canvas) {
329 matrix.reset();
330 // 根据手指移动的距离计算出总偏移值
331 float translateX = totalTranslateX + movedDistanceX;
332 float translateY = totalTranslateY + movedDistanceY;
333 // 先按照已有的缩放比例对图片进行缩放
334 matrix.postScale(totalRatio, totalRatio);
335 // 再根据移动距离进行偏移
336 matrix.postTranslate(translateX, translateY);
337 totalTranslateX = translateX;
338 totalTranslateY = translateY;
339 canvas.drawBitmap(sourceBitmap, matrix, null);
340 }
341
342 /**
343 * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。
344 *
345 * @param canvas
346 */
347 private void initBitmap(Canvas canvas) {
348 if (sourceBitmap != null) {
349 matrix.reset();
350 int bitmapWidth = sourceBitmap.getWidth();
351 int bitmapHeight = sourceBitmap.getHeight();
352 if (bitmapWidth > width || bitmapHeight > height) {
353 if (bitmapWidth - width > bitmapHeight - height) {
354 // 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来
355 float ratio = width / (bitmapWidth * 1.0f);
356 matrix.postScale(ratio, ratio);
357 float translateY = (height - (bitmapHeight * ratio)) / 2f;
358 // 在纵坐标方向上进行偏移,以保证图片居中显示
359 matrix.postTranslate(0, translateY);
360 totalTranslateY = translateY;
361 totalRatio = initRatio = ratio;
362 } else {
363 // 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来
364 float ratio = height / (bitmapHeight * 1.0f);
365 matrix.postScale(ratio, ratio);
366 float translateX = (width - (bitmapWidth * ratio)) / 2f;
367 // 在横坐标方向上进行偏移,以保证图片居中显示
368 matrix.postTranslate(translateX, 0);
369 totalTranslateX = translateX;
370 totalRatio = initRatio = ratio;
371 }
372 currentBitmapWidth = bitmapWidth * initRatio;
373 currentBitmapHeight = bitmapHeight * initRatio;
374 } else {
375 // 当图片的宽高都小于屏幕宽高时,直接让图片居中显示
376 float translateX = (width - sourceBitmap.getWidth()) / 2f;
377 float translateY = (height - sourceBitmap.getHeight()) / 2f;
378 matrix.postTranslate(translateX, translateY);
379 totalTranslateX = translateX;
380 totalTranslateY = translateY;
381 totalRatio = initRatio = 1f;
382 currentBitmapWidth = bitmapWidth;
383 currentBitmapHeight = bitmapHeight;
384 }
385 canvas.drawBitmap(sourceBitmap, matrix, null);
386 }
387 }
388
389 /**
390 * 计算两个手指之间的距离。
391 *
392 * @param event
393 * @return 两个手指之间的距离
394 */
395 private double distanceBetweenFingers(MotionEvent event) {
396 float disX = Math.abs(event.getX(0) - event.getX(1));
397 float disY = Math.abs(event.getY(0) - event.getY(1));
398 return Math.sqrt(disX * disX + disY * disY);
399 }
400
401 /**
402 * 计算两个手指之间中心点的坐标。
403 *
404 * @param event
405 */
406 private void centerPointBetweenFingers(MotionEvent event) {
407 float xPoint0 = event.getX(0);
408 float yPoint0 = event.getY(0);
409 float xPoint1 = event.getX(1);
410 float yPoint1 = event.getY(1);
411 centerPointX = (xPoint0 + xPoint1) / 2;
412 centerPointY = (yPoint0 + yPoint1) / 2;
413 }
414
415 }
最后一个是图片管理工具类 也是缓存核心类 这个就是上面提到的防止加载过多的图片时产生OOM
1 package com.higgs.mviewpager;
2
3 import android.graphics.Bitmap;
4 import android.graphics.BitmapFactory;
5 import android.util.LruCache;
6
7 /**
8 * 对图片进行管理的工具类。
9 *
10 * @author Tony
11 */
12 public class ImageLoader {
13
14 /**
15 * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
16 */
17 private static LruCache<String, Bitmap> mMemoryCache;
18
19 /**
20 * ImageLoader的实例。
21 */
22 private static ImageLoader mImageLoader;
23
24 private ImageLoader() {
25 // 获取应用程序最大可用内存
26 int maxMemory = (int) Runtime.getRuntime().maxMemory();
27 int cacheSize = maxMemory / 8;
28 // 设置图片缓存大小为程序最大可用内存的1/8
29 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
30 @Override
31 protected int sizeOf(String key, Bitmap bitmap) {
32 return bitmap.getByteCount();
33 }
34 };
35 }
36
37 /**
38 * 获取ImageLoader的实例。
39 *
40 * @return ImageLoader的实例。
41 */
42 public static ImageLoader getInstance() {
43 if (mImageLoader == null) {
44 mImageLoader = new ImageLoader();
45 }
46 return mImageLoader;
47 }
48
49 /**
50 * 将一张图片存储到LruCache中。
51 *
52 * @param key
53 * LruCache的键,这里传入图片的URL地址。
54 * @param bitmap
55 * LruCache的键,这里传入从网络上下载的Bitmap对象。
56 */
57 public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
58 if (getBitmapFromMemoryCache(key) == null) {
59 mMemoryCache.put(key, bitmap);
60 }
61 }
62
63 /**
64 * 从LruCache中获取一张图片,如果不存在就返回null。
65 *
66 * @param key
67 * LruCache的键,这里传入图片的URL地址。
68 * @return 对应传入键的Bitmap对象,或者null。
69 */
70 public Bitmap getBitmapFromMemoryCache(String key) {
71 return mMemoryCache.get(key);
72 }
73
74 public static int calculateInSampleSize(BitmapFactory.Options options,
75 int reqWidth) {
76 // 源图片的宽度
77 final int width = options.outWidth;
78 int inSampleSize = 1;
79 if (width > reqWidth) {
80 // 计算出实际宽度和目标宽度的比率
81 final int widthRatio = Math.round((float) width / (float) reqWidth);
82 inSampleSize = widthRatio;
83 }
84 return inSampleSize;
85 }
86
87 public static Bitmap decodeSampledBitmapFromResource(String pathName,
88 int reqWidth) {
89 // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
90 final BitmapFactory.Options options = new BitmapFactory.Options();
91 options.inJustDecodeBounds = true;
92 BitmapFactory.decodeFile(pathName, options);
93 // 调用上面定义的方法计算inSampleSize值
94 options.inSampleSize = calculateInSampleSize(options, reqWidth);
95 // 使用获取到的inSampleSize值再次解析图片
96 options.inJustDecodeBounds = false;
97 return BitmapFactory.decodeFile(pathName, options);
98 }
99
100 }