我们还是来看一款示例:(蘑菇街)  

       

         

 看起来很像我们的gridview吧,不过又不像,因为item大小不固定的,看起来是不是别有一番风味,确实如此.就如我们的方角图形,斯通见惯后也就出现了圆角.下面我简单介绍下实现方法.

第一种:

我们在配置文件中定义好列数.如上图也就是3列.我们需要定义三个LinearLayout,然后把获取到的图片add里面就ok了.

main.xml

1. <?xml version="1.0" encoding="utf-8"?>  
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
3. "fill_parent"  
4. "fill_parent"  
5. "@android:color/background_light"  
6. "vertical" >  
7.   
8.     <include  
9. "@+id/progressbar"  
10. "@layout/loading" />  
11.   
12.     <com.jj.waterfall.LazyScrollView  
13. "@+id/lazyscrollview"  
14. "fill_parent"  
15. "fill_parent"  
16. "1"  
17. "@null" >  
18.   
19.         <LinearLayout  
20. "fill_parent"  
21. "fill_parent"  
22. "@android:color/background_light"  
23. "horizontal"  
24. "2dp" >  
25.   
26.             <LinearLayout  
27. "@+id/layout01"  
28. "fill_parent"  
29. "fill_parent"  
30. "1"  
31. "vertical" >  
32.             </LinearLayout>  
33.   
34.             <LinearLayout  
35. "@+id/layout02"  
36. "fill_parent"  
37. "fill_parent"  
38. "1"  
39. "vertical" >  
40.             </LinearLayout>  
41.   
42.             <LinearLayout  
43. "@+id/layout03"  
44. "fill_parent"  
45. "fill_parent"  
46. "1"  
47. "vertical" >  
48.             </LinearLayout>  
49.         </LinearLayout>  
50.     </com.jj.waterfall.LazyScrollView>  
51.   
52.     <TextView  
53. "@+id/loadtext"  
54. "fill_parent"  
55. "wrap_content"  
56. "@drawable/loading_bg"  
57. "center"  
58. "10dp"  
59. "Loading..."  
60. "@android:color/background_dark" />  
61.   
62. </LinearLayout>

 

在这里因为图片很多就把图片放在assets文件中,如果想从网上拉取数据,自己写额外部分.

 

1. @Override  
2. public void onCreate(Bundle savedInstanceState) {  
3. super.onCreate(savedInstanceState);  
4.         InitView();  
5.   
6. this.getAssets();  
7. // 获取显示图片宽度  
8. 4) / 3;  
9. try {  
10. "images"));// 获取图片名称  
11. catch (IOException e) {  
12.             e.printStackTrace();  
13.         }  
14.   
15.         addImage(current_page, count);  
16.   
17.     }

 


1. /*** 
2.      * 加载更多 
3.      *  
4.      * @param current_page 
5.      *            当前页数 
6.      * @param count 
7.      *            每页显示个数 
8.      */  
9. private void addImage(int current_page, int count) {  
10. for (int x = current_page * count; x < (current_page + 1) * count  
11.                 && x < image_filenames.size(); x++) {  
12.             addBitMapToImage(image_filenames.get(x), y, x);  
13.             y++;  
14. if (y >= 3)  
15. 0;  
16.         }  
17.   
18.     }


1. /*** 
2.      * 添加imageview 到layout 
3.      *  
4.      * @param imagePath 图片name 
5.      * @param j 列 
6.      * @param i 行 
7.      */  
8. public void addBitMapToImage(String imagePath, int j, int i) {  
9.         ImageView imageView = getImageview();  
10. new ImageDownLoadAsyncTask(this, imagePath, imageView,  
11.                 Image_width);  
12.         asyncTask.setProgressbar(progressbar);  
13.         asyncTask.setLoadtext(loadtext);  
14.         asyncTask.execute();  
15.   
16.         imageView.setTag(i);  
17. if (j == 0) {  
18.             layout01.addView(imageView);  
19. else if (j == 1) {  
20.             layout02.addView(imageView);  
21. else if (j == 2) {  
22.             layout03.addView(imageView);  
23.         }  
24.   
25. new OnClickListener() {  
26.   
27. @Override  
28. public void onClick(View v) {  
29. this,  
30. "您点击了" + v.getTag() + "个Item", Toast.LENGTH_SHORT)  
31.                         .show();  
32.   
33.             }  
34.         });  
35.     }

 

