編輯:關於Android編程
因為項目中需要用到所以實現的一個橫向的照片浏覽器,使用橫向SrollView實現。
實現效果如下:
實現思路:
在開始做之前呢,本著有輪子就用輪子的精神,也還是去百度找了很久,諸如"Android橫向照片牆"、"Android橫向照片流"、"Android橫向照片選擇器"…完全沒有好咩。。查來查去都是那幾篇豎向照片瀑布流的,橫向的反正我是沒找到。
然後,在將郭神的《ndroid瀑布流照片牆實現,體驗不規則排列的美感》一文拜讀之後(http://blog.csdn.net/guolin_blog/article/details/10470797),靈雞一動,想著既然豎向的能實現,那麼橫向的豈不是轉個方向就好了?
雖然最終實現起來還是花了一點時間,但是基本原理好像就是轉了個方向。。。但是修改後的代碼和郭神的源碼雖說圖片加載部分我們沒有改動,但在很多地方都還是很很大區別的。下面特別說明一下。
需要注意的點有以下三個方面:
1、不再繼承自普通的ScrollView而是繼承自HorizontalScrollView 。
2、在onLayout的初始化中不再初始化三列照片(郭神寫的是瀑布流嘛~),而是改為橫向的一列,並使每張照片的寬高相等,使之保持正方形。
3、在可見性判斷中不再根據高度而是根據寬度進行判斷:
/** * 遍歷imageViewList中的每張圖片,對圖片的可見性進行檢查,如果圖片已經離開屏幕可見范圍,則將圖片替換成一張空圖。 */ public void checkVisibility() { for (int i = 0; i < imageViewList.size(); i++) { ImageView imageView = imageViewList.get(i); int borderLeft = (Integer) imageView.getTag(R.string.border_top); int borderRight = (Integer) imageView .getTag(R.string.border_bottom); if (borderLeft > getScrollX() && borderRight < getScrollX() + ColumnWith) { String imageUrl = (String) imageView.getTag(R.string.image_url); //從內存中獲取圖片 Bitmap bitmap = NGImageLoader.getBitmapFromMemoryCache(imageUrl); if (bitmap!=null) { imageView.setImageBitmap(bitmap); }else { //TODO 顯示空圖 } } else { } } }
源碼實現如下:
package com.whale.nangua.toquan.view; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.os.AsyncTask; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Toast; import com.whale.nangua.toquan.R; import com.whale.nangua.toquan.UserInfoActivity; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Created by nangua on 2016/8/3. */ public class NGOthersInfoAtyHorizotalScrollView extends HorizontalScrollView implements View.OnTouchListener{ /** * 是否已加載過一次layout,這裡onLayout中的初始化只需加載一次 */ private boolean loadOnce; /** * 列的布局 */ private LinearLayout linearlayout_userinfo_personal_column; /** * 總的寬度 */ private static int ColumnWith; /** * 每張照片的寬度 */ private int perphotoWidth; /** * 記錄上垂直方向的滾動距離。 */ private static int lastScrollX = -1; /** * MyScrollView下的直接子布局。 */ private static View scrollLayout; /** * 進行一些關鍵性的初始化操作,NGOthersInfoAtyHorizotalScrollView,以及得到高度值。並在這裡開始加載第一頁的圖片。 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (changed && !loadOnce) { scrollViewHeight = getHeight(); linearlayout_userinfo_personal_column = new LinearLayout(getContext()); linearlayout_userinfo_personal_column.setLayoutParams( new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT , ViewGroup.LayoutParams.MATCH_PARENT) ); linearlayout_userinfo_personal_column.setOrientation(LinearLayout.HORIZONTAL); this.addView(linearlayout_userinfo_personal_column); perphotoWidth = scrollViewHeight; //每張照片的寬度等於列高 loadOnce = true; //加載下一頁圖片 loadMoreImages(); scrollLayout = getChildAt(0); } } /** * 記錄當前已加載到第幾頁 * @param context */ private int page = 0; /** * 每頁要加載的圖片數量 * 默認為5張 * @param context */ public static final int PAGE_SIZE = 5; /** * 記錄所有正在下載或等待下載的任務。 */ private static SettaskCollection; /** * 對圖片進行管理的工具類 */ private com.whale.nangua.toquan.utils.NGImageLoader NGImageLoader; /** * MyScrollView布局的高度。 */ private static int scrollViewHeight; /** * MyScrollView的構造函數。 * @param context * @param attrs */ public NGOthersInfoAtyHorizotalScrollView(Context context, AttributeSet attrs) { super(context, attrs); NGImageLoader = NGImageLoader.getInstance(); taskCollection = new HashSet (); setOnTouchListener(this); } /** * 在Handler中進行圖片可見性檢查的判斷,以及加載更多圖片的操作。 */ private static Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { NGOthersInfoAtyHorizotalScrollView myScrollView = (NGOthersInfoAtyHorizotalScrollView) msg.obj; int scrollX = myScrollView.getScrollX(); // 如果當前的滾動位置和上次相同,表示已停止滾動 if (scrollX == lastScrollX) { // 當滾動的最右邊,並且當前沒有正在下載的任務時,開始加載下一頁的圖片 if ( ColumnWith + scrollX >= (scrollLayout.getWidth() ) && taskCollection.isEmpty()) { myScrollView.loadMoreImages(); } myScrollView.checkVisibility(); } else { lastScrollX = scrollX; Message message = new Message(); message.obj = myScrollView; // 5毫秒後再次對滾動位置進行判斷 handler.sendMessageDelayed(message, 5); } } }; /** * 監聽用戶的觸屏事件,如果用戶手指離開屏幕則開始進行滾動檢測。 */ @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { Message message = new Message(); message.obj = this; handler.sendMessageDelayed(message, 5); } return false; } /** * 遍歷imageViewList中的每張圖片,對圖片的可見性進行檢查,如果圖片已經離開屏幕可見范圍,則將圖片替換成一張空圖。 */ public void checkVisibility() { for (int i = 0; i < imageViewList.size(); i++) { ImageView imageView = imageViewList.get(i); int borderLeft = (Integer) imageView.getTag(R.string.border_top); int borderRight = (Integer) imageView .getTag(R.string.border_bottom); if (borderLeft > getScrollX() && borderRight < getScrollX() + ColumnWith) { String imageUrl = (String) imageView.getTag(R.string.image_url); //從內存中獲取圖片 Bitmap bitmap = NGImageLoader.getBitmapFromMemoryCache(imageUrl); if (bitmap!=null) { imageView.setImageBitmap(bitmap); }else { //TODO 顯示空圖 } } else { } } } static boolean hasOver = false; private String[] imageUrls; public void setImageUrls(String[] imageUrls) { this.imageUrls = imageUrls; } /** * 開始加載下一頁的圖片,每張圖片都會開啟一個異步線程去下載。 */ public void loadMoreImages() { if (hasSDCard()&& imageUrls!=null) { //判斷是否有SD卡 int startIndex = page * PAGE_SIZE; //起始位置 int endIndex = page * PAGE_SIZE + PAGE_SIZE; //結束位置 if (startIndex < imageUrls.length) { //Toast.makeText(getContext(), "正在加載...", Toast.LENGTH_SHORT).show(); if (endIndex > imageUrls.length) { endIndex = imageUrls.length; } for (int i = startIndex; i < endIndex; i++) { //加載圖片 LoadImageTask task = new LoadImageTask(); taskCollection.add(task); task.execute(imageUrls[i]); } page++; } else { if (hasOver == false) { Toast.makeText(getContext(), "已沒有更多圖片", Toast.LENGTH_SHORT).show(); hasOver = true; } } } else { //Toast.makeText(getContext(), "未發現SD卡", Toast.LENGTH_SHORT).show(); } } /** * 判斷手機是否有SD卡。 * @return 有SD卡返回true,沒有返回false。 */ private boolean hasSDCard() { return Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()); } public int dpToPx(Resources res, int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics()); } /** * 記錄所有界面上的圖片,用以可以隨時控制對圖片的釋放。 */ private List imageViewList = new ArrayList (); /** * 異步下載圖片的任務。 * * @author guolin */ class LoadImageTask extends AsyncTask { @Override public boolean equals(Object o) { return super.equals(o); } @Override public int hashCode() { return super.hashCode(); } /** * 圖片的URL地址 */ private String mImageUrl; /** * 可重復使用的ImageView */ private ImageView mImageView; public LoadImageTask() { } /** * 將可重復使用的ImageView傳入 * * @param imageView */ public LoadImageTask(ImageView imageView) { mImageView = imageView; } @Override protected Bitmap doInBackground(String... params) { mImageUrl = params[0]; Bitmap imageBitmap = NGImageLoader .getBitmapFromMemoryCache(mImageUrl); if (imageBitmap == null) { imageBitmap = loadImage(mImageUrl); } return imageBitmap; } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { addImage(bitmap, perphotoWidth, perphotoWidth); } taskCollection.remove(this); } /** * 根據傳入的URL,對圖片進行加載。如果這張圖片已經存在於SD卡中,則直接從SD卡裡讀取,否則就從網絡上下載。 * * @param imageUrl * 圖片的URL地址 * @return 加載到內存的圖片。 */ private Bitmap loadImage(String imageUrl) { File imageFile = new File(getImagePath(imageUrl)); if (!imageFile.exists()) { downloadImage(imageUrl); } if (imageUrl != null) { Bitmap bitmap = NGImageLoader.decodeSampledBitmapFromResource( imageFile.getPath(), perphotoWidth); if (bitmap != null) { NGImageLoader.addBitmapToMemoryCache(imageUrl, bitmap); return bitmap; } } return null; } /** * 向ImageView中添加一張圖片 * * @param bitmap * 待添加的圖片 * @param imageWidth * 圖片的寬度 * @param imageHeight * 圖片的高度 */ private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( imageWidth, imageHeight); if (mImageView != null) { mImageView.setImageBitmap(bitmap); } else { ImageView imageView = new ImageView(getContext()); imageView.setLayoutParams(params); imageView.setImageBitmap(bitmap); imageView.setScaleType(ImageView.ScaleType.FIT_XY); //imageView.setPadding(5, 5, 5, 5); imageView.setTag(R.string.image_url, mImageUrl); //這裡應該計算圖片當前的位置 // imageView.setTag(R.string.border_top, firstColumnHeight); imageView.setTag(R.string.border_top, ColumnWith); ColumnWith += perphotoWidth;//增加總寬 imageView.setTag(R.string.border_bottom, ColumnWith); linearlayout_userinfo_personal_column.addView(imageView); imageViewList.add(imageView); } } /** * 將圖片下載到SD卡緩存起來。 * * @param imageUrl * 圖片的URL地址。 */ private void downloadImage(String imageUrl) { HttpURLConnection con = null; FileOutputStream fos = null; BufferedOutputStream bos = null; BufferedInputStream bis = null; File imageFile = null; try { URL url = new URL(imageUrl); con = (HttpURLConnection) url.openConnection(); con.setConnectTimeout(5 * 1000); con.setReadTimeout(15 * 1000); con.setDoInput(true); con.setDoOutput(true); bis = new BufferedInputStream(con.getInputStream()); imageFile = new File(getImagePath(imageUrl)); fos = new FileOutputStream(imageFile); bos = new BufferedOutputStream(fos); byte[] b = new byte[1024]; int length; while ((length = bis.read(b)) != -1) { bos.write(b, 0, length); bos.flush(); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (bis != null) { bis.close(); } if (bos != null) { bos.close(); } if (con != null) { con.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } if (imageFile != null) { Bitmap bitmap = NGImageLoader.decodeSampledBitmapFromResource( imageFile.getPath(), perphotoWidth); if (bitmap != null) { NGImageLoader.addBitmapToMemoryCache(imageUrl, bitmap); } } } /** * 獲取圖片的本地存儲路徑。 * * @param imageUrl * 圖片的URL地址。 * @return 圖片的本地存儲路徑。 */ private String getImagePath(String imageUrl) { int lastSlashIndex = imageUrl.lastIndexOf("/"); String imageName = imageUrl.substring(lastSlashIndex + 1); String imageDir = Environment.getExternalStorageDirectory() .getPath() + "/PhotoWallFalls/"; File file = new File(imageDir); if (!file.exists()) { file.mkdirs(); } String imagePath = imageDir + imageName; return imagePath; } } }
本文實例講述了Android編程基於自定義View實現絢麗的圓形進度條功能。分享給大家供大家參考,具體如下:本文包含兩個組件,首先上效果圖:1.ProgressBarVi
一、概述講解優化查詢相冊圖片之前,我們先來看下PM提出的需求,PM的需求很簡單,就是要做一個類似微信的本地相冊圖片查詢控件,主要包含兩個兩部分: 進入圖片選擇頁面就要顯
本篇博客要分享的一個效果是實現廣告Banner輪播效果,這個效果也比較常見,一些視頻類應用就經常有,就拿360影視大全來舉例吧: 用紅框框住的那個效果就是小巫今
本文實例講述了Android編程實現長按Button按鈕連續響應功能。分享給大家供大家參考,具體如下:在電商類app的購物車頁面,經常會有這樣的需求:長按“+”按鈕或者“