編輯:關於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 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);
}
}
}
}
}
上面是主要的東西,思路和注釋已經添加。其中imageView中的tag我要解釋一下,主要保存了每一列的上邊距和下邊距和圖片的url,這個方法,就是只顯示當前頁的圖片。
布局文件:
效果圖:
源碼地址:
http://download.csdn.net/detail/pangzaifei/7639423
Android數據庫框架GreenDao封裝使用,易理解、易擴展
一、概述在之前一個項目中,因為涉及到數據庫,所以就接觸到了ORM框架的GreenDao。後面就去網上大量的搜索下載學習,發現很多都是官網的翻譯或者是官網DEMO的簡單入門
Android自定義軟鍵盤的設計與實現代碼
偶然間發現了Android.inputmethodservice.Keyboard類,即android可以自定義鍵盤類,做了一個簡單例子供大家參考。效果如下:先看界面布局
Android研究之游戲開發處理按鍵的響應
1.onKeyDown 方法 onKeyDown 方法是KeyEvent.Callback 接口中的一個抽象方法,重寫onKeyDown 方法可以監聽到按鍵被按下的事件,
android高分段進階攻略(2)傳感器
一開始,先對昨晚在昆明市火車站遇難的同胞表示默哀,並對惡勢力進行譴責,你們如果有再大的冤情也不要對平民下手,所謂冤有頭債有主,該弄誰弄誰去啊,欺負百姓算是怎麼回事,所以在