注释已经很明确,相信大家都看的明白,我就不过多解释了.

因为瀑布流不是一个规则的试图,所以我们不可能用listview那种“底部加一个按钮试图,点击加载更多,这样看起来很难看”。因此我们最好滑动到低端自动加载.

我们这里用到的自定义ScrollView,因为我们要实现下滑分页,这里要判断是否要进行分页等操作.

LazyScrollView.Java (这个法很实用哦.)

1. /*** 
2.  * 自定义ScrollView 
3.  *  
4.  * @author zhangjia 
5.  *  
6.  */  
7. public class LazyScrollView extends ScrollView {  
8. private static final String tag = "LazyScrollView";  
9. private Handler handler;  
10. private View view;  
11.   
12. public LazyScrollView(Context context) {  
13. super(context);  
14.     }  
15.   
16. public LazyScrollView(Context context, AttributeSet attrs) {  
17. super(context, attrs);  
18.     }  
19.   
20. public LazyScrollView(Context context, AttributeSet attrs, int defStyle) {  
21. super(context, attrs, defStyle);  
22.     }  
23.   
24. // 这个获得总的高度  
25. public int computeVerticalScrollRange() {  
26. return super.computeHorizontalScrollRange();  
27.     }  
28.   
29. public int computeVerticalScrollOffset() {  
30. return super.computeVerticalScrollOffset();  
31.     }  
32.   
33. /*** 
34.      * 初始化 
35.      */  
36. private void init() {  
37.   
38. this.setOnTouchListener(onTouchListener);  
39. new Handler() {  
40. @Override  
41. public void handleMessage(Message msg) {  
42. // process incoming messages here  
43. super.handleMessage(msg);  
44. switch (msg.what) {  
45. case 1:  
46. if (view.getMeasuredHeight() <= getScrollY() + getHeight()) {  
47. if (onScrollListener != null) {  
48.                             onScrollListener.onBottom();  
49.                         }  
50.   
51. else if (getScrollY() == 0) {  
52. if (onScrollListener != null) {  
53.                             onScrollListener.onTop();  
54.                         }  
55. else {  
56. if (onScrollListener != null) {  
57.                             onScrollListener.onScroll();  
58.                         }  
59.                     }  
60. break;  
61. default:  
62. break;  
63.                 }  
64.             }  
65.         };  
66.   
67.     }  
68.   
69. new OnTouchListener() {  
70.   
71. @Override  
72. public boolean onTouch(View v, MotionEvent event) {  
73. // TODO Auto-generated method stub  
74. switch (event.getAction()) {  
75. case MotionEvent.ACTION_DOWN:  
76. break;  
77. case MotionEvent.ACTION_UP:  
78. if (view != null && onScrollListener != null) {  
79. 1), 200);  
80.                 }  
81. break;  
82.   
83. default:  
84. break;  
85.             }  
86. return false;  
87.         }  
88.   
89.     };  
90.   
91. /** 
92.      * 获得参考的View,主要是为了获得它的MeasuredHeight,然后和滚动条的ScrollY+getHeight作比较。 
93.      */  
94. public void getView() {  
95. this.view = getChildAt(0);  
96. if (view != null) {  
97.             init();  
98.         }  
99.     }  
100.   
101. /** 
102.      * 定义接口 
103.      *  
104.      * @author admin 
105.      *  
106.      */  
107. public interface OnScrollListener {  
108. void onBottom();  
109.   
110. void onTop();  
111.   
112. void onScroll();  
113.     }  
114.   
115. private OnScrollListener onScrollListener;  
116.   
117. public void setOnScrollListener(OnScrollListener onScrollListener) {  
118. this.onScrollListener = onScrollListener;  
119.     }

我们还需要一个类,异步加载实现,我想有开发经验的朋友一定用过好多次了,这里就不展示代码了,想看的朋友,可以点击下载(如果认为还不错的话,请您一定要表示一下哦.)

 

对了,忘记一点,我们还需要对MainActivity 中的lazyScrollView实现OnScrollListener接口,对滑动到底部进行监听.

效果图:

 

/**************************************************************************/

下面我介绍另外一种做法:(相对上面更灵活)

我们动态添加列.

配置文件就不贴了,和上面那例子一样,只不过里面值包含一个LinearLayout布局.

在这里我们动态添加列布局.

1. /*** 
2.      * init view 
3.      */  
4. public void initView() {  
5.         setContentView(R.layout.main);  
6.         lazyScrollView = (LazyScrollView) findViewById(R.id.waterfall_scroll);  
7.         lazyScrollView.getView();  
8. this);  
9.         waterfall_container = (LinearLayout) findViewById(R.id.waterfall_container);  
10.         progressbar = (LinearLayout) findViewById(R.id.progressbar);  
11.         loadtext = (TextView) findViewById(R.id.loadtext);  
12.   
13.         item_width = getWindowManager().getDefaultDisplay().getWidth() / column;  
14. new ArrayList<LinearLayout>();  
15.   
16. // 添加列到waterfall_container  
17. for (int i = 0; i < column; i++) {  
18. new LinearLayout(this);  
19. new LinearLayout.LayoutParams(  
20.                     item_width, LayoutParams.WRAP_CONTENT);  
21.             layout.setOrientation(LinearLayout.VERTICAL);  
22.             layout.setLayoutParams(itemParam);  
23.             linearLayouts.add(layout);  
24.             waterfall_container.addView(layout);  
25.         }  
26.   
27.     }


