最近因為要做一個項目,需要使用到圖片的瀏覽。我就自己在網上找了些資料,然后加以修改整理后出來一個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 "http://img.my.csdn.net/uploads/201309/01/1378037235_3453.jpg", 7 "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg", 8 "http://img.my.csdn.net/uploads/201309/01/1378037235_9280.jpg", 9 "http://img.my.csdn.net/uploads/201309/01/1378037234_3539.jpg", 10 "http://img.my.csdn.net/uploads/201309/01/1378037234_6318.jpg", 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 }
下面是幾個工具類。是我從網上找的。個人覺得非常有用。所以就拿過來了。注意了,下面幾個工具類都用上了,所以不能少哦
在這里要感謝 http://blog.csdn.net/sziicool/article/details/18728187 博主,我是站在他的肩膀上修改的。
第一個是查看大圖類 就是圖片詳情類
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 }
好了 大家照着自己做做就可以出來效果了,因為我已經把全部的源碼貼出來了,如果你懶得連代碼都不想敲。我覺得此文章對你沒有什么作用。只有自己敲了就理解了
第一次寫博客,感覺思路很亂,很多都沒有講明白。一個是時間不夠,二是關鍵點都有注釋,代碼都貼上來了。共勉~~~~