效果图:

 

瀑流流实现涉及的知识点

1.ScrollView滚动视图,我们这里用的是自定义ScrollView

/**
 * Created by Spring on 2015/11/2.
 * 自定义ScrollView
 */
public class CustomScrollView extends ScrollView {

    public CustomScrollView(Context context) {
        super(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    /**
     * 获得由垂直方向滚动条代表的所有垂直范围,缺省的范围是当前视图的画图高度。
     */
    public int getComputeVerticalScrollRange() {
        //滚动视图的可滚动范围是所有子元素的高度。
        return super.computeVerticalScrollRange();
    }

    /**
     * 获得滚动条的滑块垂直方向的偏移。
     */
    public int getComputeVerticalScrollOffSet() {
        //计算垂直方向滚动条的滑块的偏移。此值用来计算滚动条轨迹的滑块的位置。
        return super.computeVerticalScrollOffset();
    }

    /**
     *
     * getScrollY()获得ScrollView滑动的距离
     * getHeight是获得控件的显示的大小,如果控件大小超出的屏幕,那他的大小就是屏幕的大小。
     * 详情见:http://www.cnblogs.com/qinghuaideren/p/3186990.html
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {

        if (t + getHeight() >= computeVerticalScrollRange()) {
            //ScrollView滑动到底部了
            onScrollListener.onBottom();

        } else if (getScrollY() == 0) {
            //ScrollView滑动到顶部了
            onScrollListener.onTop();
        } else {
            //ScrollView滑动中
            onScrollListener.onScroll();
        }

    }


    /**
     * 定义接口
     *
     * @author admin
     */
    public interface OnScrollListener {
        void onBottom();

        void onTop();

        void onScroll();
    }

    private OnScrollListener onScrollListener;

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }
}

 

 

2.AsyncTask,异步加载图片

package com.jingling.practice.waterfall;


import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;

/**
 * Created by Spring on 2015/11/4.
 * 图片异步加载任务
 */
public class ImageLoaderTask extends AsyncTask<TaskParam, Void, Bitmap> {
    private TaskParam param;
    private final WeakReference<ImageView> imageViewReference; // 防止内存溢出

    public ImageLoaderTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);

    }

    /**
     * 完成实际的下载任务
     * @param params
     * @return
     */
    @Override
    protected Bitmap doInBackground(TaskParam... params) {
        param = params[0];
        return loadImageFile(param.getFilename(),param.getAssetManager());
    }

    private Bitmap loadImageFile(final String filename, final AssetManager assetManager) {
        InputStream is = null;
        try {
            Bitmap bmp = BitmapCache.getInstance().getBitmap(filename,
                    param.getAssetManager());
            return bmp;
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;

    }

    /**
     * 当下载完成后,显示出下载的图片
     * @param bitmap
     */
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }
        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                if (bitmap != null) {
                    int width = bitmap.getWidth();// 获取真实宽高
                    int height = bitmap.getHeight();
                    ViewGroup.LayoutParams lp = imageView.getLayoutParams();
                    lp.height = (height * param.getItemWidth()) / width;// 调整高度
                    imageView.setLayoutParams(lp);

                    imageView.setImageBitmap(bitmap);

                }

            }
        }
    }

}

 

3.MainActivity

 

package com.jingling.practice.waterfall;

import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class MainActivity extends Activity {
    /**
     * 滚动视图
     */
    private CustomScrollView waterfall_scroll;
    /**
     * 布局内容框架
     */
    private LinearLayout waterfall_container;
    /**
     * 布局内容item
     */
    private ArrayList<LinearLayout> waterfall_items;
    /**
     * 图片文件名
     */
    private List<String> image_filenames;
    /**
     * 图片路径前缀
     */
    private final String image_path = "images";
    /**
     * 提供关于屏幕尺寸和分辨率的信息
     */
    private Display display;
    /**
     * 访问assets目录下的文件
     */
    private AssetManager assetManager;

    /**
     * 每个item的宽度
     */
    private int itemWidth;
    /**
     * 显示列数
     */

    private int column_count = 3;
    /**
     * 每次加载15张图片
     */
    private int page_count = 15;
    /**
     * 当前页数
     */
    private int current_page = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取手机默认的屏幕尺寸和分辨率的信息
        display = this.getWindowManager().getDefaultDisplay();
        //根据屏幕计算每列的大小
        itemWidth = display.getWidth() / column_count;
        //获取asset目录下的文件
        assetManager = this.getAssets();

        initLayout();
    }

    public void initLayout() {
        waterfall_scroll = (CustomScrollView) findViewById(R.id.waterfall_scroll);
        //设置滚动监听
        waterfall_scroll.setOnScrollListener(new CustomScrollView.OnScrollListener() {
            @Override
            public void onBottom() {
                // 滚动到最低端
                AddItemToContainer(++current_page, page_count);
                Log.d("Scroll", "Scroll to bottom");
            }

            @Override
            public void onTop() {
                // 滚动到最顶端
                Log.d("Scroll", "Scroll to top");
            }

            @Override
            public void onScroll() {
                // 滚动中
                Log.d("Scroll", "Scrolling");
            }
        });

        waterfall_container = (LinearLayout) findViewById(R.id.waterfall_container);
        waterfall_items = new ArrayList<LinearLayout>();
        for (int i = 0; i < column_count; i++) {
            LinearLayout itemLayout = new LinearLayout(this);
            LinearLayout.LayoutParams itemParams = new LinearLayout.LayoutParams(itemWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
            itemLayout.setPadding(2, 2, 2, 2);
            itemLayout.setOrientation(LinearLayout.VERTICAL);
            itemLayout.setLayoutParams(itemParams);
            waterfall_items.add(itemLayout);
            waterfall_container.addView(itemLayout);
        }

        // 加载所有图片路径
        try {
            image_filenames = Arrays.asList(assetManager.list(image_path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 第一次加载
        AddItemToContainer(current_page, page_count);
    }

    private void AddItemToContainer(int pageindex, int pagecount) {
        int j = 0;
        int images_count = image_filenames.size();
        for (int i = pageindex * pagecount; i < pagecount * (pageindex + 1)
                && i < images_count; i++) {

            j = j >= column_count ? j = 0 : j;
            AddImage(image_filenames.get(i), j++);
        }


    }

    private void AddImage(String filename, int columnIndex) {
        ImageView item = (ImageView) LayoutInflater.from(this).inflate(
                R.layout.waterfall_item, null);
        waterfall_items.get(columnIndex).addView(item);

        TaskParam param = new TaskParam();
        param.setAssetManager(assetManager);
        param.setFilename(image_path + "/" + filename);
        param.setItemWidth(itemWidth);
        ImageLoaderTask task = new ImageLoaderTask(item);
        task.execute(param);
    }
}

 

 

4.android-studio   assets目录的创建(这里的图片全部放在assets目录下的,studio的assets目录不像在eclipse中项目一创建完成就有的)

 

(1) 选择project

 

(2)选择你项目下src/main,右键鼠标选择new Directory,输入assets,即可创建成功。

 

 

源码已经上传:https://github.com/presCheng/WaterFall.git