Demo地址 http://download.csdn.net/detail/qq_28934205/9336625
/**
* 瀑布流类
*
* 原理:
* 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<DownLoadTask> 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<ImageView> mImageViewList = new ArrayList<ImageView>();
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<DownLoadTask>();
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<String, String, Bitmap> {
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 = (Integer) iv.getTag(R.string.border_top);
int borderBottom =(Integer) 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);
}
}
}
}
}
/**
* 数据源类
*
* @author pangzf
* @date 2014年7月15日 上午10:31:52
*/
public class Images {
private static Images images;
private LruCache<String, Bitmap> mMemoryCache;
public Images() {
initLrucache();// 初始化lrucache
}
public static Images getInstance() {
if (images == null) {
images = new Images();
}
return images;
}
/**
* 初始化lrucache
*/
private void initLrucache() {
long maxSize = Runtime.getRuntime().maxMemory();
int cacheSize = (int) (maxSize / 8);
mMemoryCache = new LruCache<String, Bitmap>(cacheSize);
}
/**
* 从lrucache中获得key
*/
public Bitmap getMemoryCache(String key) {
if (mMemoryCache != null) {
Bitmap bitmap = mMemoryCache.get(key);
if (bitmap != null) {
return bitmap;
}
}
return null;
}
/**
* 将图片添加到lrucache中
*
* @param key
* @param bitmap
*/
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getMemoryCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public static final String[] imageThumbs = new String[] {
"http://img.my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
"http://img.my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
"http://img.my.csdn.net/uploads/201308/31/1377949577_1998.jpg" };
/**
* 将大图缩放
*
* @param path
* @param mClolumnWidth
*/
public Bitmap decodeSimpleBitMapFromResource(String path, int mClolumnWidth) {
final Options options = new Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inSampleSize = decodeSimpleSize(options, mClolumnWidth);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
/**
* 获得simpleSize
*
* @param options
* @return
*/
private int decodeSimpleSize(Options options, int reqwidth) {
int width = options.outWidth;
int simplesize = 1;
if (width > reqwidth) {
simplesize = Math.round(width / reqwidth);
}
return simplesize;
}
}
activity_demo.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.pangzaifei.falls.PhotoFallScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/first_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/second_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/third_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
</com.pangzaifei.falls.PhotoFallScrollView>
</LinearLayout>