編輯:關於Android編程
這是一個Android瀑布流的實現demo。
瀑布流我的實現是定義三個linearlayout,然後向裡面addView(),如果多了會出現oom異常,所以做了一些處理。
1.lrucache緩存
2.只顯示當前屏的圖片
3.滑動過程中不加載圖片
4.大圖縮放成小圖
直接看代碼:
PhotoFallScrollView.java主類 自定義的ScrollView.
package com.pangzaifei.falls; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Toast; /** * 瀑布流類 * * 原理: 1:創建3個linearlayout,設置他們的寬度,將獲得的圖片壓縮成和3個linearlayout一樣的寬度, * 然後根據3個linearlayout的高度來判斷,將bitmap添加到哪一個linearlayout中 * 2:翻頁處理,根據手勢抬起的位置和滑動的末尾處來進行翻頁 * * @author pangzf * @date 2014年7月15日 上午10:33:05 */ public class PhotoFallScrollView extends ScrollView implements OnTouchListener { /** * 頁數 */ private static int page; /** * 每頁顯示多少張 */ private static final int PAGE_SIZE = 8; private Context mContext; /** * 數據源圖片 */ private Images mImagesThoumb; /** * task請求集合 */ private Set上面是主要的東西,思路和注釋已經添加。其中imageView中的tag我要解釋一下,主要保存了每一列的上邊距和下邊距和圖片的url,這個方法,就是只顯示當前頁的圖片。mTasks; boolean isFirstEntr = true; private LinearLayout mFirstColumn; private LinearLayout mSecondColumn; private LinearLayout mThirdColumn; private int mFirstColumnHeight; private int mSecondColumnHeight; private int mThirdColumnHeight; private int mClolumnWidth; private long mDelay = 5; /** * 上次滑動的最後位置 */ private static int lastScrollY = -1; /** * 是否已加載過一次layout,這裡onLayout中的初始化只需加載一次 */ private boolean loadOnce; /** * 存放圖片的集合 */ private List mImageViewList = new ArrayList (); public PhotoFallScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.mContext = context; init(); } public PhotoFallScrollView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; init(); } public PhotoFallScrollView(Context context) { super(context); this.mContext = context; init(); } /** * 初始化 */ private void init() { mImagesThoumb = Images.getInstance(); mTasks = new HashSet (); setOnTouchListener(this); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); // 第一次進入就加載第一頁的圖片 if (changed && !loadOnce) { mScrollViewHeight = this.getHeight(); mScrollLayout = this.getChildAt(0); mFirstColumn = (LinearLayout) findViewById(R.id.first_column); mSecondColumn = (LinearLayout) findViewById(R.id.second_column); mThirdColumn = (LinearLayout) findViewById(R.id.third_column); mClolumnWidth = mFirstColumn.getWidth(); loadOnce = true; loadMoreImages(); } } /** * 加載圖片 */ private void loadMoreImages() { if (hashSdcard()) { // 根據頁數加載圖片 int startIndex = page * PAGE_SIZE; int endIndex = page * PAGE_SIZE + PAGE_SIZE; if (startIndex < mImagesThoumb.imageThumbs.length) { if (endIndex > mImagesThoumb.imageThumbs.length) { endIndex = mImagesThoumb.imageThumbs.length; } for (int i = startIndex; i < endIndex; i++) { String imageUrl = mImagesThoumb.imageThumbs[i].toString(); if (imageUrl != null && !"".equals(imageUrl)) { downLoadData(imageUrl); } } page++; } else { Toast.makeText(mContext, "沒有更多圖片了", 0).show(); } } else { Toast.makeText(mContext, "無sdcard", 0).show(); } } /** * 下載 * * @param imageUrl */ private void downLoadData(String imageUrl) { DownLoadTask task = new DownLoadTask(); mTasks.add(task); task.execute(imageUrl); } public class DownLoadTask extends AsyncTask { private String mImageUrl; @Override protected Bitmap doInBackground(String... params) { try { mImageUrl = params[0]; Bitmap bitmapFromMemory = mImagesThoumb .getMemoryCache(mImageUrl); if (bitmapFromMemory != null) { return bitmapFromMemory; } if (hashSdcard()) { Bitmap bitmap = loadImage(mImageUrl); return bitmap; } else { Toast.makeText(mContext, "無sdcard,無法獲取圖片", 0).show(); } } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); // 展示圖片 if (bitmap != null) { // 1.縮放圖片 // 2.新建ImageView // 3.找到需要的linerlayout添加imageView float width = bitmap.getWidth(); float radio = width / mFirstColumn.getWidth(); float scaleHeight = bitmap.getHeight() / radio; addImage(bitmap, mFirstColumn.getWidth(), scaleHeight); } mTasks.remove(this); } /** * 將圖片添加到linearlayout中 * * @param bitmap * @param scaleHeight */ public void addImage(Bitmap bitmap, float width, float scaleHeight) { // 生成縮放的iv ImageView iv = new ImageView(mContext); android.view.ViewGroup.LayoutParams params = new LayoutParams( (int) width, (int) scaleHeight); iv.setLayoutParams(params); if (bitmap != null) { // 解決默認圖片有大有小的問題 iv.setScaleType(ScaleType.FIT_XY); iv.setPadding(5, 5, 5, 5); iv.setImageBitmap(bitmap); iv.setTag(R.string.iamgurl, mImageUrl); findColumnToAdd(iv, (int) scaleHeight).addView(iv); mImageViewList.add(iv); } } } private Bitmap downLoad(String imageUrl) throws IOException { BufferedInputStream bis = null; FileOutputStream fos = null; BufferedOutputStream bos = null; HttpURLConnection conn = null; File imageFile = null; try { URL url = new URL(imageUrl); conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000); conn.setConnectTimeout(5000); conn.setDoInput(true); conn.setDoOutput(true); InputStream is = conn.getInputStream(); imageFile = new File(getImagePath(imageUrl)); bis = new BufferedInputStream(is); fos = new FileOutputStream(imageFile); bos = new BufferedOutputStream(fos); int len = 0; byte[] buffer = new byte[1024]; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); bos.flush(); } } catch (Exception e) { e.printStackTrace(); } finally { if (bis != null) { bis.close(); } if (bos != null) { bos.close(); } if (conn != null) { conn.disconnect(); } } // 如果imageFile不為null,將圖片添加到memory中 if (imageFile != null) { Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getPath()); mImagesThoumb.addBitmapToMemoryCache(imageUrl, bitmap); return bitmap; } return null; } /** * 判斷圖片sdcard是否有圖片,如果有就用,沒有就下載 * * @param mImageUrl * @return */ public Bitmap loadImage(String mImageUrl) throws Exception { File file = new File(getImagePath(mImageUrl)); if (!file.exists()) { downLoad(mImageUrl); } if (mImageUrl != null) { // 處理本地圖片,設置大小防止oom Bitmap bitmap = mImagesThoumb.decodeSimpleBitMapFromResource( file.getPath(), mClolumnWidth); // Bitmap bitmap = BitmapFactory.decodeFile(file.getPath()); if (bitmap != null) { mImagesThoumb.addBitmapToMemoryCache(mImageUrl, bitmap); return bitmap; } } return null; } /** * 查找要添加的column * * @param iv */ private LinearLayout findColumnToAdd(ImageView iv, int imageHeight) { if (mFirstColumnHeight <= mSecondColumnHeight) { if (mFirstColumnHeight <= mThirdColumnHeight) { iv.setTag(R.string.border_top, mFirstColumnHeight); mFirstColumnHeight += imageHeight; iv.setTag(R.string.border_bottom, mFirstColumnHeight); return mFirstColumn; } iv.setTag(R.string.border_top, mThirdColumnHeight); mThirdColumnHeight += imageHeight; iv.setTag(R.string.border_bottom, mThirdColumnHeight); return mThirdColumn; } else { if (mSecondColumnHeight <= mThirdColumnHeight) { iv.setTag(R.string.border_top, mSecondColumnHeight); mSecondColumnHeight += imageHeight; iv.setTag(R.string.border_bottom, mSecondColumnHeight); return mSecondColumn; } iv.setTag(R.string.border_top, mThirdColumnHeight); mThirdColumnHeight += imageHeight; iv.setTag(R.string.border_bottom, mThirdColumnHeight); return mThirdColumn; } } /** * 獲得file地址 * * @param imageUrl * @return */ private String getImagePath(String imageUrl) { int lastIndexOf = imageUrl.lastIndexOf("/"); String imageName = imageUrl.substring(lastIndexOf + 1); String imageDir = Environment.getExternalStorageDirectory().getPath() + "/pangzaifei/"; File file = new File(imageDir); if (!file.exists()) { file.mkdir(); } String imagePath = imageDir + imageName; return imagePath; } /** * 獲得圖片的名字 * * @param imageUrl */ private boolean hashSdcard() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { return true; } return false; } @Override /** * 當手勢抬起時,開始每個5毫秒計算位置 */ public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { // 發送handler Message msg = mHandler.obtainMessage(); msg.obj = this; mHandler.sendMessageDelayed(msg, mDelay); } return false; } private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 判斷是否已經滑到了最低處,如果滑到了最低處,則加載更多頁面,否則繼續發送handler掃描 PhotoFallScrollView scrollView = (PhotoFallScrollView) msg.obj; int scrollY = scrollView.getScrollY(); if (scrollY == lastScrollY) { if (mScrollViewHeight + scrollY >= mScrollLayout.getHeight() && mTasks.isEmpty()) { scrollView.loadMoreImages(); } scrollView.checkVisibile(); } else { lastScrollY = scrollY; Message message = new Message(); message.obj = scrollView; mHandler.sendMessageDelayed(message, mDelay); } } }; private int mScrollViewHeight; private View mScrollLayout; /** * 想不可見的變為空圖片 */ protected void checkVisibile() { if (mImageViewList != null && mImageViewList.size() > 0) { for (int i = 0; i < mImageViewList.size(); i++) { ImageView iv = mImageViewList.get(i); int borderTop = (int) iv.getTag(R.string.border_top); int borderBottom = (int) iv.getTag(R.string.border_bottom); if (borderBottom > getScrollY() && borderTop < getScrollY() + mScrollViewHeight) { String imageUrl = (String) iv.getTag(R.string.iamgurl); if (imageUrl != null && !"".equals(imageUrl)) { Bitmap bitmap = mImagesThoumb.getMemoryCache(imageUrl); if (bitmap != null) { iv.setImageBitmap(bitmap); } else { downLoadData(imageUrl); } } } else { iv.setImageResource(R.drawable.empty_photo); } } } } }
布局文件:
效果圖:
源碼地址:
http://download.csdn.net/detail/pangzaifei/7639423
一、概述在之前一個項目中,因為涉及到數據庫,所以就接觸到了ORM框架的GreenDao。後面就去網上大量的搜索下載學習,發現很多都是官網的翻譯或者是官網DEMO的簡單入門
偶然間發現了Android.inputmethodservice.Keyboard類,即android可以自定義鍵盤類,做了一個簡單例子供大家參考。效果如下:先看界面布局
1.onKeyDown 方法 onKeyDown 方法是KeyEvent.Callback 接口中的一個抽象方法,重寫onKeyDown 方法可以監聽到按鍵被按下的事件,
一開始,先對昨晚在昆明市火車站遇難的同胞表示默哀,並對惡勢力進行譴責,你們如果有再大的冤情也不要對平民下手,所謂冤有頭債有主,該弄誰弄誰去啊,欺負百姓算是怎麼回事,所以在