1. /*** 
2.      * 获取imageview 
3.      *  
4.      * @param imageName 
5.      * @return 
6.      */  
7. public ImageView getImageview(String imageName) {  
8.         BitmapFactory.Options options = getBitmapBounds(imageName);  
9. // 创建显示图片的对象  
10. new ImageView(this);  
11. new LayoutParams(LayoutParams.WRAP_CONTENT,  
12.                 LayoutParams.FILL_PARENT);  
13.         imageView.setLayoutParams(layoutParams);  
14. //  
15.         imageView.setMinimumHeight(options.outHeight);  
16.         imageView.setMinimumWidth(options.outWidth);  
17. 2, 0, 2, 2);  
18.         imageView.setBackgroundResource(R.drawable.image_border);  
19. if (options != null)  
20. null;  
21. return imageView;  
22.     }  
23.   
24. /*** 
25.      *  
26.      * 获取相应图片的 BitmapFactory.Options 
27.      */  
28. public BitmapFactory.Options getBitmapBounds(String imageName) {  
29. int h, w;  
30. new BitmapFactory.Options();  
31. true;// 只返回bitmap的大小,可以减少内存使用,防止OOM.  
32. null;  
33. try {  
34. "/" + imageName);  
35. catch (IOException e) {  
36.             e.printStackTrace();  
37.         }  
38. null, options);  
39. return options;  
40.   
41.     }

在这里我稍微修改了下,为要显示的iamgeview添加一个边框,这样看起来效果不错,我们动态滑动的同时, 然后图片陆续的填充边框.蘑菇街就是这种效果哦.

 效果图:

        

       

  

显示成4列,因此图片有点小,仔细看的话,你应该可以看到有好多边框,然后图片陆续的填充边框.这种效果感觉对上面那个用户体验更友好些.

最后简单总结下:针对瀑布流最好使用第二种方法,这种可扩展性比较大,哪天老大说四列太丑了,改成三列,那么我们只需要把column改成3就ok了,简单吧。

 

注意:由于图片量太多,占用空间太大,因此我将图片上传到网上,获取源码的同学下载该文件放到项目的assets文件夹下,然后运行就ok了.

 

如果有不足之处,请留言指出,