Android 瀑布流

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>



你可能感兴趣的:(android)